diff --git a/.agents/architecture.md b/.agents/architecture.md new file mode 100644 index 0000000000..2f16b755e7 --- /dev/null +++ b/.agents/architecture.md @@ -0,0 +1,157 @@ +# Nitro Architecture Deep Dive + +## Core Instance (`src/nitro.ts`) + +`createNitro(config, opts)` creates the main context with: +- `options: NitroOptions` — Resolved configuration +- `hooks: Hookable` — Build lifecycle hooks +- `vfs: Map` — Virtual file system +- `routing: { routes, routeRules, globalMiddleware, routedMiddleware }` +- `scannedHandlers: NitroEventHandler[]` +- `unimport?: Unimport` — Auto-imports (optional) +- `logger: ConsolaInstance` +- `updateConfig(config)` — Hot-reload config +- `close()` — Cleanup + +**Setup flow:** +1. Load options via `loadOptions()` +2. Install modules via `installModules()` +3. Init routing via `initNitroRouting()` +4. Scan handlers/plugins/tasks via `scanAndSyncOptions()` +5. Prepare unimport for auto-imports +6. Setup hooks + +## Entry Points + +- `src/builder.ts` — Main public API: `createNitro()`, `build()`, `createDevServer()`, `prerender()`, `copyPublicAssets()`, `prepare()`, `writeTypes()`, `runTask()`, `listTasks()` +- `src/vite.ts` — Vite plugin export from `src/build/vite/plugin.ts` + +## Build System (`src/build/`) + +**Builder dispatch** (`build/build.ts`): delegates to `rollup`, `rolldown`, or `vite` based on `nitro.options.builder`. + +**Builder selection** (resolved in `config/resolvers/builder.ts`): +- Check `NITRO_BUILDER` / `NITRO_VITE_BUILDER` env vars +- Auto-detect available packages +- Fallback: rolldown → vite → rollup + +**Base config** (`build/config.ts`): +- Extensions: `.ts`, `.mjs`, `.js`, `.json`, `.node`, `.tsx`, `.jsx` +- Import.meta replacements (`import.meta.dev`, `import.meta.preset`, etc.) +- Unenv aliases for polyfills +- External dependency patterns + +**Plugins** (`build/plugins.ts`): +1. Virtual modules — renders from `build/virtual/` +2. Auto imports — Unimport plugin +3. WASM loader — unwasm +4. Server main injection — `globalThis.__server_main__` +5. Raw imports — `?raw` suffix +6. Route meta — OpenAPI metadata +7. Replace plugin — variable substitution +8. Externals plugin — Node.js native resolution +9. Sourcemap minify (optional) + +**Virtual modules** (`build/virtual/`, 14 templates): +All prefixed `#nitro/virtual/`: +- `routing.ts` — Compiled router matcher +- `plugins.ts` — Plugin registry +- `error-handler.ts` — Error handler +- `public-assets.ts` — Public asset metadata +- `server-assets.ts` — Server asset metadata +- `runtime-config.ts` — Runtime config object +- `database.ts` — Database setup +- `storage.ts` — Storage backends +- `tasks.ts` — Task registry +- `polyfills.ts` — Env polyfills +- `feature-flags.ts` — Feature detection +- `routing-meta.ts` — Route metadata (OpenAPI) +- `renderer-template.ts` — SSR renderer +- `_all.ts` — Aggregator + +## Configuration System (`src/config/`) + +**Loader** (`config/loader.ts`): `loadOptions(config, opts)` +1. Merge with defaults (`NitroDefaults`) +2. Load c12 config files (`nitro.config.ts`, `package.json.nitro`, etc.) +3. Resolve preset +4. Run config resolvers sequentially + +**Resolvers** (`config/resolvers/`): +`compatibility`, `tsconfig`, `paths`, `imports`, `route-rules`, `database`, `export-conditions`, `runtime-config`, `open-api`, `url`, `assets`, `storage`, `error`, `unenv`, `builder` + +**Defaults** (`config/defaults.ts`): All NitroConfig defaults. + +## Runtime (`src/runtime/`) + +**Internal** (`runtime/internal/`): +- `app.ts` — NitroApp creation, H3 app setup +- `cache.ts` — Response caching +- `context.ts` — Async context +- `route-rules.ts` — Route rule middleware (headers, redirect, proxy, cache, cors) +- `static.ts` — Static file serving +- `task.ts` — Task execution +- `plugin.ts` — Plugin helpers +- `runtime-config.ts` — Config getter + +**Public exports**: `runtime/app.ts` (`defineConfig()`), `runtime/nitro.ts` (`serverFetch()`), `runtime/cache.ts`, `runtime/task.ts`, `runtime/storage.ts`, etc. + +## Dev Server (`src/dev/`) + +- `dev/server.ts` — `NitroDevServer`: Worker management via `env-runner`, restart on failure (max 3 retries), WebSocket support, VFS debug endpoint (`/_vfs/**`) +- `dev/app.ts` — `NitroDevApp`: H3 app with error handling, static serving with compression, dev proxy + +## Prerender (`src/prerender/`) + +- `prerender/prerender.ts` — Main flow: parse routes → build prerenderer (preset: `nitro-prerender`) → execute in parallel → link crawling → write to disk → compress +- `prerender/utils.ts` — `extractLinks()`, `matchesIgnorePattern()`, `formatPrerenderRoute()` + +## Routing & Scanning (`src/routing.ts`, `src/scan.ts`) + +**Scanning**: Discovers routes, middleware, plugins, tasks, modules from filesystem. + +Route file conventions: +- `routes/index.ts` → `GET /` +- `routes/users/[id].ts` → `GET /users/:id` +- `routes/users/[...slug].ts` → `GET /users/**:slug` +- `api/users.post.ts` → `POST /api/users` +- `.dev`/`.prod`/`.prerender` suffixes for environment filtering + +**Router** (`Router` class): Based on `rou3`, compiles to optimized string matcher, supports method routing + env conditions. + +## Presets (`src/presets/`) + +31 presets. Structure per preset: +``` +presets// +├── preset.ts # defineNitroPreset() +├── runtime/ # Runtime entry (bundled) +├── types.ts # Types (optional) +├── utils.ts # Build-time utils (optional) +└── unenv/ # Env overrides (optional) +``` + +Key presets: `standard`, `node` (server/middleware/cluster), `cloudflare` (pages/workers), `vercel`, `netlify`, `aws-lambda`, `deno`, `firebase`, `azure`, `bun`, `winterjs` + +Resolution: `presets/_resolve.ts` handles aliases, dev/prod, compat dates, static hosting. + +## CLI (`src/cli/`) + +Uses `citty` with lazy-loaded commands: `dev`, `build`, `deploy`, `preview`, `prepare`, `task`, `docs`. + +## Key Libraries + +| Library | Purpose | +|---------|---------| +| `h3` | HTTP framework | +| `rou3` | Route matching | +| `c12` | Config loading | +| `citty` | CLI framework | +| `hookable` | Hook system | +| `unimport` | Auto-imports | +| `unstorage` | Storage abstraction | +| `unenv` | Runtime polyfills | +| `defu` | Config merging | +| `pathe` | Path operations | +| `consola` | Logging | +| `env-runner` | Worker management | diff --git a/.agents/docs.md b/.agents/docs.md new file mode 100644 index 0000000000..3dee93462a --- /dev/null +++ b/.agents/docs.md @@ -0,0 +1,499 @@ +# Documentation Guide + +## Structure + +Documentation lives in `docs/` and is built with [UnDocs](https://github.com/unjs/undocs). + +``` +docs/ + .docs/ # UnDocs Nuxt app (components, pages, layouts, utils) + .config/ # docs.yaml (site config), automd.config.ts + 1.docs/ # Core documentation (getting started, routing, cache, etc.) + 2.deploy/ # Deployment docs (runtimes, providers) + 3.config/ # Config reference + 4.examples/ # Examples index + index.md # Homepage +``` + +Numeric prefixes control navigation order. Files with the same prefix are sorted alphabetically. + +## Conventions + +### Preset Names + +Canonical preset names use **underscores** (e.g., `node_server`, `cloudflare_module`, `digital_ocean`). Both underscores and hyphens are supported at runtime (resolved via `kebabCase`), but docs should use underscore form. + +### Import Paths + +Nitro v3 uses subpath exports — not deep runtime imports: + +```ts +import { defineHandler, readBody, getQuery } from "nitro/h3"; +import { defineCachedHandler, defineCachedFunction } from "nitro/cache"; +import { useStorage } from "nitro/storage"; +import { useDatabase } from "nitro/database"; +import { useRuntimeConfig } from "nitro/runtime-config"; +import { defineNitroConfig } from "nitro/config"; +import { definePlugin } from "nitro"; // runtime plugin +import { defineRouteMeta } from "nitro"; // route meta macro +``` + +### H3 v2 API + +Nitro v3 uses H3 v2. Key differences from v1: + +- **Handler**: `defineHandler()` (not `eventHandler` / `defineEventHandler`) +- **Error**: `throw new HTTPError(message, { status })` (not `createError()`) +- **Router**: `new H3()` (not `createApp()` / `createRouter()`) +- **Response**: Return values directly; no `send()` function +- **Headers**: `event.res.headers.set(name, value)` (not `setResponseHeader(event, name, value)`) +- **Hooks**: `request` hook receives `(event: HTTPEvent)`, not `(req)` + +### Code Examples + +- **Auto imports are not available** — always show explicit imports in examples +- Always use `defineHandler` from `"nitro/h3"` (not `eventHandler`) +- Always use `defineNitroConfig` from `"nitro/config"` (not `defineConfig`) +- Include import statements in code examples +- Use `"nitro/*"` imports, never `"nitropack/*"` + +### Node.js Version + +Nitro v3 requires Node.js >= 20. All deployment docs should reference Node.js 20+ (not 16 or 18). + +### Environment Variables + +The preset env var is `NITRO_PRESET` (not `SERVER_PRESET` or any other name). + +### Runtime Config + +- Prefix: `NITRO_` for env var overrides +- camelCase in config, UPPER_SNAKE_CASE in env vars + +## Common Mistakes to Avoid + +- Using `send(event, value)` — removed in h3 v2, return values directly +- Using `createError()` — use `new HTTPError()` or `HTTPError.status()` +- Using `eventHandler()` — use `defineHandler()` +- Using `defineConfig()` for nitro config — use `defineNitroConfig()` +- Duplicate imports (e.g., importing `defineHandler` from both `nitro/h3` and `nitro/cache`) +- Wrong env var names (e.g., `NITR_PRESET`, `SERVER_PRESET`) +- Outdated Node.js versions in deployment examples +- Using hyphen preset names in docs (use underscores) + +## MDC Syntax Reference + +Docs use [MDC](https://content.nuxt.com/) (Markdown Components) syntax to embed Vue components in markdown. + +### Block Components + +Use `::` for block components. Nesting increases the colon count: + +```markdown +::component-name +Content here +:: + +::component{prop="value" boolProp} +Content +:: +``` + +Nested (each level adds one `:`): + +```markdown +::parent + :::child + Content + ::: +:: +``` + +### Props + +**Inline:** `::alert{type="warning" icon="i-lucide-alert"}` + +**YAML block** (for multiple props): + +```markdown +::component +--- +title: My Title +icon: i-lucide-rocket +--- +Content +:: +``` + +### Slots + +Named slots use `#`: + +```markdown +::hero +Default slot content + +#title +Title slot content + +#description +Description slot content + +#links + :::u-button{to="/docs"} + Get Started + ::: +:: +``` + +### Inline Components & Attributes + +```markdown +:inline-component{prop="value"} + +Hello [World]{.text-primary style="color: green;"} +``` + +### Variables + +```markdown +--- +title: My Page +--- +# {{ $doc.title }} +``` + +## Prose Components (Typography) + +These are available in markdown files for documentation content. Provided by [Nuxt UI](https://ui.nuxt.com/). + +### Callouts + +```markdown +::note +Additional information for the user. +:: + +::tip +Helpful suggestion or best practice. +:: + +::warning +Caution about potential unexpected results. +:: + +::caution +Warning about irreversible or dangerous actions. +:: +``` + +Generic callout with props: + +```markdown +::callout{icon="i-lucide-info" color="primary"} +Custom callout content with **markdown**. +:: +``` + +Colors: `primary`, `secondary`, `success`, `info`, `warning`, `error`, `neutral`. + +### Tabs + +```markdown +::tabs + :::tabs-item{label="npm" icon="i-lucide-package"} + ```bash + npm install nitro + ``` + ::: + :::tabs-item{label="pnpm"} + ```bash + pnpm add nitro + ``` + ::: +:: +``` + +Props: `orientation` (`horizontal`|`vertical`), `defaultValue`, `content`, `unmountOnHide`. + +### Steps + +```markdown +::steps{level="3"} +### Install +Install the package. + +### Configure +Add to your config. + +### Deploy +Deploy your app. +:: +``` + +`level` prop: `"2"`, `"3"` (default), `"4"` — determines which heading level becomes numbered steps. + +### Code Group + +```markdown +::code-group +```ts [nuxt.config.ts] +export default defineNuxtConfig({}) +``` +```ts [nitro.config.ts] +export default defineNitroConfig({}) +``` +:: +``` + +Props: `defaultValue`, `sync` (persists selection to localStorage). + +### Code Tree + +Interactive file tree with code preview: + +```markdown +::code-tree{defaultValue="routes/hello.ts" expand-all} + ::prose-pre{filename="routes/hello.ts"} + ```ts + export default defineHandler(() => 'Hello!') + ``` + :: + ::prose-pre{filename="vite.config.ts"} + ```ts + import { nitro } from 'nitro/vite' + export default defineConfig({ plugins: [nitro()] }) + ``` + :: +:: +``` + +Props: `defaultValue`, `expandAll`, `items`. + +### Card + +```markdown +::card{title="Storage" icon="i-lucide-database" to="/docs/storage"} +Access key-value storage in your handlers. +:: +``` + +Props: `title`, `icon`, `color`, `to`, `target`, `variant` (`solid`|`outline`|`soft`|`subtle`). + +### Field + +Document API parameters: + +```markdown +::field{name="preset" type="string" required} +The deployment preset to use. +:: +``` + +Props: `name`, `type`, `description`, `required`. + +### Collapsible + +```markdown +::collapsible{name="Advanced Options"} +Hidden content shown on expand. +:: +``` + +Props: `name`, `size`, `color`, `defaultOpen`, `unmountOnHide`. + +### Kbd (Keyboard) + +`:kbd[Ctrl]` + `:kbd[C]` renders keyboard shortcuts inline. + +### Icon + +`:icon{name="i-lucide-rocket"}` renders an inline icon. + +### Prose Pre (Code Block) + +Explicit code block with filename: + +```markdown +::prose-pre{filename="server.ts"} +```ts +export default { fetch: () => new Response('ok') } +``` +:: +``` + +## Landing Page Components + +These are Nuxt UI `Page*` components used in `docs/index.md` for the homepage. Prefix with `u-` in MDC. + +### PageHero (`::u-page-hero`) + +```markdown +::u-page-hero +--- +orientation: horizontal +--- +#title +Ship [Full-Stack]{.text-primary} Vite Apps + +#description +Build production-ready server applications. + +#links + :::u-button{size="xl" to="/docs"} + Get Started + ::: + +#default + :::some-illustration + ::: +:: +``` + +Props: `title`, `description`, `headline`, `orientation` (`vertical`|`horizontal`), `reverse`, `links` (ButtonProps[]). +Slots: `top`, `header`, `headline`, `title`, `description`, `body`, `footer`, `links`, `default`, `bottom`. + +### PageSection (`::u-page-section`) + +```markdown +::u-page-section +--- +orientation: horizontal +features: + - title: Feature One + description: Description here + icon: i-lucide-zap +--- +#title +Section Title + +#description +Section description text. +:: +``` + +Props: `headline`, `icon`, `title`, `description`, `orientation`, `reverse`, `links` (ButtonProps[]), `features` (PageFeatureProps[]). +Slots: `top`, `header`, `leading`, `headline`, `title`, `description`, `body`, `features`, `footer`, `links`, `default`, `bottom`. + +### PageFeature (`::u-page-feature`) + +```markdown +:::::u-page-feature +#title +Feature Name + +#description +Feature description text. +::::: +``` + +Props: `icon`, `title`, `description`, `orientation` (`horizontal`|`vertical`), `to`, `target`. +Slots: `leading`, `title`, `description`, `default`. + +### PageGrid (`::u-page-grid`) + +Responsive grid (1→2→3 columns). Wraps `PageCard` or `PageFeature` children: + +```markdown +::::u-page-grid + :::::u-page-card{title="Card" icon="i-lucide-box"} + Card content + ::::: +:::: +``` + +### PageCard (`::u-page-card`) + +```markdown +::u-page-card{title="Title" icon="i-lucide-box" to="/link"} +Card body content. +:: +``` + +Props: `icon`, `title`, `description`, `orientation`, `reverse`, `highlight`, `highlightColor`, `spotlight`, `spotlightColor`, `variant`, `to`, `target`. +Slots: `header`, `leading`, `title`, `description`, `body`, `footer`, `default`. + +### PageCTA (`::u-page-cta`) + +Call-to-action block: + +```markdown +::u-page-cta +--- +variant: solid +links: + - label: Get Started + to: /docs + color: neutral +--- +#title +Ready to get started? + +#description +Deploy your app in minutes. +:: +``` + +Props: `title`, `description`, `orientation`, `reverse`, `variant` (`outline`|`solid`|`soft`|`subtle`|`naked`), `links`. + +### PageLogos (`::u-page-logos`) + +```markdown +::u-page-logos +--- +title: Trusted by +marquee: true +items: + - i-simple-icons-github + - i-simple-icons-vercel +--- +:: +``` + +Props: `title`, `items` (icon strings or `{src, alt}` objects), `marquee` (boolean or MarqueeProps). + +### PageLinks (`::u-page-links`) + +```markdown +::u-page-links +--- +title: Community +links: + - label: GitHub + icon: i-simple-icons-github + to: https://github.com/nitrojs/nitro +--- +:: +``` + +### Other Page Components + +- **PageHeader** — Page title/description header +- **PageBody** — Main content wrapper +- **PageColumns** — Multi-column layout +- **PageList** — Vertical list of items +- **PageAnchors** — Anchor link navigation +- **PageAside** — Sidebar content + +## Nuxt Content Querying (for custom components) + +```ts +// Single page by path +const page = await queryCollection('docs').path('/hello').first() + +// Filtered list +const posts = await queryCollection('blog') + .where('draft', '=', false) + .order('date', 'DESC') + .all() + +// Navigation tree +const nav = await queryCollectionNavigation('docs') + +// Prev/next +const [prev, next] = await queryCollectionItemSurroundings('docs', '/current') +``` + +## Custom Components + +Project-specific components live in `docs/.docs/components/` and can be used in markdown with `:component-name` or `::component-name` syntax (e.g., `:page-sponsors`, `:hero-background` as seen in `index.md`). diff --git a/.agents/presets.md b/.agents/presets.md new file mode 100644 index 0000000000..e8e527d47d --- /dev/null +++ b/.agents/presets.md @@ -0,0 +1,75 @@ +# Nitro Presets Reference + +## All Presets (31) + +### Core +- `_nitro/` — Internal presets (dev, prerender, worker modes) +- `standard/` — Framework-agnostic standard server +- `node/` — Node.js (server, middleware, cluster) +- `bun/` — Bun runtime + +### Cloud Providers +- `aws-lambda/` — AWS Lambda +- `aws-amplify/` — AWS Amplify +- `azure/` — Azure Static Web Apps +- `cloudflare/` — Cloudflare Pages/Workers +- `deno/` — Deno Deploy +- `firebase/` — Firebase Hosting +- `netlify/` — Netlify Functions/Edge +- `vercel/` — Vercel Functions/Edge +- `digitalocean/` — DigitalOcean App Platform +- `heroku/` — Heroku +- `koyeb/` — Koyeb +- `zeabur/` — Zeabur +- `render.com/` — Render +- `stormkit/` — Stormkit +- `genezio/` — Genezio +- `winterjs/` — WinterJS +- `zephyr/` — Zephyr +- `alwaysdata/` +- `cleavr/` +- `flightcontrol/` +- `iis/` +- `platform.sh/` + +## Preset Structure + +``` +presets// +├── preset.ts # defineNitroPreset() — config overrides, hooks +├── runtime/ # Runtime entry points (bundled into output) +│ └── .ts # Platform-specific request handler +├── types.ts # TypeScript types (optional) +├── utils.ts # Build-time utilities (optional) +└── unenv/ # Environment polyfill overrides (optional) + ├── preset.ts + └── node-compat.ts +``` + +## Creating a Preset + +Use `defineNitroPreset()` from `src/presets/_utils/preset.ts`: + +```ts +import { defineNitroPreset } from "../_utils/preset.ts"; + +export default defineNitroPreset({ + // Preset metadata + entry: "./runtime/.ts", + // NitroConfig overrides + node: false, + // Hooks + hooks: { + "build:before": async (nitro) => { /* ... */ }, + }, +}); +``` + +## Preset Resolution (`presets/_resolve.ts`) + +`resolvePreset(name, opts)` considers: +- Preset name aliases +- Dev vs production mode +- Compatibility dates +- Static hosting detection +- Generated mappings in `_all.gen.ts` and `_types.gen.ts` diff --git a/.agents/skills/update-deps/SKILL.md b/.agents/skills/update-deps/SKILL.md new file mode 100644 index 0000000000..561e99820f --- /dev/null +++ b/.agents/skills/update-deps/SKILL.md @@ -0,0 +1,161 @@ +# Update Dependencies Skill + +This skill guides you through the process of updating dependencies in the Nitro repository. + +## Step-by-Step Process + +### Ensure Clean State + +Check that you're on a clean main branch with latest changes. + +- Clean working directory on main branch +- Latest changes pulled from remote + +```bash +git checkout main +git pull origin main +git status # Should show "nothing to commit, working tree clean" +``` + +(if branch name starts with chore, you can stay in it, no need to pull or change branch or clean state) + +### Initial Install + +Run an initial install to ensure everything is up to date: + +```bash +pnpm install +``` + +### Run pnpm upgrade -r + +Run `pnpm upgrade -r` to update non-major versions. + +After upgrade, check git diff: + +- Make sure range types does not change in `dependencies` field (example: `"h3": "^2.0.1-rc.7"` should remain `"h3": "^2.0.1-rc.7",` not `"h3": "2.0.1-rc.7",`) +- Make sure dependencies are not converted to `link:..` (example: `"nitro": "latest",` should remain same, instead of `"nitro": "link:../.."`) + +**Fix workspace package link references:** + +`pnpm upgrade -r` often incorrectly converts workspace package references (like `"nitro": "latest"`) to link format (`"nitro": "link:../.."`) in monorepo packages. + +Check git diff for any workspace packages that were converted to `link:` format: + +```bash +# Check for any link: conversions in modified files +git diff --name-only | xargs grep -l '"link:' 2>/dev/null +``` + +If found, revert them back to their original format. For this repo, `"nitro"` should always be `"latest"`: + +```bash +# Revert nitro link references back to latest in all modified package.json files +git diff --name-only | grep 'package.json$' | while read file; do + if grep -q '"nitro": "link:' "$file" 2>/dev/null; then + sed -i 's/"nitro": "link:[^"]*"/"nitro": "latest"/g' "$file" + echo "Fixed: $file" + fi +done +``` + +**Fix caret prefix removal:** + +If any dependencies in root `package.json` lost their `^` prefix, restore them manually. + +### Check for Outdated Dependencies + +Find outdated dependencies: + +```bash +pnpm outdated -r +``` + +**IMPORTANT**: Check for newer beta/alpha/rc versions manually. `pnpm outdated` doesn't show pre-release updates. + +Check each package with beta/alpha/rc versions in package.json: + +```bash +# List all versions including pre-releases +pnpm show vite versions --json | grep -E "beta|alpha|rc" | tail -5 +pnpm show youch versions --json | grep -E "beta|alpha|rc" | tail -5 +``` + +Or check all versions for a specific package: + +```bash +pnpm show versions +``` + +### 4. Update Dependencies + +Manually update all dependencies to their latest versions in [package.json](../package.json): + +- Update both `dependencies` and `devDependencies` +- Keep the range prefix (e.g., `^` for caret ranges) +- **For beta/alpha/rc packages**: Update to the latest pre-release tag found in step 3 + - Example: `vite: "8.0.0-beta.6"` → `"8.0.0-beta.7"` + - Example: `h3: "^2.0.1-rc.7"` → `"^2.0.1-rc.8"` (if available) +- Maintain version range conventions (prefer `^` over exact versions) +- **Do not update** `@azure/functions` + +### 5. Clean Install + +Remove lock file and node_modules, then reinstall: + +```bash +rm -rf node_modules pnpm-lock.yaml +pnpm i +``` + +### 6. Lint and Fix + +Run linting and auto-fix issues: + +```bash +pnpm format +``` + +### 7. Build Project + +Build the project to ensure compatibility: + +```bash +pnpm build +``` + +### 9. Fix Remaining Issues + +If there are lint or type errors: + +1. Review the output carefully +2. Fix issues manually following the project conventions +3. Re-run `pnpm format` to verify lint fixes +4. Re-run `pnpm typecheck` to verify type fixes. Ignore errors, only report them in the end. + +### 10. Final + +Do not commit changes. Only summarize what happened. + +## Common Issues + +### Breaking Changes + +If a dependency has breaking changes: + +- Check the package's changelog/release notes +- Update code to match new API if needed +- Consider pinning to previous major version if breaking changes are too extensive + +### Build Failures + +If the build fails after updates: + +- Check for TypeScript errors first: `pnpm typecheck` +- Review error messages for deprecated APIs +- Consider updating dependencies one at a time to isolate issues + +### Lock File Conflicts + +- Test thoroughly after updates, especially major version bumps +- Review changelogs for significant updates diff --git a/.agents/testing.md b/.agents/testing.md new file mode 100644 index 0000000000..77fd9bd6db --- /dev/null +++ b/.agents/testing.md @@ -0,0 +1,59 @@ +# Nitro Testing Guide + +## Test Structure + +``` +test/ +├── tests.ts # Main test definitions (shared across presets) +├── fixture/ # Test fixture Nitro app +│ ├── nitro.config.ts +│ ├── routes/ # Test route handlers +│ ├── api/ # Test API handlers +│ ├── middleware/ # Test middleware +│ ├── plugins/ # Test plugins +│ └── public/ # Test static assets +├── presets/ # Per-preset test setup +│ ├── node.test.ts +│ ├── cloudflare.test.ts +│ ├── vercel.test.ts +│ └── ... +├── unit/ # Isolated unit tests +└── minimal/ # Minimal bundle output tests +``` + +## How Tests Work + +1. `test/tests.ts` defines shared test cases using vitest +2. Each `test/presets/.test.ts` imports shared tests and runs them against a specific preset +3. The test fixture in `test/fixture/` is a full Nitro app used as the test target +4. Preset tests build the fixture with the preset, then run HTTP assertions + +## Adding Regression Tests + +1. Add test route/handler to `test/fixture/` (e.g., `test/fixture/routes/new-feature.ts`) +2. Add test case to `test/tests.ts` +3. Run `pnpm vitest run test/presets/node.test.ts` to verify + +## Running Tests + +```bash +# Run all tests +pnpm test + +# Run specific preset test +pnpm vitest run test/presets/node.test.ts + +# Run unit tests +pnpm vitest run test/unit/ + +# Run minimal bundle test +pnpm vitest run test/minimal/ +``` + +## Bug Fix Workflow + +1. Write regression test in `test/fixture/` + `test/tests.ts` +2. Confirm it **fails** (`pnpm vitest run test/presets/node.test.ts`) +3. Fix the implementation +4. Confirm it **passes** +5. Run full suite (`pnpm test`) diff --git a/.agents/vite.md b/.agents/vite.md new file mode 100644 index 0000000000..5df8a14ed2 --- /dev/null +++ b/.agents/vite.md @@ -0,0 +1,240 @@ +# Nitro Vite Build System + +## Overview + +`src/build/vite/` is Nitro's Vite-based build system using Vite 6+ multi-environment API. It integrates as a Vite plugin (`nitro()`) that manages server builds, service environments, dev server, and production output. + +## File Map + +| File | Purpose | +|------|---------| +| `plugin.ts` | Main plugin — 6 sub-plugins orchestrating the build | +| `env.ts` | Vite environment creation (nitro, services, env-runner) | +| `dev.ts` | Dev server integration, `FetchableDevEnvironment`, middleware | +| `prod.ts` | Production multi-env build, asset management, virtual setup module | +| `bundler.ts` | Rollup/Rolldown config generation | +| `build.ts` | CLI build entry for `nitro build` (`viteBuild()`) | +| `preview.ts` | Preview server plugin | +| `types.ts` | Type definitions (`NitroPluginConfig`, `NitroPluginContext`) | + +## Plugin Architecture (`plugin.ts`) + +`nitro(config?)` returns an array of 6 sub-plugins: + +### 1. `nitroInit` — Context Setup +- Calls `setupNitroContext()` on first `config` hook +- Creates Nitro instance via `createNitro()` +- Detects Rolldown vs Rollup (`_isRolldown`) +- Resolves bundler config via `getBundlerConfig()` +- Initializes env-runner in dev mode +- Attaches rollup plugins for dev environments + +### 2. `nitroEnv` — Environment Registration +- Registers Vite environments: `client`, `nitro`, and user services +- Auto-detects `entry-server` for SSR +- Configures per-environment build options (consumer type, externals, etc.) + +### 3. `nitroMain` — Build Orchestration +- Sets app type to `"custom"` +- Configures resolve aliases, server port +- `buildApp` hook → calls `buildEnvironments()` (production) +- `generateBundle` hook → tracks entry points +- `configureServer` → calls `configureViteDevServer()` (dev) +- `hotUpdate` → server-only module reload + +### 4. `nitroPrepare` — Output Cleanup +- Cleans build directory before build starts + +### 5. `nitroService` — Virtual Module Handler +- Resolves `#nitro-vite-setup` virtual module +- Provides production setup code for service environments + +### 6. `nitroPreviewPlugin` — Preview Server +- Routes all preview requests through Nitro +- WebSocket upgrade support + +## `setupNitroContext()` Flow + +1. Merge plugin config with user config +2. Load dotenv files +3. Detect SSR entry (looks for `entry-server.{ts,js,tsx,jsx,mjs}`) +4. Create Nitro instance (`createNitro()`) +5. Resolve bundler config (`getBundlerConfig()`) +6. Initialize env-runner for dev (`initEnvRunner()`) + +## Environments (`env.ts`) + +Nitro uses Vite 6+ environments API for multi-bundle builds: + +| Environment | Consumer | Purpose | +|-------------|----------|---------| +| `client` | `"client"` | Browser HTML/CSS/JS | +| `nitro` | `"server"` | Main server bundle | +| `ssr` | `"server"` | Optional SSR service | +| Custom | `"server"` | User-defined services | + +### `createNitroEnvironment()` +- Consumer: `"server"` +- Uses bundler config (Rollup/Rolldown) +- Dev: creates `FetchableDevEnvironment` with hot reload +- Prod: standard environment with minify, sourcemap, commonJS options +- Resolve: `noExternal` differs for dev vs prod +- Special conditions: `"workerd"` for miniflare, excludes `"node"` + +### `initEnvRunner()` / `getEnvRunner()` +- Uses `env-runner` package for worker management +- Supports Node Worker or Miniflare runtime +- Auto-restarts on failure (max 3 retries) +- Custom evaluator for workerd (`AsyncFunction` not allowed) +- Routes module imports through Vite's transform pipeline + +### `reloadEnvRunner()` +- Triggers full reload of the env-runner worker + +## Dev Server (`dev.ts`) + +### `FetchableDevEnvironment` (extends `DevEnvironment`) +- Overrides `fetchModule()` for CJS/ESM resolution +- For workerd: prevents externalization of bare imports +- `dispatchFetch()` — routes requests to the dev server worker +- Sends custom message on init with environment info + +### `configureViteDevServer()` +- Watches Nitro config file for changes (triggers full restart) +- WebSocket upgrade handling +- File watchers for route/API/middleware directories (debounced reload) +- RPC for `transformHTML` messages + +### Dev Middleware (`nitroDevMiddleware`) +Two-stage request routing: + +1. **Pre-processor** — checks if request should go to Nitro: + - Skips Vite internal requests (`/@`, `/__`) + - Skips file extension requests (`.js`, `.css`, etc.) + - Uses `sec-fetch-dest` header for browser detection + - Routes to `NitroDevApp` first (static/proxy/dev handlers) +2. **Main handler** — falls back to env-runner worker for server routes + +### Request Flow (Dev) +``` +Browser → Vite Dev Server + → nitroDevMiddleware (pre-processor) + → NitroDevApp (static assets, dev proxy, /_vfs) + → env-runner worker (main server logic) + → Vite static/HMR (if not handled) +``` + +## Production Build (`prod.ts`) + +### `buildEnvironments()` — 5 Stages + +**Stage 1: Build non-Nitro environments** +- Client environment (browser bundle) +- Service environments (SSR, API, custom) +- Detailed logging per environment + +**Stage 2: Renderer template processing** +- If client input == renderer template, replaces SSR outlet +- Inlines `globalThis.__nitro_vite_envs__?.["ssr"]?.fetch($REQUEST)` +- Moves processed template to build dir + +**Stage 3: Asset management** +- Calls `builder.writeAssetsManifest?.()` +- Registers asset dirs with `max-age=31536000, immutable` + +**Stage 4: Build Nitro environment** +- `prepare()` → clean output +- Build main server bundle +- Close Nitro instance +- Fire `compiled` hook +- Write build info + +**Stage 5: Preview** +- Start preview server, log success + +### `prodSetup()` Virtual Module +Generates `#nitro-vite-setup` content: +```js +// For each service environment +globalThis.__nitro_vite_envs__ = { + "ssr": { fetch: (...args) => import("entry").then(m => m.default.fetch(...args)) } +} +``` + +## Bundler Config (`bundler.ts`) + +`getBundlerConfig()` returns: +```ts +{ + base: BaseBuildConfig, + rollupConfig?: RollupConfig, // if using Rollup + rolldownConfig?: RolldownConfig // if using Rolldown +} +``` + +Common config: ESM output, tree-shaking, chunking, sourcemaps. + +**Rolldown-specific**: Transform injection, library chunking, `inlineDynamicImports`/`iife` support. +**Rollup-specific**: `@rollup/plugin-inject`, `@rollup/plugin-alias`, manual chunk naming. + +## HMR (Dev Only) + +**Server-only module reload**: +1. `hotUpdate` hook detects file change +2. Determines if module is server-only or shared +3. Server-only → sends `full-reload` to nitro environment +4. Shared → returns for normal Vite client HMR +5. Optionally reloads browser (`experimental.vite.serverReload`) + +**Directory watchers** (debounced): +- Routes, API, middleware, plugins, modules dirs +- Add/delete → full routing rebuild + reload + +## Runtime Integration + +### Worker Entry (`src/runtime/internal/vite/`) + +| File | Purpose | +|------|---------| +| `dev-entry.mjs` | Dev entry: polyfills, WebSocket adapter, schedule runner | +| `dev-worker.mjs` | Worker process: `ViteEnvRunner` class, RPC layer, env management | +| `ssr-renderer.mjs` | SSR service: calls `fetchViteEnv("ssr", req)` | + +### `ViteEnvRunner` (in `dev-worker.mjs`) +- Manages Vite `ModuleRunner` per environment +- Loads environment entry via `runner.import()` +- Routes fetch requests to loaded entries +- Exposes `__VITE_ENVIRONMENT_RUNNER_IMPORT__` for RSC + +### Runtime API (`src/runtime/vite.ts`) +- `fetchViteEnv(name, input, init)` — route fetch to named Vite environment +- Accesses `globalThis.__nitro_vite_envs__` registry + +## Dev vs Production + +| Aspect | Dev | Production | +|--------|-----|-----------| +| Runner | env-runner (node-worker / miniflare) | Bundled ESM | +| HMR | Full reload on file change | N/A | +| Errors | Interactive error page (Youch) | JSON or minimal HTML | +| Services | Lazy-loaded via env-runner | Pre-bundled via `prodSetup()` | +| Template | Dynamic (vite-env route) | Static (inlined SSR outlet) | +| Sourcemaps | Enabled | Optional | + +## Experimental Features + +`experimental.vite` options: +- `assetsImport` (default: true) — `?assets` imports via `@hiogawa/vite-plugin-fullstack` +- `serverReload` (default: true) — reload on server-only module changes +- `services` — register custom service environments + +## Key Connections + +- `src/vite.ts` — public export (`nitro` plugin) +- `src/build/build.ts` — dispatcher calls `viteBuild()` +- `src/build/config.ts` — base build config +- `src/build/plugins.ts` — base build plugins (virtual modules, auto-imports, etc.) +- `src/build/virtual/` — 14 virtual module templates +- `src/dev/app.ts` — `NitroDevApp` for dev-only handlers +- `src/dev/server.ts` — `NitroDevServer` with `RunnerManager` +- `src/runtime/internal/vite/` — runtime worker and entry points diff --git a/.claude/skills b/.claude/skills new file mode 120000 index 0000000000..2b7a412b8f --- /dev/null +++ b/.claude/skills @@ -0,0 +1 @@ +../.agents/skills \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 0a680fcf72..175cf8c183 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -3,16 +3,15 @@ { "name": "nitro-devcontainer", "forwardPorts": [3000], - "image": "node:22", + "image": "node:lts", "features": {}, "customizations": { "vscode": { "settings": {}, "extensions": [ "ms-azuretools.vscode-docker", - "dbaeumer.vscode-eslint", "github.vscode-github-actions", - "esbenp.prettier-vscode" + "oxc.oxc-vscode" ] } }, diff --git a/.eslintcache b/.eslintcache new file mode 100644 index 0000000000..1eb756e253 --- /dev/null +++ b/.eslintcache @@ -0,0 +1 @@ +[{"/home/pooya/Code/nitro/AGENTS.md":"1","/home/pooya/Code/nitro/CHANGELOG.md":"2","/home/pooya/Code/nitro/CLAUDE.md":"3","/home/pooya/Code/nitro/CODE_OF_CONDUCT.md":"4","/home/pooya/Code/nitro/CONTRIBUTING.md":"5","/home/pooya/Code/nitro/README.md":"6","/home/pooya/Code/nitro/SECURITY.md":"7","/home/pooya/Code/nitro/automd.config.ts":"8","/home/pooya/Code/nitro/build.config.ts":"9","/home/pooya/Code/nitro/changelog.config.ts":"10","/home/pooya/Code/nitro/docs/.config/automd.config.ts":"11","/home/pooya/Code/nitro/eslint.config.mjs":"12","/home/pooya/Code/nitro/examples/api-routes/api/hello/[name].ts":"13","/home/pooya/Code/nitro/examples/api-routes/api/hello.ts":"14","/home/pooya/Code/nitro/examples/api-routes/api/test.get.ts":"15","/home/pooya/Code/nitro/examples/api-routes/api/test.post.ts":"16","/home/pooya/Code/nitro/examples/api-routes/nitro.config.ts":"17","/home/pooya/Code/nitro/examples/api-routes/vite.config.ts":"18","/home/pooya/Code/nitro/examples/auto-imports/nitro.config.ts":"19","/home/pooya/Code/nitro/examples/auto-imports/server/utils/hello.ts":"20","/home/pooya/Code/nitro/examples/auto-imports/server.ts":"21","/home/pooya/Code/nitro/examples/auto-imports/vite.config.ts":"22","/home/pooya/Code/nitro/examples/cached-handler/nitro.config.ts":"23","/home/pooya/Code/nitro/examples/cached-handler/server.ts":"24","/home/pooya/Code/nitro/examples/cached-handler/vite.config.ts":"25","/home/pooya/Code/nitro/examples/custom-error-handler/error.ts":"26","/home/pooya/Code/nitro/examples/custom-error-handler/nitro.config.ts":"27","/home/pooya/Code/nitro/examples/custom-error-handler/server.ts":"28","/home/pooya/Code/nitro/examples/custom-error-handler/vite.config.ts":"29","/home/pooya/Code/nitro/examples/database/nitro.config.ts":"30","/home/pooya/Code/nitro/examples/database/server.ts":"31","/home/pooya/Code/nitro/examples/database/tasks/db/migrate.ts":"32","/home/pooya/Code/nitro/examples/database/vite.config.ts":"33","/home/pooya/Code/nitro/examples/elysia/nitro.config.ts":"34","/home/pooya/Code/nitro/examples/elysia/server.ts":"35","/home/pooya/Code/nitro/examples/elysia/vite.config.ts":"36","/home/pooya/Code/nitro/examples/express/nitro.config.ts":"37","/home/pooya/Code/nitro/examples/express/server.node.ts":"38","/home/pooya/Code/nitro/examples/express/vite.config.ts":"39","/home/pooya/Code/nitro/examples/fastify/nitro.config.ts":"40","/home/pooya/Code/nitro/examples/fastify/server.node.ts":"41","/home/pooya/Code/nitro/examples/fastify/vite.config.ts":"42","/home/pooya/Code/nitro/examples/hello-world/nitro.config.ts":"43","/home/pooya/Code/nitro/examples/hello-world/server.ts":"44","/home/pooya/Code/nitro/examples/hello-world/vite.config.ts":"45","/home/pooya/Code/nitro/examples/hono/nitro.config.ts":"46","/home/pooya/Code/nitro/examples/hono/server.ts":"47","/home/pooya/Code/nitro/examples/hono/vite.config.ts":"48","/home/pooya/Code/nitro/examples/import-alias/nitro.config.ts":"49","/home/pooya/Code/nitro/examples/import-alias/server/routes/index.ts":"50","/home/pooya/Code/nitro/examples/import-alias/server/utils/math.ts":"51","/home/pooya/Code/nitro/examples/import-alias/vite.config.ts":"52","/home/pooya/Code/nitro/examples/middleware/nitro.config.ts":"53","/home/pooya/Code/nitro/examples/middleware/server/middleware/auth.ts":"54","/home/pooya/Code/nitro/examples/middleware/server.ts":"55","/home/pooya/Code/nitro/examples/middleware/vite.config.ts":"56","/home/pooya/Code/nitro/examples/mono-jsx/nitro.config.ts":"57","/home/pooya/Code/nitro/examples/mono-jsx/server.tsx":"58","/home/pooya/Code/nitro/examples/mono-jsx/vite.config.ts":"59","/home/pooya/Code/nitro/examples/nano-jsx/nitro.config.ts":"60","/home/pooya/Code/nitro/examples/nano-jsx/server.tsx":"61","/home/pooya/Code/nitro/examples/nano-jsx/vite.config.ts":"62","/home/pooya/Code/nitro/examples/plugins/nitro.config.ts":"63","/home/pooya/Code/nitro/examples/plugins/server/plugins/test.ts":"64","/home/pooya/Code/nitro/examples/plugins/server.ts":"65","/home/pooya/Code/nitro/examples/plugins/vite.config.ts":"66","/home/pooya/Code/nitro/examples/renderer/api/hello.ts":"67","/home/pooya/Code/nitro/examples/renderer/nitro.config.ts":"68","/home/pooya/Code/nitro/examples/renderer/renderer.ts":"69","/home/pooya/Code/nitro/examples/renderer/vite.config.ts":"70","/home/pooya/Code/nitro/examples/runtime-config/nitro.config.ts":"71","/home/pooya/Code/nitro/examples/runtime-config/server.ts":"72","/home/pooya/Code/nitro/examples/runtime-config/vite.config.ts":"73","/home/pooya/Code/nitro/examples/server-fetch/nitro.config.ts":"74","/home/pooya/Code/nitro/examples/server-fetch/routes/hello.ts":"75","/home/pooya/Code/nitro/examples/server-fetch/routes/index.ts":"76","/home/pooya/Code/nitro/examples/server-fetch/vite.config.ts":"77","/home/pooya/Code/nitro/examples/shiki/api/highlight.ts":"78","/home/pooya/Code/nitro/examples/shiki/nitro.config.ts":"79","/home/pooya/Code/nitro/examples/shiki/vite.config.ts":"80","/home/pooya/Code/nitro/examples/virtual-routes/nitro.config.ts":"81","/home/pooya/Code/nitro/examples/virtual-routes/vite.config.ts":"82","/home/pooya/Code/nitro/examples/vite-nitro-plugin/vite.config.mjs":"83","/home/pooya/Code/nitro/examples/vite-rsc/app/action.tsx":"84","/home/pooya/Code/nitro/examples/vite-rsc/app/client.tsx":"85","/home/pooya/Code/nitro/examples/vite-rsc/app/framework/entry.browser.tsx":"86","/home/pooya/Code/nitro/examples/vite-rsc/app/framework/entry.rsc.tsx":"87","/home/pooya/Code/nitro/examples/vite-rsc/app/framework/entry.ssr.tsx":"88","/home/pooya/Code/nitro/examples/vite-rsc/app/framework/error-boundary.tsx":"89","/home/pooya/Code/nitro/examples/vite-rsc/app/framework/request.tsx":"90","/home/pooya/Code/nitro/examples/vite-rsc/app/root.tsx":"91","/home/pooya/Code/nitro/examples/vite-rsc/vite.config.ts":"92","/home/pooya/Code/nitro/examples/vite-ssr-html/app/entry-server.ts":"93","/home/pooya/Code/nitro/examples/vite-ssr-html/routes/quote.ts":"94","/home/pooya/Code/nitro/examples/vite-ssr-html/vite.config.ts":"95","/home/pooya/Code/nitro/examples/vite-ssr-preact/src/app.tsx":"96","/home/pooya/Code/nitro/examples/vite-ssr-preact/src/entry-client.tsx":"97","/home/pooya/Code/nitro/examples/vite-ssr-preact/src/entry-server.tsx":"98","/home/pooya/Code/nitro/examples/vite-ssr-preact/vite.config.mjs":"99","/home/pooya/Code/nitro/examples/vite-ssr-react/src/app.tsx":"100","/home/pooya/Code/nitro/examples/vite-ssr-react/src/entry-client.tsx":"101","/home/pooya/Code/nitro/examples/vite-ssr-react/src/entry-server.tsx":"102","/home/pooya/Code/nitro/examples/vite-ssr-react/vite.config.mjs":"103","/home/pooya/Code/nitro/examples/vite-ssr-solid/src/app.tsx":"104","/home/pooya/Code/nitro/examples/vite-ssr-solid/src/entry-client.tsx":"105","/home/pooya/Code/nitro/examples/vite-ssr-solid/src/entry-server.tsx":"106","/home/pooya/Code/nitro/examples/vite-ssr-solid/vite.config.mjs":"107","/home/pooya/Code/nitro/examples/vite-ssr-tsr-react/src/main.tsx":"108","/home/pooya/Code/nitro/examples/vite-ssr-tsr-react/src/routes/__root.tsx":"109","/home/pooya/Code/nitro/examples/vite-ssr-tsr-react/src/routes/index.tsx":"110","/home/pooya/Code/nitro/examples/vite-ssr-tsr-react/vite.config.mjs":"111","/home/pooya/Code/nitro/examples/vite-ssr-tss-react/server.ts":"112","/home/pooya/Code/nitro/examples/vite-ssr-tss-react/src/router.tsx":"113","/home/pooya/Code/nitro/examples/vite-ssr-tss-react/src/routes/__root.tsx":"114","/home/pooya/Code/nitro/examples/vite-ssr-tss-react/src/routes/api/test.ts":"115","/home/pooya/Code/nitro/examples/vite-ssr-tss-react/src/routes/index.tsx":"116","/home/pooya/Code/nitro/examples/vite-ssr-tss-react/vite.config.mjs":"117","/home/pooya/Code/nitro/examples/vite-ssr-vue-router/app/entry-client.ts":"118","/home/pooya/Code/nitro/examples/vite-ssr-vue-router/app/entry-server.ts":"119","/home/pooya/Code/nitro/examples/vite-ssr-vue-router/app/routes.ts":"120","/home/pooya/Code/nitro/examples/vite-ssr-vue-router/app/shims.d.ts":"121","/home/pooya/Code/nitro/examples/vite-ssr-vue-router/vite.config.mjs":"122","/home/pooya/Code/nitro/examples/vite-trpc/server/trpc.ts":"123","/home/pooya/Code/nitro/examples/vite-trpc/vite.config.ts":"124","/home/pooya/Code/nitro/examples/websocket/nitro.config.ts":"125","/home/pooya/Code/nitro/examples/websocket/routes/_ws.ts":"126","/home/pooya/Code/nitro/examples/websocket/vite.config.ts":"127","/home/pooya/Code/nitro/lib/h3.d.mts":"128","/home/pooya/Code/nitro/lib/h3.mjs":"129","/home/pooya/Code/nitro/lib/vite.types.d.mts":"130","/home/pooya/Code/nitro/lib/vite.types.mjs":"131","/home/pooya/Code/nitro/playground/nitro.config.ts":"132","/home/pooya/Code/nitro/playground/server.ts":"133","/home/pooya/Code/nitro/playground/vite.config.ts":"134","/home/pooya/Code/nitro/scripts/bump-nightly.ts":"135","/home/pooya/Code/nitro/scripts/gen-node-compat.ts":"136","/home/pooya/Code/nitro/scripts/gen-presets.ts":"137","/home/pooya/Code/nitro/src/build/assets.ts":"138","/home/pooya/Code/nitro/src/build/build.ts":"139","/home/pooya/Code/nitro/src/build/chunks.ts":"140","/home/pooya/Code/nitro/src/build/config.ts":"141","/home/pooya/Code/nitro/src/build/info.ts":"142","/home/pooya/Code/nitro/src/build/plugins/externals.ts":"143","/home/pooya/Code/nitro/src/build/plugins/oxc.ts":"144","/home/pooya/Code/nitro/src/build/plugins/raw.ts":"145","/home/pooya/Code/nitro/src/build/plugins/route-meta.ts":"146","/home/pooya/Code/nitro/src/build/plugins/server-main.ts":"147","/home/pooya/Code/nitro/src/build/plugins/sourcemap-min.ts":"148","/home/pooya/Code/nitro/src/build/plugins/virtual.ts":"149","/home/pooya/Code/nitro/src/build/plugins.ts":"150","/home/pooya/Code/nitro/src/build/prepare.ts":"151","/home/pooya/Code/nitro/src/build/rolldown/build.ts":"152","/home/pooya/Code/nitro/src/build/rolldown/config.ts":"153","/home/pooya/Code/nitro/src/build/rolldown/dev.ts":"154","/home/pooya/Code/nitro/src/build/rolldown/prod.ts":"155","/home/pooya/Code/nitro/src/build/rollup/build.ts":"156","/home/pooya/Code/nitro/src/build/rollup/config.ts":"157","/home/pooya/Code/nitro/src/build/rollup/dev.ts":"158","/home/pooya/Code/nitro/src/build/rollup/error.ts":"159","/home/pooya/Code/nitro/src/build/rollup/prod.ts":"160","/home/pooya/Code/nitro/src/build/types.ts":"161","/home/pooya/Code/nitro/src/build/virtual/_all.ts":"162","/home/pooya/Code/nitro/src/build/virtual/database.ts":"163","/home/pooya/Code/nitro/src/build/virtual/error-handler.ts":"164","/home/pooya/Code/nitro/src/build/virtual/feature-flags.ts":"165","/home/pooya/Code/nitro/src/build/virtual/plugins.ts":"166","/home/pooya/Code/nitro/src/build/virtual/polyfills.ts":"167","/home/pooya/Code/nitro/src/build/virtual/public-assets.ts":"168","/home/pooya/Code/nitro/src/build/virtual/renderer-template.ts":"169","/home/pooya/Code/nitro/src/build/virtual/routing-meta.ts":"170","/home/pooya/Code/nitro/src/build/virtual/routing.ts":"171","/home/pooya/Code/nitro/src/build/virtual/runtime-config.ts":"172","/home/pooya/Code/nitro/src/build/virtual/server-assets.ts":"173","/home/pooya/Code/nitro/src/build/virtual/storage.ts":"174","/home/pooya/Code/nitro/src/build/virtual/tasks.ts":"175","/home/pooya/Code/nitro/src/build/vite/build.ts":"176","/home/pooya/Code/nitro/src/build/vite/bundler.ts":"177","/home/pooya/Code/nitro/src/build/vite/dev.ts":"178","/home/pooya/Code/nitro/src/build/vite/env.ts":"179","/home/pooya/Code/nitro/src/build/vite/plugin.ts":"180","/home/pooya/Code/nitro/src/build/vite/preview.ts":"181","/home/pooya/Code/nitro/src/build/vite/prod.ts":"182","/home/pooya/Code/nitro/src/build/vite/types.ts":"183","/home/pooya/Code/nitro/src/builder.ts":"184","/home/pooya/Code/nitro/src/cli/commands/build.ts":"185","/home/pooya/Code/nitro/src/cli/commands/dev.ts":"186","/home/pooya/Code/nitro/src/cli/commands/prepare.ts":"187","/home/pooya/Code/nitro/src/cli/commands/task/index.ts":"188","/home/pooya/Code/nitro/src/cli/commands/task/list.ts":"189","/home/pooya/Code/nitro/src/cli/commands/task/run.ts":"190","/home/pooya/Code/nitro/src/cli/common.ts":"191","/home/pooya/Code/nitro/src/cli/index.ts":"192","/home/pooya/Code/nitro/src/config/defaults.ts":"193","/home/pooya/Code/nitro/src/config/loader.ts":"194","/home/pooya/Code/nitro/src/config/resolvers/assets.ts":"195","/home/pooya/Code/nitro/src/config/resolvers/builder.ts":"196","/home/pooya/Code/nitro/src/config/resolvers/compatibility.ts":"197","/home/pooya/Code/nitro/src/config/resolvers/database.ts":"198","/home/pooya/Code/nitro/src/config/resolvers/error.ts":"199","/home/pooya/Code/nitro/src/config/resolvers/export-conditions.ts":"200","/home/pooya/Code/nitro/src/config/resolvers/imports.ts":"201","/home/pooya/Code/nitro/src/config/resolvers/open-api.ts":"202","/home/pooya/Code/nitro/src/config/resolvers/paths.ts":"203","/home/pooya/Code/nitro/src/config/resolvers/route-rules.ts":"204","/home/pooya/Code/nitro/src/config/resolvers/runtime-config.ts":"205","/home/pooya/Code/nitro/src/config/resolvers/storage.ts":"206","/home/pooya/Code/nitro/src/config/resolvers/tsconfig.ts":"207","/home/pooya/Code/nitro/src/config/resolvers/unenv.ts":"208","/home/pooya/Code/nitro/src/config/resolvers/url.ts":"209","/home/pooya/Code/nitro/src/config/update.ts":"210","/home/pooya/Code/nitro/src/dev/app.ts":"211","/home/pooya/Code/nitro/src/dev/server.ts":"212","/home/pooya/Code/nitro/src/dev/vfs.ts":"213","/home/pooya/Code/nitro/src/global.ts":"214","/home/pooya/Code/nitro/src/module.ts":"215","/home/pooya/Code/nitro/src/nitro.ts":"216","/home/pooya/Code/nitro/src/prerender/prerender.ts":"217","/home/pooya/Code/nitro/src/prerender/utils.ts":"218","/home/pooya/Code/nitro/src/presets/_nitro/base-worker.ts":"219","/home/pooya/Code/nitro/src/presets/_nitro/nitro-dev.ts":"220","/home/pooya/Code/nitro/src/presets/_nitro/nitro-prerender.ts":"221","/home/pooya/Code/nitro/src/presets/_nitro/preset.ts":"222","/home/pooya/Code/nitro/src/presets/_nitro/runtime/nitro-dev.ts":"223","/home/pooya/Code/nitro/src/presets/_nitro/runtime/nitro-prerenderer.ts":"224","/home/pooya/Code/nitro/src/presets/_nitro/runtime/service-worker.ts":"225","/home/pooya/Code/nitro/src/presets/_resolve.ts":"226","/home/pooya/Code/nitro/src/presets/_static/preset.ts":"227","/home/pooya/Code/nitro/src/presets/_utils/fs.ts":"228","/home/pooya/Code/nitro/src/presets/_utils/preset.ts":"229","/home/pooya/Code/nitro/src/presets/alwaysdata/preset.ts":"230","/home/pooya/Code/nitro/src/presets/aws-amplify/preset.ts":"231","/home/pooya/Code/nitro/src/presets/aws-amplify/runtime/aws-amplify.ts":"232","/home/pooya/Code/nitro/src/presets/aws-amplify/types.ts":"233","/home/pooya/Code/nitro/src/presets/aws-amplify/utils.ts":"234","/home/pooya/Code/nitro/src/presets/aws-lambda/preset.ts":"235","/home/pooya/Code/nitro/src/presets/aws-lambda/runtime/_utils.ts":"236","/home/pooya/Code/nitro/src/presets/aws-lambda/runtime/aws-lambda-streaming.ts":"237","/home/pooya/Code/nitro/src/presets/aws-lambda/runtime/aws-lambda.ts":"238","/home/pooya/Code/nitro/src/presets/aws-lambda/types.ts":"239","/home/pooya/Code/nitro/src/presets/azure/preset.ts":"240","/home/pooya/Code/nitro/src/presets/azure/runtime/_utils.ts":"241","/home/pooya/Code/nitro/src/presets/azure/runtime/azure-swa.ts":"242","/home/pooya/Code/nitro/src/presets/azure/types.ts":"243","/home/pooya/Code/nitro/src/presets/azure/utils.ts":"244","/home/pooya/Code/nitro/src/presets/bun/preset.ts":"245","/home/pooya/Code/nitro/src/presets/bun/runtime/bun.ts":"246","/home/pooya/Code/nitro/src/presets/cleavr/preset.ts":"247","/home/pooya/Code/nitro/src/presets/cloudflare/dev.ts":"248","/home/pooya/Code/nitro/src/presets/cloudflare/entry-exports.ts":"249","/home/pooya/Code/nitro/src/presets/cloudflare/preset.ts":"250","/home/pooya/Code/nitro/src/presets/cloudflare/runtime/_module-handler.ts":"251","/home/pooya/Code/nitro/src/presets/cloudflare/runtime/cloudflare-durable.ts":"252","/home/pooya/Code/nitro/src/presets/cloudflare/runtime/cloudflare-module.ts":"253","/home/pooya/Code/nitro/src/presets/cloudflare/runtime/cloudflare-pages.ts":"254","/home/pooya/Code/nitro/src/presets/cloudflare/runtime/plugin.dev.ts":"255","/home/pooya/Code/nitro/src/presets/cloudflare/runtime/shims/workers.dev.mjs":"256","/home/pooya/Code/nitro/src/presets/cloudflare/types.ts":"257","/home/pooya/Code/nitro/src/presets/cloudflare/unenv/node-compat.ts":"258","/home/pooya/Code/nitro/src/presets/cloudflare/unenv/preset.ts":"259","/home/pooya/Code/nitro/src/presets/cloudflare/utils.ts":"260","/home/pooya/Code/nitro/src/presets/cloudflare/wrangler/_utils.ts":"261","/home/pooya/Code/nitro/src/presets/cloudflare/wrangler/config.ts":"262","/home/pooya/Code/nitro/src/presets/cloudflare/wrangler/environment.ts":"263","/home/pooya/Code/nitro/src/presets/deno/preset.ts":"264","/home/pooya/Code/nitro/src/presets/deno/runtime/deno-deploy.ts":"265","/home/pooya/Code/nitro/src/presets/deno/runtime/deno-server.ts":"266","/home/pooya/Code/nitro/src/presets/deno/unenv/node-compat.ts":"267","/home/pooya/Code/nitro/src/presets/deno/unenv/preset.ts":"268","/home/pooya/Code/nitro/src/presets/digitalocean/preset.ts":"269","/home/pooya/Code/nitro/src/presets/firebase/preset.ts":"270","/home/pooya/Code/nitro/src/presets/firebase/types.ts":"271","/home/pooya/Code/nitro/src/presets/flightcontrol/preset.ts":"272","/home/pooya/Code/nitro/src/presets/genezio/preset.ts":"273","/home/pooya/Code/nitro/src/presets/heroku/preset.ts":"274","/home/pooya/Code/nitro/src/presets/iis/preset.ts":"275","/home/pooya/Code/nitro/src/presets/iis/utils.ts":"276","/home/pooya/Code/nitro/src/presets/index.ts":"277","/home/pooya/Code/nitro/src/presets/koyeb/preset.ts":"278","/home/pooya/Code/nitro/src/presets/netlify/preset.ts":"279","/home/pooya/Code/nitro/src/presets/netlify/runtime/netlify-edge.ts":"280","/home/pooya/Code/nitro/src/presets/netlify/runtime/netlify.ts":"281","/home/pooya/Code/nitro/src/presets/netlify/types.ts":"282","/home/pooya/Code/nitro/src/presets/netlify/utils.ts":"283","/home/pooya/Code/nitro/src/presets/node/cluster.ts":"284","/home/pooya/Code/nitro/src/presets/node/preset.ts":"285","/home/pooya/Code/nitro/src/presets/node/runtime/node-cluster.ts":"286","/home/pooya/Code/nitro/src/presets/node/runtime/node-middleware.ts":"287","/home/pooya/Code/nitro/src/presets/node/runtime/node-server.ts":"288","/home/pooya/Code/nitro/src/presets/platform.sh/preset.ts":"289","/home/pooya/Code/nitro/src/presets/render.com/preset.ts":"290","/home/pooya/Code/nitro/src/presets/standard/preset.ts":"291","/home/pooya/Code/nitro/src/presets/standard/runtime/server.ts":"292","/home/pooya/Code/nitro/src/presets/stormkit/preset.ts":"293","/home/pooya/Code/nitro/src/presets/stormkit/runtime/stormkit.ts":"294","/home/pooya/Code/nitro/src/presets/vercel/preset.ts":"295","/home/pooya/Code/nitro/src/presets/vercel/runtime/isr.ts":"296","/home/pooya/Code/nitro/src/presets/vercel/runtime/vercel.node.ts":"297","/home/pooya/Code/nitro/src/presets/vercel/runtime/vercel.web.ts":"298","/home/pooya/Code/nitro/src/presets/vercel/types.ts":"299","/home/pooya/Code/nitro/src/presets/vercel/utils.ts":"300","/home/pooya/Code/nitro/src/presets/winterjs/preset.ts":"301","/home/pooya/Code/nitro/src/presets/winterjs/runtime/winterjs.ts":"302","/home/pooya/Code/nitro/src/presets/zeabur/preset.ts":"303","/home/pooya/Code/nitro/src/presets/zeabur/runtime/zeabur.ts":"304","/home/pooya/Code/nitro/src/presets/zerops/preset.ts":"305","/home/pooya/Code/nitro/src/routing.ts":"306","/home/pooya/Code/nitro/src/runner/node.ts":"307","/home/pooya/Code/nitro/src/runner/proxy.ts":"308","/home/pooya/Code/nitro/src/runtime/app.ts":"309","/home/pooya/Code/nitro/src/runtime/cache.ts":"310","/home/pooya/Code/nitro/src/runtime/config.ts":"311","/home/pooya/Code/nitro/src/runtime/context.ts":"312","/home/pooya/Code/nitro/src/runtime/database.ts":"313","/home/pooya/Code/nitro/src/runtime/internal/app.ts":"314","/home/pooya/Code/nitro/src/runtime/internal/cache.ts":"315","/home/pooya/Code/nitro/src/runtime/internal/context.ts":"316","/home/pooya/Code/nitro/src/runtime/internal/database.ts":"317","/home/pooya/Code/nitro/src/runtime/internal/empty.ts":"318","/home/pooya/Code/nitro/src/runtime/internal/error/dev.ts":"319","/home/pooya/Code/nitro/src/runtime/internal/error/hooks.ts":"320","/home/pooya/Code/nitro/src/runtime/internal/error/prod.ts":"321","/home/pooya/Code/nitro/src/runtime/internal/error/utils.ts":"322","/home/pooya/Code/nitro/src/runtime/internal/meta.ts":"323","/home/pooya/Code/nitro/src/runtime/internal/plugin.ts":"324","/home/pooya/Code/nitro/src/runtime/internal/route-rules.ts":"325","/home/pooya/Code/nitro/src/runtime/internal/routes/dev-tasks.ts":"326","/home/pooya/Code/nitro/src/runtime/internal/routes/openapi.ts":"327","/home/pooya/Code/nitro/src/runtime/internal/routes/renderer-template.dev.ts":"328","/home/pooya/Code/nitro/src/runtime/internal/routes/renderer-template.ts":"329","/home/pooya/Code/nitro/src/runtime/internal/routes/scalar.ts":"330","/home/pooya/Code/nitro/src/runtime/internal/routes/swagger.ts":"331","/home/pooya/Code/nitro/src/runtime/internal/runtime-config.ts":"332","/home/pooya/Code/nitro/src/runtime/internal/static.ts":"333","/home/pooya/Code/nitro/src/runtime/internal/storage.ts":"334","/home/pooya/Code/nitro/src/runtime/internal/task.ts":"335","/home/pooya/Code/nitro/src/runtime/internal/vite/dev-entry.mjs":"336","/home/pooya/Code/nitro/src/runtime/internal/vite/node-runner.mjs":"337","/home/pooya/Code/nitro/src/runtime/internal/vite/ssr-renderer.mjs":"338","/home/pooya/Code/nitro/src/runtime/meta.ts":"339","/home/pooya/Code/nitro/src/runtime/nitro.ts":"340","/home/pooya/Code/nitro/src/runtime/runtime-config.ts":"341","/home/pooya/Code/nitro/src/runtime/storage.ts":"342","/home/pooya/Code/nitro/src/runtime/task.ts":"343","/home/pooya/Code/nitro/src/runtime/virtual/_runtime_warn.ts":"344","/home/pooya/Code/nitro/src/runtime/virtual/database.ts":"345","/home/pooya/Code/nitro/src/runtime/virtual/error-handler.ts":"346","/home/pooya/Code/nitro/src/runtime/virtual/feature-flags.ts":"347","/home/pooya/Code/nitro/src/runtime/virtual/plugins.ts":"348","/home/pooya/Code/nitro/src/runtime/virtual/polyfills.ts":"349","/home/pooya/Code/nitro/src/runtime/virtual/public-assets.ts":"350","/home/pooya/Code/nitro/src/runtime/virtual/renderer-template.ts":"351","/home/pooya/Code/nitro/src/runtime/virtual/routing-meta.ts":"352","/home/pooya/Code/nitro/src/runtime/virtual/routing.ts":"353","/home/pooya/Code/nitro/src/runtime/virtual/runtime-config.ts":"354","/home/pooya/Code/nitro/src/runtime/virtual/server-assets.ts":"355","/home/pooya/Code/nitro/src/runtime/virtual/storage.ts":"356","/home/pooya/Code/nitro/src/runtime/virtual/tasks.ts":"357","/home/pooya/Code/nitro/src/runtime/vite.ts":"358","/home/pooya/Code/nitro/src/scan.ts":"359","/home/pooya/Code/nitro/src/task.ts":"360","/home/pooya/Code/nitro/src/types/_utils.ts":"361","/home/pooya/Code/nitro/src/types/build.ts":"362","/home/pooya/Code/nitro/src/types/config.ts":"363","/home/pooya/Code/nitro/src/types/fetch/_match.ts":"364","/home/pooya/Code/nitro/src/types/fetch/_serialize.ts":"365","/home/pooya/Code/nitro/src/types/fetch/fetch.ts":"366","/home/pooya/Code/nitro/src/types/fetch/index.ts":"367","/home/pooya/Code/nitro/src/types/global.ts":"368","/home/pooya/Code/nitro/src/types/h3.ts":"369","/home/pooya/Code/nitro/src/types/handler.ts":"370","/home/pooya/Code/nitro/src/types/hooks.ts":"371","/home/pooya/Code/nitro/src/types/index.ts":"372","/home/pooya/Code/nitro/src/types/module.ts":"373","/home/pooya/Code/nitro/src/types/nitro.ts":"374","/home/pooya/Code/nitro/src/types/openapi-ts.ts":"375","/home/pooya/Code/nitro/src/types/openapi.ts":"376","/home/pooya/Code/nitro/src/types/prerender.ts":"377","/home/pooya/Code/nitro/src/types/preset.ts":"378","/home/pooya/Code/nitro/src/types/route-rules.ts":"379","/home/pooya/Code/nitro/src/types/runner.ts":"380","/home/pooya/Code/nitro/src/types/runtime/asset.ts":"381","/home/pooya/Code/nitro/src/types/runtime/cache.ts":"382","/home/pooya/Code/nitro/src/types/runtime/index.ts":"383","/home/pooya/Code/nitro/src/types/runtime/nitro.ts":"384","/home/pooya/Code/nitro/src/types/runtime/task.ts":"385","/home/pooya/Code/nitro/src/types/srvx.ts":"386","/home/pooya/Code/nitro/src/utils/compress.ts":"387","/home/pooya/Code/nitro/src/utils/dep.ts":"388","/home/pooya/Code/nitro/src/utils/fs-tree.ts":"389","/home/pooya/Code/nitro/src/utils/fs.ts":"390","/home/pooya/Code/nitro/src/utils/parallel.ts":"391","/home/pooya/Code/nitro/src/utils/regex.ts":"392","/home/pooya/Code/nitro/src/vite.ts":"393","/home/pooya/Code/nitro/test/examples.test.ts":"394","/home/pooya/Code/nitro/test/fixture/error.ts":"395","/home/pooya/Code/nitro/test/fixture/exports.cloudflare.ts":"396","/home/pooya/Code/nitro/test/fixture/nitro.config.ts":"397","/home/pooya/Code/nitro/test/fixture/public/foo.js":"398","/home/pooya/Code/nitro/test/fixture/server/files/sqlts.sql.ts":"399","/home/pooya/Code/nitro/test/fixture/server/middleware/_ignored.ts":"400","/home/pooya/Code/nitro/test/fixture/server/plugins/errors.ts":"401","/home/pooya/Code/nitro/test/fixture/server/plugins/vary.ts":"402","/home/pooya/Code/nitro/test/fixture/server/routes/(route-group)/route-group.ts":"403","/home/pooya/Code/nitro/test/fixture/server/routes/500.ts":"404","/home/pooya/Code/nitro/test/fixture/server/routes/api/_ignored.ts":"405","/home/pooya/Code/nitro/test/fixture/server/routes/api/cached.ts":"406","/home/pooya/Code/nitro/test/fixture/server/routes/api/db.ts":"407","/home/pooya/Code/nitro/test/fixture/server/routes/api/echo.ts":"408","/home/pooya/Code/nitro/test/fixture/server/routes/api/error.ts":"409","/home/pooya/Code/nitro/test/fixture/server/routes/api/errors.ts":"410","/home/pooya/Code/nitro/test/fixture/server/routes/api/headers.ts":"411","/home/pooya/Code/nitro/test/fixture/server/routes/api/hello.ts":"412","/home/pooya/Code/nitro/test/fixture/server/routes/api/hey/index.get.ts":"413","/home/pooya/Code/nitro/test/fixture/server/routes/api/kebab.ts":"414","/home/pooya/Code/nitro/test/fixture/server/routes/api/meta/test.ts":"415","/home/pooya/Code/nitro/test/fixture/server/routes/api/methods/foo.get.get.ts":"416","/home/pooya/Code/nitro/test/fixture/server/routes/api/methods/get.ts":"417","/home/pooya/Code/nitro/test/fixture/server/routes/api/param/[test-id].ts":"418","/home/pooya/Code/nitro/test/fixture/server/routes/api/storage/item.get.ts":"419","/home/pooya/Code/nitro/test/fixture/server/routes/api/storage/item.put.ts":"420","/home/pooya/Code/nitro/test/fixture/server/routes/api/upload.post.ts":"421","/home/pooya/Code/nitro/test/fixture/server/routes/api/wildcard/[...param].ts":"422","/home/pooya/Code/nitro/test/fixture/server/routes/assets/[id].ts":"423","/home/pooya/Code/nitro/test/fixture/server/routes/assets/all.ts":"424","/home/pooya/Code/nitro/test/fixture/server/routes/assets/md.ts":"425","/home/pooya/Code/nitro/test/fixture/server/routes/config.ts":"426","/home/pooya/Code/nitro/test/fixture/server/routes/context.ts":"427","/home/pooya/Code/nitro/test/fixture/server/routes/env/index.dev.ts":"428","/home/pooya/Code/nitro/test/fixture/server/routes/env/index.get.prod.ts":"429","/home/pooya/Code/nitro/test/fixture/server/routes/error-stack.ts":"430","/home/pooya/Code/nitro/test/fixture/server/routes/fetch.ts":"431","/home/pooya/Code/nitro/test/fixture/server/routes/file.ts":"432","/home/pooya/Code/nitro/test/fixture/server/routes/icon.png.ts":"433","/home/pooya/Code/nitro/test/fixture/server/routes/imports.ts":"434","/home/pooya/Code/nitro/test/fixture/server/routes/json-string.ts":"435","/home/pooya/Code/nitro/test/fixture/server/routes/jsx.tsx":"436","/home/pooya/Code/nitro/test/fixture/server/routes/modules.ts":"437","/home/pooya/Code/nitro/test/fixture/server/routes/node-compat.ts":"438","/home/pooya/Code/nitro/test/fixture/server/routes/prerender-custom.html.ts":"439","/home/pooya/Code/nitro/test/fixture/server/routes/prerender.ts":"440","/home/pooya/Code/nitro/test/fixture/server/routes/raw.ts":"441","/home/pooya/Code/nitro/test/fixture/server/routes/replace.ts":"442","/home/pooya/Code/nitro/test/fixture/server/routes/rules/[...slug].ts":"443","/home/pooya/Code/nitro/test/fixture/server/routes/static-flags.ts":"444","/home/pooya/Code/nitro/test/fixture/server/routes/stream.ts":"445","/home/pooya/Code/nitro/test/fixture/server/routes/tasks/[...name].ts":"446","/home/pooya/Code/nitro/test/fixture/server/routes/wait-until.ts":"447","/home/pooya/Code/nitro/test/fixture/server/routes/wasm/dynamic-import.ts":"448","/home/pooya/Code/nitro/test/fixture/server/routes/wasm/static-import.ts":"449","/home/pooya/Code/nitro/test/fixture/server/tasks/db/migrate.ts":"450","/home/pooya/Code/nitro/test/fixture/server/tasks/test.ts":"451","/home/pooya/Code/nitro/test/fixture/server/utils/foo/bar/test.ts":"452","/home/pooya/Code/nitro/test/fixture/server/utils/foo/test.ts":"453","/home/pooya/Code/nitro/test/fixture/server/utils/test.ts":"454","/home/pooya/Code/nitro/test/fixture/server.config.ts":"455","/home/pooya/Code/nitro/test/fixture/server.ts":"456","/home/pooya/Code/nitro/test/fixture/vite.config.ts":"457","/home/pooya/Code/nitro/test/minimal/minimal.test.ts":"458","/home/pooya/Code/nitro/test/minimal/nitro.config.ts":"459","/home/pooya/Code/nitro/test/minimal/server.ts":"460","/home/pooya/Code/nitro/test/minimal/vite.config.mjs":"461","/home/pooya/Code/nitro/test/presets/aws-lambda.test.ts":"462","/home/pooya/Code/nitro/test/presets/azure-swa.test.ts":"463","/home/pooya/Code/nitro/test/presets/bun.test.ts":"464","/home/pooya/Code/nitro/test/presets/cloudflare-module.test.ts":"465","/home/pooya/Code/nitro/test/presets/cloudflare-pages.test.ts":"466","/home/pooya/Code/nitro/test/presets/deno-server.test.ts":"467","/home/pooya/Code/nitro/test/presets/netlify.test.ts":"468","/home/pooya/Code/nitro/test/presets/nitro-dev.test.ts":"469","/home/pooya/Code/nitro/test/presets/node.test.ts":"470","/home/pooya/Code/nitro/test/presets/standard.test.ts":"471","/home/pooya/Code/nitro/test/presets/static.test.ts":"472","/home/pooya/Code/nitro/test/presets/vercel.test.ts":"473","/home/pooya/Code/nitro/test/presets/winterjs.test.ts":"474","/home/pooya/Code/nitro/test/scripts/gen-fixture-types.ts":"475","/home/pooya/Code/nitro/test/tests.ts":"476","/home/pooya/Code/nitro/test/unit/azure.utils.test.ts":"477","/home/pooya/Code/nitro/test/unit/runtime-config.env.test.ts":"478","/home/pooya/Code/nitro/test/unit/runtime-config.test.ts":"479","/home/pooya/Code/nitro/test/unit/virtual.test.ts":"480","/home/pooya/Code/nitro/vitest.config.ts":"481"},{"size":6278,"mtime":1768935766630,"results":"482","hashOfConfig":"483"},{"size":11098,"mtime":1769020993118,"results":"484","hashOfConfig":"483"},{"size":11,"mtime":1768935766630,"results":"485","hashOfConfig":"483"},{"size":5220,"mtime":1768485628956,"results":"486","hashOfConfig":"483"},{"size":2878,"mtime":1768485628956,"results":"487","hashOfConfig":"483"},{"size":658,"mtime":1769019507194,"results":"488","hashOfConfig":"483"},{"size":622,"mtime":1768485628956,"results":"489","hashOfConfig":"483"},{"size":726,"mtime":1768485628956,"results":"490","hashOfConfig":"491"},{"size":5625,"mtime":1768935766630,"results":"492","hashOfConfig":"491"},{"size":200,"mtime":1769103053294,"results":"493","hashOfConfig":"491"},{"size":47,"mtime":1765885654431,"results":"494","hashOfConfig":"491"},{"size":585,"mtime":1768935766633,"results":"495","hashOfConfig":"496"},{"size":137,"mtime":1768485628958,"results":"497","hashOfConfig":"491"},{"size":100,"mtime":1768485628958,"results":"498","hashOfConfig":"491"},{"size":99,"mtime":1768485628958,"results":"499","hashOfConfig":"491"},{"size":188,"mtime":1768485628958,"results":"500","hashOfConfig":"491"},{"size":92,"mtime":1768485628958,"results":"501","hashOfConfig":"491"},{"size":127,"mtime":1768485628958,"results":"502","hashOfConfig":"491"},{"size":107,"mtime":1768485628958,"results":"503","hashOfConfig":"491"},{"size":75,"mtime":1768485628959,"results":"504","hashOfConfig":"491"},{"size":172,"mtime":1768485628958,"results":"505","hashOfConfig":"491"},{"size":127,"mtime":1768485628959,"results":"506","hashOfConfig":"491"},{"size":72,"mtime":1768485628959,"results":"507","hashOfConfig":"491"},{"size":428,"mtime":1768485628959,"results":"508","hashOfConfig":"491"},{"size":127,"mtime":1768485628959,"results":"509","hashOfConfig":"491"},{"size":240,"mtime":1768485628959,"results":"510","hashOfConfig":"491"},{"size":178,"mtime":1768485628959,"results":"511","hashOfConfig":"491"},{"size":153,"mtime":1768485628959,"results":"512","hashOfConfig":"491"},{"size":127,"mtime":1768485628959,"results":"513","hashOfConfig":"491"},{"size":190,"mtime":1768485628959,"results":"514","hashOfConfig":"491"},{"size":635,"mtime":1768485628959,"results":"515","hashOfConfig":"491"},{"size":548,"mtime":1768485628959,"results":"516","hashOfConfig":"491"},{"size":127,"mtime":1768485628959,"results":"517","hashOfConfig":"491"},{"size":72,"mtime":1768485628959,"results":"518","hashOfConfig":"491"},{"size":141,"mtime":1768485628959,"results":"519","hashOfConfig":"491"},{"size":127,"mtime":1768485628959,"results":"520","hashOfConfig":"491"},{"size":72,"mtime":1768485628959,"results":"521","hashOfConfig":"491"},{"size":157,"mtime":1768870633712,"results":"522","hashOfConfig":"491"},{"size":127,"mtime":1768485628959,"results":"523","hashOfConfig":"491"},{"size":72,"mtime":1768485628959,"results":"524","hashOfConfig":"491"},{"size":155,"mtime":1768485628959,"results":"525","hashOfConfig":"491"},{"size":127,"mtime":1768485628959,"results":"526","hashOfConfig":"491"},{"size":72,"mtime":1768485628959,"results":"527","hashOfConfig":"491"},{"size":90,"mtime":1768485628959,"results":"528","hashOfConfig":"491"},{"size":127,"mtime":1768485628959,"results":"529","hashOfConfig":"491"},{"size":72,"mtime":1768485628959,"results":"530","hashOfConfig":"491"},{"size":146,"mtime":1768485628959,"results":"531","hashOfConfig":"491"},{"size":127,"mtime":1768485628959,"results":"532","hashOfConfig":"491"},{"size":140,"mtime":1768485628959,"results":"533","hashOfConfig":"491"},{"size":239,"mtime":1768485628960,"results":"534","hashOfConfig":"491"},{"size":190,"mtime":1768485628960,"results":"535","hashOfConfig":"491"},{"size":127,"mtime":1768485628960,"results":"536","hashOfConfig":"491"},{"size":92,"mtime":1768485628960,"results":"537","hashOfConfig":"491"},{"size":171,"mtime":1768485628960,"results":"538","hashOfConfig":"491"},{"size":119,"mtime":1768485628960,"results":"539","hashOfConfig":"491"},{"size":127,"mtime":1768485628960,"results":"540","hashOfConfig":"491"},{"size":72,"mtime":1768485628960,"results":"541","hashOfConfig":"491"},{"size":83,"mtime":1768485628960,"results":"542","hashOfConfig":"491"},{"size":127,"mtime":1768485628960,"results":"543","hashOfConfig":"491"},{"size":72,"mtime":1768485628960,"results":"544","hashOfConfig":"491"},{"size":188,"mtime":1768485628960,"results":"545","hashOfConfig":"491"},{"size":127,"mtime":1768485628960,"results":"546","hashOfConfig":"491"},{"size":92,"mtime":1768485628960,"results":"547","hashOfConfig":"491"},{"size":269,"mtime":1768485628960,"results":"548","hashOfConfig":"491"},{"size":96,"mtime":1768485628960,"results":"549","hashOfConfig":"491"},{"size":127,"mtime":1768485628960,"results":"550","hashOfConfig":"491"},{"size":100,"mtime":1768485628960,"results":"551","hashOfConfig":"491"},{"size":131,"mtime":1768485628960,"results":"552","hashOfConfig":"491"},{"size":533,"mtime":1768485628960,"results":"553","hashOfConfig":"491"},{"size":127,"mtime":1768485628960,"results":"554","hashOfConfig":"491"},{"size":132,"mtime":1768485628960,"results":"555","hashOfConfig":"491"},{"size":218,"mtime":1768485628960,"results":"556","hashOfConfig":"491"},{"size":127,"mtime":1768485628960,"results":"557","hashOfConfig":"491"},{"size":315,"mtime":1768485628960,"results":"558","hashOfConfig":"491"},{"size":89,"mtime":1768485628960,"results":"559","hashOfConfig":"491"},{"size":127,"mtime":1768485628961,"results":"560","hashOfConfig":"491"},{"size":127,"mtime":1768485628961,"results":"561","hashOfConfig":"491"},{"size":621,"mtime":1768485628961,"results":"562","hashOfConfig":"491"},{"size":92,"mtime":1768485628961,"results":"563","hashOfConfig":"491"},{"size":130,"mtime":1768485628961,"results":"564","hashOfConfig":"491"},{"size":244,"mtime":1768485628961,"results":"565","hashOfConfig":"491"},{"size":127,"mtime":1768485628961,"results":"566","hashOfConfig":"491"},{"size":440,"mtime":1768485628961,"results":"567","hashOfConfig":"496"},{"size":198,"mtime":1768935766633,"results":"568","hashOfConfig":"491"},{"size":247,"mtime":1768935766633,"results":"569","hashOfConfig":"491"},{"size":4359,"mtime":1768935766633,"results":"570","hashOfConfig":"491"},{"size":4641,"mtime":1768935766634,"results":"571","hashOfConfig":"491"},{"size":2850,"mtime":1768935766634,"results":"572","hashOfConfig":"491"},{"size":2258,"mtime":1768935766634,"results":"573","hashOfConfig":"491"},{"size":1889,"mtime":1768935766634,"results":"574","hashOfConfig":"491"},{"size":2353,"mtime":1768935766634,"results":"575","hashOfConfig":"491"},{"size":567,"mtime":1768935766634,"results":"576","hashOfConfig":"491"},{"size":748,"mtime":1768485628961,"results":"577","hashOfConfig":"491"},{"size":570,"mtime":1768485628961,"results":"578","hashOfConfig":"491"},{"size":234,"mtime":1768485628961,"results":"579","hashOfConfig":"491"},{"size":202,"mtime":1768485628961,"results":"580","hashOfConfig":"491"},{"size":150,"mtime":1768485628962,"results":"581","hashOfConfig":"491"},{"size":1223,"mtime":1768485628962,"results":"582","hashOfConfig":"491"},{"size":329,"mtime":1768485628962,"results":"583","hashOfConfig":"496"},{"size":265,"mtime":1768485628962,"results":"584","hashOfConfig":"491"},{"size":177,"mtime":1768485628962,"results":"585","hashOfConfig":"491"},{"size":1062,"mtime":1768485628962,"results":"586","hashOfConfig":"491"},{"size":294,"mtime":1768485628962,"results":"587","hashOfConfig":"496"},{"size":283,"mtime":1768485628962,"results":"588","hashOfConfig":"491"},{"size":154,"mtime":1768485628962,"results":"589","hashOfConfig":"491"},{"size":1192,"mtime":1768485628962,"results":"590","hashOfConfig":"491"},{"size":452,"mtime":1768485628962,"results":"591","hashOfConfig":"496"},{"size":706,"mtime":1768485628962,"results":"592","hashOfConfig":"491"},{"size":439,"mtime":1768485628962,"results":"593","hashOfConfig":"491"},{"size":364,"mtime":1768485628962,"results":"594","hashOfConfig":"491"},{"size":323,"mtime":1768485628962,"results":"595","hashOfConfig":"496"},{"size":180,"mtime":1768485628962,"results":"596","hashOfConfig":"491"},{"size":390,"mtime":1768485628962,"results":"597","hashOfConfig":"491"},{"size":1475,"mtime":1768485628962,"results":"598","hashOfConfig":"491"},{"size":511,"mtime":1768485628962,"results":"599","hashOfConfig":"491"},{"size":266,"mtime":1768485628962,"results":"600","hashOfConfig":"491"},{"size":553,"mtime":1768485628962,"results":"601","hashOfConfig":"496"},{"size":422,"mtime":1768485628962,"results":"602","hashOfConfig":"491"},{"size":1784,"mtime":1768485628962,"results":"603","hashOfConfig":"491"},{"size":898,"mtime":1768485628962,"results":"604","hashOfConfig":"491"},{"size":150,"mtime":1768485628962,"results":"605","hashOfConfig":"491"},{"size":773,"mtime":1768485628962,"results":"606","hashOfConfig":"496"},{"size":589,"mtime":1768935766634,"results":"607","hashOfConfig":"491"},{"size":211,"mtime":1768935766634,"results":"608","hashOfConfig":"491"},{"size":155,"mtime":1768485628962,"results":"609","hashOfConfig":"491"},{"size":683,"mtime":1768485628962,"results":"610","hashOfConfig":"491"},{"size":127,"mtime":1768485628962,"results":"611","hashOfConfig":"491"},{"size":20,"mtime":1768485628962,"results":"612","hashOfConfig":"491"},{"size":20,"mtime":1768485628963,"results":"613","hashOfConfig":"496"},{"size":630,"mtime":1768935766634,"results":"614","hashOfConfig":"491"},{"size":73,"mtime":1768935766634,"results":"615","hashOfConfig":"496"},{"size":98,"mtime":1769017480816,"results":"616","hashOfConfig":"491"},{"size":106,"mtime":1769017481745,"results":"617","hashOfConfig":"491"},{"size":130,"mtime":1768485628963,"results":"618","hashOfConfig":"491"},{"size":3765,"mtime":1768485628963,"results":"619","hashOfConfig":"491"},{"size":554,"mtime":1768485628963,"results":"620","hashOfConfig":"491"},{"size":3432,"mtime":1768485628963,"results":"621","hashOfConfig":"491"},{"size":2654,"mtime":1768485628963,"results":"622","hashOfConfig":"491"},{"size":592,"mtime":1768485628964,"results":"623","hashOfConfig":"491"},{"size":3107,"mtime":1769018727869,"results":"624","hashOfConfig":"491"},{"size":3313,"mtime":1769020222179,"results":"625","hashOfConfig":"491"},{"size":2914,"mtime":1768485628964,"results":"626","hashOfConfig":"491"},{"size":7864,"mtime":1768935766636,"results":"627","hashOfConfig":"491"},{"size":1007,"mtime":1768485628964,"results":"628","hashOfConfig":"491"},{"size":2685,"mtime":1769112665825,"results":"629","hashOfConfig":"491"},{"size":3323,"mtime":1768935766636,"results":"630","hashOfConfig":"491"},{"size":375,"mtime":1768485628964,"results":"631","hashOfConfig":"491"},{"size":939,"mtime":1768485628964,"results":"632","hashOfConfig":"491"},{"size":2580,"mtime":1768485628964,"results":"633","hashOfConfig":"491"},{"size":2833,"mtime":1769111694906,"results":"634","hashOfConfig":"491"},{"size":500,"mtime":1768485628964,"results":"635","hashOfConfig":"491"},{"size":494,"mtime":1768935766636,"results":"636","hashOfConfig":"491"},{"size":2730,"mtime":1769018634698,"results":"637","hashOfConfig":"491"},{"size":2885,"mtime":1768485628964,"results":"638","hashOfConfig":"491"},{"size":2044,"mtime":1768485628964,"results":"639","hashOfConfig":"491"},{"size":481,"mtime":1768935766636,"results":"640","hashOfConfig":"491"},{"size":3117,"mtime":1768935766636,"results":"641","hashOfConfig":"491"},{"size":3140,"mtime":1768485628964,"results":"642","hashOfConfig":"491"},{"size":865,"mtime":1768485628964,"results":"643","hashOfConfig":"491"},{"size":2133,"mtime":1768485628964,"results":"644","hashOfConfig":"491"},{"size":9200,"mtime":1768868651078,"results":"645","hashOfConfig":"491"},{"size":1242,"mtime":1768485628964,"results":"646","hashOfConfig":"491"},{"size":1322,"mtime":1768485628964,"results":"647","hashOfConfig":"491"},{"size":1146,"mtime":1768485628964,"results":"648","hashOfConfig":"491"},{"size":885,"mtime":1769020222179,"results":"649","hashOfConfig":"491"},{"size":565,"mtime":1768485628964,"results":"650","hashOfConfig":"491"},{"size":359,"mtime":1768485628964,"results":"651","hashOfConfig":"491"},{"size":5808,"mtime":1768935766636,"results":"652","hashOfConfig":"491"},{"size":2048,"mtime":1768485628964,"results":"653","hashOfConfig":"491"},{"size":879,"mtime":1768485628964,"results":"654","hashOfConfig":"491"},{"size":3501,"mtime":1768485628964,"results":"655","hashOfConfig":"491"},{"size":309,"mtime":1768485628964,"results":"656","hashOfConfig":"491"},{"size":2793,"mtime":1768485628964,"results":"657","hashOfConfig":"491"},{"size":1492,"mtime":1768485628964,"results":"658","hashOfConfig":"491"},{"size":1436,"mtime":1768485628964,"results":"659","hashOfConfig":"491"},{"size":613,"mtime":1768935766636,"results":"660","hashOfConfig":"491"},{"size":3531,"mtime":1769111910945,"results":"661","hashOfConfig":"491"},{"size":7854,"mtime":1769020222179,"results":"662","hashOfConfig":"491"},{"size":3580,"mtime":1769018634698,"results":"663","hashOfConfig":"491"},{"size":14692,"mtime":1769018634698,"results":"664","hashOfConfig":"491"},{"size":4130,"mtime":1768935766637,"results":"665","hashOfConfig":"491"},{"size":5798,"mtime":1768485628964,"results":"666","hashOfConfig":"491"},{"size":1469,"mtime":1769018634698,"results":"667","hashOfConfig":"491"},{"size":561,"mtime":1768485628964,"results":"668","hashOfConfig":"491"},{"size":1617,"mtime":1768485628964,"results":"669","hashOfConfig":"491"},{"size":2090,"mtime":1768485628964,"results":"670","hashOfConfig":"491"},{"size":508,"mtime":1768485628964,"results":"671","hashOfConfig":"491"},{"size":306,"mtime":1768485628964,"results":"672","hashOfConfig":"491"},{"size":862,"mtime":1768485628964,"results":"673","hashOfConfig":"491"},{"size":1561,"mtime":1768485628964,"results":"674","hashOfConfig":"491"},{"size":288,"mtime":1768485628964,"results":"675","hashOfConfig":"491"},{"size":573,"mtime":1768485628964,"results":"676","hashOfConfig":"491"},{"size":1743,"mtime":1769018634698,"results":"677","hashOfConfig":"491"},{"size":6134,"mtime":1768485628965,"results":"678","hashOfConfig":"491"},{"size":1877,"mtime":1768485628965,"results":"679","hashOfConfig":"491"},{"size":2489,"mtime":1768485628965,"results":"680","hashOfConfig":"491"},{"size":286,"mtime":1768485628965,"results":"681","hashOfConfig":"491"},{"size":739,"mtime":1768485628965,"results":"682","hashOfConfig":"491"},{"size":674,"mtime":1768485628965,"results":"683","hashOfConfig":"491"},{"size":1613,"mtime":1768485628965,"results":"684","hashOfConfig":"491"},{"size":1251,"mtime":1768485628965,"results":"685","hashOfConfig":"491"},{"size":1747,"mtime":1768485628965,"results":"686","hashOfConfig":"491"},{"size":5347,"mtime":1768485628965,"results":"687","hashOfConfig":"491"},{"size":2152,"mtime":1768485628965,"results":"688","hashOfConfig":"491"},{"size":2094,"mtime":1768485628965,"results":"689","hashOfConfig":"491"},{"size":126,"mtime":1768485628965,"results":"690","hashOfConfig":"491"},{"size":2237,"mtime":1768485628965,"results":"691","hashOfConfig":"491"},{"size":1368,"mtime":1768485628965,"results":"692","hashOfConfig":"491"},{"size":250,"mtime":1768485628965,"results":"693","hashOfConfig":"491"},{"size":633,"mtime":1768485628965,"results":"694","hashOfConfig":"491"},{"size":4444,"mtime":1768485628965,"results":"695","hashOfConfig":"491"},{"size":7333,"mtime":1768485628966,"results":"696","hashOfConfig":"491"},{"size":5919,"mtime":1768485628966,"results":"697","hashOfConfig":"491"},{"size":1061,"mtime":1768485628966,"results":"698","hashOfConfig":"491"},{"size":1270,"mtime":1768485628966,"results":"699","hashOfConfig":"491"},{"size":2311,"mtime":1768935766637,"results":"700","hashOfConfig":"491"},{"size":12420,"mtime":1768485628966,"results":"701","hashOfConfig":"491"},{"size":3209,"mtime":1768485628966,"results":"702","hashOfConfig":"491"},{"size":492,"mtime":1768485628966,"results":"703","hashOfConfig":"491"},{"size":742,"mtime":1768485628966,"results":"704","hashOfConfig":"491"},{"size":373,"mtime":1768485628966,"results":"705","hashOfConfig":"491"},{"size":179,"mtime":1768485628966,"results":"706","hashOfConfig":"491"},{"size":2341,"mtime":1769020222179,"results":"707","hashOfConfig":"491"},{"size":713,"mtime":1768485628966,"results":"708","hashOfConfig":"491"},{"size":947,"mtime":1768485628966,"results":"709","hashOfConfig":"491"},{"size":3441,"mtime":1768485628967,"results":"710","hashOfConfig":"491"},{"size":1434,"mtime":1768485628967,"results":"711","hashOfConfig":"491"},{"size":756,"mtime":1768485628967,"results":"712","hashOfConfig":"491"},{"size":510,"mtime":1768485628967,"results":"713","hashOfConfig":"491"},{"size":368,"mtime":1768485628967,"results":"714","hashOfConfig":"491"},{"size":950,"mtime":1768485628967,"results":"715","hashOfConfig":"491"},{"size":493,"mtime":1768935766637,"results":"716","hashOfConfig":"491"},{"size":5386,"mtime":1768485628967,"results":"717","hashOfConfig":"491"},{"size":2894,"mtime":1768485628967,"results":"718","hashOfConfig":"491"},{"size":547,"mtime":1768485628967,"results":"719","hashOfConfig":"491"},{"size":4383,"mtime":1768485628967,"results":"720","hashOfConfig":"491"},{"size":1473,"mtime":1768935766637,"results":"721","hashOfConfig":"491"},{"size":734,"mtime":1768485628967,"results":"722","hashOfConfig":"491"},{"size":61,"mtime":1765879310418,"results":"723","hashOfConfig":"491"},{"size":756,"mtime":1768485628967,"results":"724","hashOfConfig":"491"},{"size":1737,"mtime":1768485628967,"results":"725","hashOfConfig":"491"},{"size":1762,"mtime":1768485628967,"results":"726","hashOfConfig":"491"},{"size":249,"mtime":1762360155096,"results":"727","hashOfConfig":"491"},{"size":4758,"mtime":1768485628967,"results":"728","hashOfConfig":"491"},{"size":404,"mtime":1768485628967,"results":"729","hashOfConfig":"491"},{"size":1414,"mtime":1769020222179,"results":"730","hashOfConfig":"491"},{"size":250,"mtime":1768485628967,"results":"731","hashOfConfig":"491"},{"size":2618,"mtime":1768485628967,"results":"732","hashOfConfig":"491"},{"size":1299,"mtime":1768485628967,"results":"733","hashOfConfig":"491"},{"size":4485,"mtime":1768485628967,"results":"734","hashOfConfig":"491"},{"size":3179,"mtime":1768935766637,"results":"735","hashOfConfig":"491"},{"size":3116,"mtime":1769020222179,"results":"736","hashOfConfig":"491"},{"size":969,"mtime":1769020222179,"results":"737","hashOfConfig":"491"},{"size":1997,"mtime":1769020222180,"results":"738","hashOfConfig":"491"},{"size":3442,"mtime":1768485628967,"results":"739","hashOfConfig":"491"},{"size":879,"mtime":1767619337864,"results":"740","hashOfConfig":"496"},{"size":4704,"mtime":1768485628967,"results":"741","hashOfConfig":"491"},{"size":2733,"mtime":1768485628967,"results":"742","hashOfConfig":"491"},{"size":922,"mtime":1768485628968,"results":"743","hashOfConfig":"491"},{"size":10545,"mtime":1768485628968,"results":"744","hashOfConfig":"491"},{"size":440,"mtime":1765879310419,"results":"745","hashOfConfig":"491"},{"size":9729,"mtime":1768485628968,"results":"746","hashOfConfig":"491"},{"size":34941,"mtime":1767619337864,"results":"747","hashOfConfig":"491"},{"size":2078,"mtime":1768485628968,"results":"748","hashOfConfig":"491"},{"size":952,"mtime":1769020222180,"results":"749","hashOfConfig":"491"},{"size":1261,"mtime":1769020222180,"results":"750","hashOfConfig":"491"},{"size":5281,"mtime":1768485628968,"results":"751","hashOfConfig":"491"},{"size":713,"mtime":1768485628968,"results":"752","hashOfConfig":"491"},{"size":246,"mtime":1768485628968,"results":"753","hashOfConfig":"491"},{"size":1626,"mtime":1768485628968,"results":"754","hashOfConfig":"491"},{"size":2382,"mtime":1768485628968,"results":"755","hashOfConfig":"491"},{"size":249,"mtime":1768485628968,"results":"756","hashOfConfig":"491"},{"size":205,"mtime":1768485628968,"results":"757","hashOfConfig":"491"},{"size":227,"mtime":1768485628968,"results":"758","hashOfConfig":"491"},{"size":700,"mtime":1768485628968,"results":"759","hashOfConfig":"491"},{"size":6279,"mtime":1768485628968,"results":"760","hashOfConfig":"491"},{"size":138,"mtime":1768485628968,"results":"761","hashOfConfig":"491"},{"size":224,"mtime":1768485628968,"results":"762","hashOfConfig":"491"},{"size":5043,"mtime":1768485628968,"results":"763","hashOfConfig":"491"},{"size":899,"mtime":1768935766637,"results":"764","hashOfConfig":"491"},{"size":1071,"mtime":1768935766637,"results":"765","hashOfConfig":"491"},{"size":2082,"mtime":1768485628968,"results":"766","hashOfConfig":"491"},{"size":3999,"mtime":1768485628968,"results":"767","hashOfConfig":"491"},{"size":1103,"mtime":1768485628968,"results":"768","hashOfConfig":"491"},{"size":560,"mtime":1768485628968,"results":"769","hashOfConfig":"491"},{"size":1517,"mtime":1769020222180,"results":"770","hashOfConfig":"491"},{"size":599,"mtime":1769020222180,"results":"771","hashOfConfig":"491"},{"size":1270,"mtime":1769020222180,"results":"772","hashOfConfig":"491"},{"size":240,"mtime":1768485628968,"results":"773","hashOfConfig":"491"},{"size":237,"mtime":1768485628968,"results":"774","hashOfConfig":"491"},{"size":565,"mtime":1768485628968,"results":"775","hashOfConfig":"491"},{"size":155,"mtime":1768485628969,"results":"776","hashOfConfig":"491"},{"size":373,"mtime":1768485628969,"results":"777","hashOfConfig":"491"},{"size":1650,"mtime":1768485628969,"results":"778","hashOfConfig":"491"},{"size":2883,"mtime":1768935766637,"results":"779","hashOfConfig":"491"},{"size":702,"mtime":1768485628969,"results":"780","hashOfConfig":"491"},{"size":1121,"mtime":1768935766638,"results":"781","hashOfConfig":"491"},{"size":1127,"mtime":1768935766638,"results":"782","hashOfConfig":"491"},{"size":4585,"mtime":1768485628969,"results":"783","hashOfConfig":"491"},{"size":14440,"mtime":1769100988355,"results":"784","hashOfConfig":"491"},{"size":473,"mtime":1768485628969,"results":"785","hashOfConfig":"491"},{"size":3264,"mtime":1768485628969,"results":"786","hashOfConfig":"491"},{"size":2037,"mtime":1768485628969,"results":"787","hashOfConfig":"491"},{"size":171,"mtime":1768485628969,"results":"788","hashOfConfig":"491"},{"size":488,"mtime":1768485628969,"results":"789","hashOfConfig":"491"},{"size":6267,"mtime":1768935766638,"results":"790","hashOfConfig":"491"},{"size":5567,"mtime":1768485628969,"results":"791","hashOfConfig":"491"},{"size":3350,"mtime":1768485628969,"results":"792","hashOfConfig":"491"},{"size":110,"mtime":1768485628969,"results":"793","hashOfConfig":"491"},{"size":81,"mtime":1768485628969,"results":"794","hashOfConfig":"491"},{"size":218,"mtime":1768485628969,"results":"795","hashOfConfig":"491"},{"size":52,"mtime":1768485628969,"results":"796","hashOfConfig":"491"},{"size":54,"mtime":1768485628969,"results":"797","hashOfConfig":"491"},{"size":7922,"mtime":1768485628969,"results":"798","hashOfConfig":"491"},{"size":10407,"mtime":1768485628969,"results":"799","hashOfConfig":"491"},{"size":1098,"mtime":1768485628969,"results":"800","hashOfConfig":"491"},{"size":555,"mtime":1768485628969,"results":"801","hashOfConfig":"491"},{"size":0,"mtime":1765879310420,"results":"802","hashOfConfig":"491"},{"size":5313,"mtime":1768935766638,"results":"803","hashOfConfig":"491"},{"size":442,"mtime":1768485628969,"results":"804","hashOfConfig":"491"},{"size":2114,"mtime":1768485628969,"results":"805","hashOfConfig":"491"},{"size":337,"mtime":1768485628969,"results":"806","hashOfConfig":"491"},{"size":125,"mtime":1768485628969,"results":"807","hashOfConfig":"491"},{"size":172,"mtime":1768485628969,"results":"808","hashOfConfig":"491"},{"size":2804,"mtime":1768485628969,"results":"809","hashOfConfig":"491"},{"size":860,"mtime":1768485628969,"results":"810","hashOfConfig":"491"},{"size":3302,"mtime":1768485628969,"results":"811","hashOfConfig":"491"},{"size":930,"mtime":1768485628969,"results":"812","hashOfConfig":"491"},{"size":214,"mtime":1768485628969,"results":"813","hashOfConfig":"491"},{"size":5542,"mtime":1768485628969,"results":"814","hashOfConfig":"491"},{"size":1690,"mtime":1768485628969,"results":"815","hashOfConfig":"491"},{"size":2237,"mtime":1768485628970,"results":"816","hashOfConfig":"491"},{"size":2613,"mtime":1768485628970,"results":"817","hashOfConfig":"491"},{"size":410,"mtime":1768485628970,"results":"818","hashOfConfig":"491"},{"size":2446,"mtime":1768485628970,"results":"819","hashOfConfig":"491"},{"size":404,"mtime":1769020222180,"results":"820","hashOfConfig":"496"},{"size":9214,"mtime":1768935766638,"results":"821","hashOfConfig":"496"},{"size":179,"mtime":1768485628970,"results":"822","hashOfConfig":"496"},{"size":846,"mtime":1768485628970,"results":"823","hashOfConfig":"491"},{"size":1522,"mtime":1768485628970,"results":"824","hashOfConfig":"491"},{"size":65,"mtime":1768485628970,"results":"825","hashOfConfig":"491"},{"size":52,"mtime":1768485628970,"results":"826","hashOfConfig":"491"},{"size":58,"mtime":1768485628970,"results":"827","hashOfConfig":"491"},{"size":212,"mtime":1768485628970,"results":"828","hashOfConfig":"491"},{"size":197,"mtime":1768485628971,"results":"829","hashOfConfig":"491"},{"size":463,"mtime":1768485628971,"results":"830","hashOfConfig":"491"},{"size":294,"mtime":1769020222180,"results":"831","hashOfConfig":"491"},{"size":126,"mtime":1768485628971,"results":"832","hashOfConfig":"491"},{"size":49,"mtime":1768485628971,"results":"833","hashOfConfig":"491"},{"size":477,"mtime":1768485628971,"results":"834","hashOfConfig":"491"},{"size":305,"mtime":1768485628971,"results":"835","hashOfConfig":"491"},{"size":182,"mtime":1768485628971,"results":"836","hashOfConfig":"491"},{"size":591,"mtime":1768485628971,"results":"837","hashOfConfig":"491"},{"size":163,"mtime":1768485628971,"results":"838","hashOfConfig":"491"},{"size":433,"mtime":1768485628971,"results":"839","hashOfConfig":"491"},{"size":156,"mtime":1768485628971,"results":"840","hashOfConfig":"491"},{"size":259,"mtime":1768485628971,"results":"841","hashOfConfig":"491"},{"size":563,"mtime":1768485628971,"results":"842","hashOfConfig":"491"},{"size":5096,"mtime":1768485628971,"results":"843","hashOfConfig":"491"},{"size":3415,"mtime":1768485628971,"results":"844","hashOfConfig":"491"},{"size":679,"mtime":1768485628971,"results":"845","hashOfConfig":"491"},{"size":643,"mtime":1769018634698,"results":"846","hashOfConfig":"491"},{"size":10091,"mtime":1769018634698,"results":"847","hashOfConfig":"491"},{"size":3511,"mtime":1768485628971,"results":"848","hashOfConfig":"491"},{"size":2006,"mtime":1766053453788,"results":"849","hashOfConfig":"491"},{"size":3555,"mtime":1768935766638,"results":"850","hashOfConfig":"491"},{"size":90,"mtime":1768485628971,"results":"851","hashOfConfig":"491"},{"size":500,"mtime":1769020222180,"results":"852","hashOfConfig":"491"},{"size":846,"mtime":1768935766638,"results":"853","hashOfConfig":"491"},{"size":1928,"mtime":1768485628971,"results":"854","hashOfConfig":"491"},{"size":1276,"mtime":1769018634698,"results":"855","hashOfConfig":"491"},{"size":650,"mtime":1769018634698,"results":"856","hashOfConfig":"491"},{"size":265,"mtime":1768485628971,"results":"857","hashOfConfig":"491"},{"size":2256,"mtime":1768485628971,"results":"858","hashOfConfig":"491"},{"size":38164,"mtime":1765879310420,"results":"859","hashOfConfig":"491"},{"size":1031,"mtime":1768485628971,"results":"860","hashOfConfig":"491"},{"size":391,"mtime":1768485628971,"results":"861","hashOfConfig":"491"},{"size":371,"mtime":1768485628971,"results":"862","hashOfConfig":"491"},{"size":2195,"mtime":1768485628971,"results":"863","hashOfConfig":"491"},{"size":1003,"mtime":1768485628971,"results":"864","hashOfConfig":"491"},{"size":236,"mtime":1768485628971,"results":"865","hashOfConfig":"491"},{"size":1121,"mtime":1768485628971,"results":"866","hashOfConfig":"491"},{"size":111,"mtime":1768485628971,"results":"867","hashOfConfig":"491"},{"size":1245,"mtime":1768485628971,"results":"868","hashOfConfig":"491"},{"size":702,"mtime":1762360155102,"results":"869","hashOfConfig":"491"},{"size":43,"mtime":1768485628971,"results":"870","hashOfConfig":"491"},{"size":4022,"mtime":1768485628971,"results":"871","hashOfConfig":"491"},{"size":1553,"mtime":1768485628971,"results":"872","hashOfConfig":"491"},{"size":2138,"mtime":1768485628971,"results":"873","hashOfConfig":"491"},{"size":1911,"mtime":1768485628971,"results":"874","hashOfConfig":"491"},{"size":1108,"mtime":1768935766638,"results":"875","hashOfConfig":"491"},{"size":691,"mtime":1768485628971,"results":"876","hashOfConfig":"491"},{"size":128,"mtime":1768485628971,"results":"877","hashOfConfig":"491"},{"size":2895,"mtime":1768935766638,"results":"878","hashOfConfig":"491"},{"size":288,"mtime":1768485628971,"results":"879","hashOfConfig":"491"},{"size":63,"mtime":1768485628971,"results":"880","hashOfConfig":"491"},{"size":4064,"mtime":1768935766639,"results":"881","hashOfConfig":"491"},{"size":23,"mtime":1768485628971,"results":"882","hashOfConfig":"496"},{"size":23,"mtime":1768485628972,"results":"883","hashOfConfig":"491"},{"size":120,"mtime":1768485628972,"results":"884","hashOfConfig":"491"},{"size":240,"mtime":1768485628972,"results":"885","hashOfConfig":"491"},{"size":299,"mtime":1768485628972,"results":"886","hashOfConfig":"491"},{"size":59,"mtime":1768485628972,"results":"887","hashOfConfig":"491"},{"size":131,"mtime":1768485628972,"results":"888","hashOfConfig":"491"},{"size":120,"mtime":1768485628972,"results":"889","hashOfConfig":"491"},{"size":234,"mtime":1768485628972,"results":"890","hashOfConfig":"491"},{"size":542,"mtime":1768485628972,"results":"891","hashOfConfig":"491"},{"size":210,"mtime":1768485628972,"results":"892","hashOfConfig":"491"},{"size":151,"mtime":1768485628972,"results":"893","hashOfConfig":"491"},{"size":184,"mtime":1768485628972,"results":"894","hashOfConfig":"491"},{"size":498,"mtime":1768485628972,"results":"895","hashOfConfig":"491"},{"size":49,"mtime":1768485628972,"results":"896","hashOfConfig":"491"},{"size":163,"mtime":1768485628972,"results":"897","hashOfConfig":"491"},{"size":82,"mtime":1768485628972,"results":"898","hashOfConfig":"491"},{"size":875,"mtime":1768935766639,"results":"899","hashOfConfig":"491"},{"size":32,"mtime":1768485628972,"results":"900","hashOfConfig":"491"},{"size":28,"mtime":1768485628972,"results":"901","hashOfConfig":"491"},{"size":195,"mtime":1768485628972,"results":"902","hashOfConfig":"491"},{"size":434,"mtime":1768485628972,"results":"903","hashOfConfig":"491"},{"size":390,"mtime":1768485628972,"results":"904","hashOfConfig":"491"},{"size":48,"mtime":1768485628972,"results":"905","hashOfConfig":"491"},{"size":137,"mtime":1768485628972,"results":"906","hashOfConfig":"491"},{"size":796,"mtime":1768485628972,"results":"907","hashOfConfig":"491"},{"size":683,"mtime":1768485628972,"results":"908","hashOfConfig":"491"},{"size":141,"mtime":1768485628972,"results":"909","hashOfConfig":"491"},{"size":238,"mtime":1768485628972,"results":"910","hashOfConfig":"491"},{"size":363,"mtime":1768485628972,"results":"911","hashOfConfig":"491"},{"size":32,"mtime":1768485628972,"results":"912","hashOfConfig":"491"},{"size":33,"mtime":1768485628972,"results":"913","hashOfConfig":"491"},{"size":114,"mtime":1768485628972,"results":"914","hashOfConfig":"491"},{"size":809,"mtime":1768485628972,"results":"915","hashOfConfig":"491"},{"size":335,"mtime":1768485628972,"results":"916","hashOfConfig":"491"},{"size":975,"mtime":1768485628972,"results":"917","hashOfConfig":"491"},{"size":273,"mtime":1768485628972,"results":"918","hashOfConfig":"491"},{"size":52,"mtime":1768485628972,"results":"919","hashOfConfig":"491"},{"size":82,"mtime":1768485628972,"results":"920","hashOfConfig":"491"},{"size":511,"mtime":1768485628972,"results":"921","hashOfConfig":"491"},{"size":1967,"mtime":1768485628972,"results":"922","hashOfConfig":"491"},{"size":447,"mtime":1768485628972,"results":"923","hashOfConfig":"491"},{"size":1208,"mtime":1768485628972,"results":"924","hashOfConfig":"491"},{"size":252,"mtime":1768485628972,"results":"925","hashOfConfig":"491"},{"size":138,"mtime":1768485628972,"results":"926","hashOfConfig":"491"},{"size":104,"mtime":1768485628972,"results":"927","hashOfConfig":"491"},{"size":350,"mtime":1768485628972,"results":"928","hashOfConfig":"491"},{"size":333,"mtime":1768485628972,"results":"929","hashOfConfig":"491"},{"size":334,"mtime":1768485628972,"results":"930","hashOfConfig":"491"},{"size":382,"mtime":1768485628972,"results":"931","hashOfConfig":"491"},{"size":299,"mtime":1768485628972,"results":"932","hashOfConfig":"491"},{"size":276,"mtime":1768485628973,"results":"933","hashOfConfig":"491"},{"size":231,"mtime":1768485628973,"results":"934","hashOfConfig":"491"},{"size":452,"mtime":1768485628973,"results":"935","hashOfConfig":"491"},{"size":41,"mtime":1768485628973,"results":"936","hashOfConfig":"491"},{"size":39,"mtime":1768485628973,"results":"937","hashOfConfig":"491"},{"size":35,"mtime":1768485628973,"results":"938","hashOfConfig":"491"},{"size":45,"mtime":1762360155104,"results":"939","hashOfConfig":"491"},{"size":236,"mtime":1768485628971,"results":"940","hashOfConfig":"491"},{"size":130,"mtime":1769111988400,"results":"941","hashOfConfig":"491"},{"size":2897,"mtime":1768485628973,"results":"942","hashOfConfig":"491"},{"size":135,"mtime":1768928617550,"results":"943","hashOfConfig":"491"},{"size":81,"mtime":1768485628973,"results":"944","hashOfConfig":"491"},{"size":151,"mtime":1768485628973,"results":"945","hashOfConfig":"496"},{"size":3012,"mtime":1768485628973,"results":"946","hashOfConfig":"491"},{"size":3973,"mtime":1768485628973,"results":"947","hashOfConfig":"491"},{"size":911,"mtime":1768485628973,"results":"948","hashOfConfig":"491"},{"size":1584,"mtime":1768485628973,"results":"949","hashOfConfig":"491"},{"size":2452,"mtime":1768485628973,"results":"950","hashOfConfig":"491"},{"size":1024,"mtime":1768485628973,"results":"951","hashOfConfig":"491"},{"size":7298,"mtime":1768485628973,"results":"952","hashOfConfig":"491"},{"size":2424,"mtime":1768935766639,"results":"953","hashOfConfig":"491"},{"size":1427,"mtime":1768485628973,"results":"954","hashOfConfig":"491"},{"size":555,"mtime":1768485628973,"results":"955","hashOfConfig":"491"},{"size":483,"mtime":1768485628973,"results":"956","hashOfConfig":"491"},{"size":18122,"mtime":1768485628973,"results":"957","hashOfConfig":"491"},{"size":1207,"mtime":1768485628973,"results":"958","hashOfConfig":"491"},{"size":515,"mtime":1768485628973,"results":"959","hashOfConfig":"491"},{"size":23391,"mtime":1769112905095,"results":"960","hashOfConfig":"491"},{"size":1967,"mtime":1768485628973,"results":"961","hashOfConfig":"491"},{"size":2728,"mtime":1768485628973,"results":"962","hashOfConfig":"491"},{"size":1688,"mtime":1768485628973,"results":"963","hashOfConfig":"491"},{"size":317,"mtime":1768485628973,"results":"964","hashOfConfig":"491"},{"size":316,"mtime":1768485628973,"results":"965","hashOfConfig":"491"},{"filePath":"966","messages":"967","suppressedMessages":"968","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"17lpsoa",{"filePath":"969","messages":"970","suppressedMessages":"971","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"972","messages":"973","suppressedMessages":"974","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"975","messages":"976","suppressedMessages":"977","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"978","messages":"979","suppressedMessages":"980","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"981","messages":"982","suppressedMessages":"983","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"984","messages":"985","suppressedMessages":"986","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"987","messages":"988","suppressedMessages":"989","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"1l1toe8",{"filePath":"990","messages":"991","suppressedMessages":"992","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"993","messages":"994","suppressedMessages":"995","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"996","messages":"997","suppressedMessages":"998","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"999","messages":"1000","suppressedMessages":"1001","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"pc2r9k",{"filePath":"1002","messages":"1003","suppressedMessages":"1004","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1005","messages":"1006","suppressedMessages":"1007","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1008","messages":"1009","suppressedMessages":"1010","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1011","messages":"1012","suppressedMessages":"1013","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1014","messages":"1015","suppressedMessages":"1016","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1017","messages":"1018","suppressedMessages":"1019","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1020","messages":"1021","suppressedMessages":"1022","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1023","messages":"1024","suppressedMessages":"1025","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1026","messages":"1027","suppressedMessages":"1028","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1029","messages":"1030","suppressedMessages":"1031","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1032","messages":"1033","suppressedMessages":"1034","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1035","messages":"1036","suppressedMessages":"1037","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1038","messages":"1039","suppressedMessages":"1040","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1041","messages":"1042","suppressedMessages":"1043","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1044","messages":"1045","suppressedMessages":"1046","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1047","messages":"1048","suppressedMessages":"1049","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1050","messages":"1051","suppressedMessages":"1052","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1053","messages":"1054","suppressedMessages":"1055","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1056","messages":"1057","suppressedMessages":"1058","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1059","messages":"1060","suppressedMessages":"1061","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1062","messages":"1063","suppressedMessages":"1064","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1065","messages":"1066","suppressedMessages":"1067","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1068","messages":"1069","suppressedMessages":"1070","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1071","messages":"1072","suppressedMessages":"1073","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1074","messages":"1075","suppressedMessages":"1076","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1077","messages":"1078","suppressedMessages":"1079","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1080","messages":"1081","suppressedMessages":"1082","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1083","messages":"1084","suppressedMessages":"1085","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1086","messages":"1087","suppressedMessages":"1088","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1089","messages":"1090","suppressedMessages":"1091","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1092","messages":"1093","suppressedMessages":"1094","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1095","messages":"1096","suppressedMessages":"1097","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1098","messages":"1099","suppressedMessages":"1100","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1101","messages":"1102","suppressedMessages":"1103","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1104","messages":"1105","suppressedMessages":"1106","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1107","messages":"1108","suppressedMessages":"1109","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1110","messages":"1111","suppressedMessages":"1112","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1113","messages":"1114","suppressedMessages":"1115","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1116","messages":"1117","suppressedMessages":"1118","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1119","messages":"1120","suppressedMessages":"1121","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1122","messages":"1123","suppressedMessages":"1124","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1125","messages":"1126","suppressedMessages":"1127","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1128","messages":"1129","suppressedMessages":"1130","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1131","messages":"1132","suppressedMessages":"1133","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1134","messages":"1135","suppressedMessages":"1136","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1137","messages":"1138","suppressedMessages":"1139","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1140","messages":"1141","suppressedMessages":"1142","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1143","messages":"1144","suppressedMessages":"1145","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1146","messages":"1147","suppressedMessages":"1148","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1149","messages":"1150","suppressedMessages":"1151","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1152","messages":"1153","suppressedMessages":"1154","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1155","messages":"1156","suppressedMessages":"1157","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1158","messages":"1159","suppressedMessages":"1160","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1161","messages":"1162","suppressedMessages":"1163","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1164","messages":"1165","suppressedMessages":"1166","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1167","messages":"1168","suppressedMessages":"1169","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1170","messages":"1171","suppressedMessages":"1172","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1173","messages":"1174","suppressedMessages":"1175","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1176","messages":"1177","suppressedMessages":"1178","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1179","messages":"1180","suppressedMessages":"1181","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1182","messages":"1183","suppressedMessages":"1184","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1185","messages":"1186","suppressedMessages":"1187","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1188","messages":"1189","suppressedMessages":"1190","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1191","messages":"1192","suppressedMessages":"1193","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1194","messages":"1195","suppressedMessages":"1196","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1197","messages":"1198","suppressedMessages":"1199","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1200","messages":"1201","suppressedMessages":"1202","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1203","messages":"1204","suppressedMessages":"1205","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1206","messages":"1207","suppressedMessages":"1208","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1209","messages":"1210","suppressedMessages":"1211","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1212","messages":"1213","suppressedMessages":"1214","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1215","messages":"1216","suppressedMessages":"1217","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1218","messages":"1219","suppressedMessages":"1220","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1221","messages":"1222","suppressedMessages":"1223","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1224","messages":"1225","suppressedMessages":"1226","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1227","messages":"1228","suppressedMessages":"1229","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1230","messages":"1231","suppressedMessages":"1232","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1233","messages":"1234","suppressedMessages":"1235","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1236","messages":"1237","suppressedMessages":"1238","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1239","messages":"1240","suppressedMessages":"1241","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1242","messages":"1243","suppressedMessages":"1244","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1245","messages":"1246","suppressedMessages":"1247","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1248","messages":"1249","suppressedMessages":"1250","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1251","messages":"1252","suppressedMessages":"1253","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1254","messages":"1255","suppressedMessages":"1256","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1257","messages":"1258","suppressedMessages":"1259","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1260","messages":"1261","suppressedMessages":"1262","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1263","messages":"1264","suppressedMessages":"1265","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1266","messages":"1267","suppressedMessages":"1268","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1269","messages":"1270","suppressedMessages":"1271","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1272","messages":"1273","suppressedMessages":"1274","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1275","messages":"1276","suppressedMessages":"1277","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1278","messages":"1279","suppressedMessages":"1280","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1281","messages":"1282","suppressedMessages":"1283","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1284","messages":"1285","suppressedMessages":"1286","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1287","messages":"1288","suppressedMessages":"1289","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1290","messages":"1291","suppressedMessages":"1292","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1293","messages":"1294","suppressedMessages":"1295","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1296","messages":"1297","suppressedMessages":"1298","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1299","messages":"1300","suppressedMessages":"1301","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1302","messages":"1303","suppressedMessages":"1304","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1305","messages":"1306","suppressedMessages":"1307","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1308","messages":"1309","suppressedMessages":"1310","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1311","messages":"1312","suppressedMessages":"1313","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1314","messages":"1315","suppressedMessages":"1316","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1317","messages":"1318","suppressedMessages":"1319","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1320","messages":"1321","suppressedMessages":"1322","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1323","messages":"1324","suppressedMessages":"1325","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1326","messages":"1327","suppressedMessages":"1328","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1329","messages":"1330","suppressedMessages":"1331","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1332","messages":"1333","suppressedMessages":"1334","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1335","messages":"1336","suppressedMessages":"1337","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1338","messages":"1339","suppressedMessages":"1340","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1341","messages":"1342","suppressedMessages":"1343","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1344","messages":"1345","suppressedMessages":"1346","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1347","messages":"1348","suppressedMessages":"1349","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1350","messages":"1351","suppressedMessages":"1352","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1353","messages":"1354","suppressedMessages":"1355","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1356","messages":"1357","suppressedMessages":"1358","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1359","messages":"1360","suppressedMessages":"1361","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1362","messages":"1363","suppressedMessages":"1364","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1365","messages":"1366","suppressedMessages":"1367","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1368","messages":"1369","suppressedMessages":"1370","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1371","messages":"1372","suppressedMessages":"1373","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1374","messages":"1375","suppressedMessages":"1376","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1377","messages":"1378","suppressedMessages":"1379","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1380","messages":"1381","suppressedMessages":"1382","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1383","messages":"1384","suppressedMessages":"1385","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1386","messages":"1387","suppressedMessages":"1388","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1389","messages":"1390","suppressedMessages":"1391","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1392","messages":"1393","suppressedMessages":"1394","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1395","messages":"1396","suppressedMessages":"1397","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1398","messages":"1399","suppressedMessages":"1400","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1401","messages":"1402","suppressedMessages":"1403","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1404","messages":"1405","suppressedMessages":"1406","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1407","messages":"1408","suppressedMessages":"1409","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1410","messages":"1411","suppressedMessages":"1412","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1413","messages":"1414","suppressedMessages":"1415","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1416","messages":"1417","suppressedMessages":"1418","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1419","messages":"1420","suppressedMessages":"1421","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1422","messages":"1423","suppressedMessages":"1424","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1425","messages":"1426","suppressedMessages":"1427","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1428","messages":"1429","suppressedMessages":"1430","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1431","messages":"1432","suppressedMessages":"1433","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1434","messages":"1435","suppressedMessages":"1436","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1437","messages":"1438","suppressedMessages":"1439","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1440","messages":"1441","suppressedMessages":"1442","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1443","messages":"1444","suppressedMessages":"1445","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1446","messages":"1447","suppressedMessages":"1448","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1449","messages":"1450","suppressedMessages":"1451","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1452","messages":"1453","suppressedMessages":"1454","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1455","messages":"1456","suppressedMessages":"1457","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1458","messages":"1459","suppressedMessages":"1460","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1461","messages":"1462","suppressedMessages":"1463","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1464","messages":"1465","suppressedMessages":"1466","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1467","messages":"1468","suppressedMessages":"1469","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1470","messages":"1471","suppressedMessages":"1472","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1473","messages":"1474","suppressedMessages":"1475","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1476","messages":"1477","suppressedMessages":"1478","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1479","messages":"1480","suppressedMessages":"1481","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1482","messages":"1483","suppressedMessages":"1484","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1485","messages":"1486","suppressedMessages":"1487","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1488","messages":"1489","suppressedMessages":"1490","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1491","messages":"1492","suppressedMessages":"1493","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1494","messages":"1495","suppressedMessages":"1496","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1497","messages":"1498","suppressedMessages":"1499","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1500","messages":"1501","suppressedMessages":"1502","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1503","messages":"1504","suppressedMessages":"1505","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1506","messages":"1507","suppressedMessages":"1508","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1509","messages":"1510","suppressedMessages":"1511","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1512","messages":"1513","suppressedMessages":"1514","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1515","messages":"1516","suppressedMessages":"1517","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1518","messages":"1519","suppressedMessages":"1520","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1521","messages":"1522","suppressedMessages":"1523","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1524","messages":"1525","suppressedMessages":"1526","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1527","messages":"1528","suppressedMessages":"1529","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1530","messages":"1531","suppressedMessages":"1532","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1533","messages":"1534","suppressedMessages":"1535","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1536","messages":"1537","suppressedMessages":"1538","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1539","messages":"1540","suppressedMessages":"1541","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1542","messages":"1543","suppressedMessages":"1544","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1545","messages":"1546","suppressedMessages":"1547","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1548","messages":"1549","suppressedMessages":"1550","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1551","messages":"1552","suppressedMessages":"1553","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1554","messages":"1555","suppressedMessages":"1556","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1557","messages":"1558","suppressedMessages":"1559","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1560","messages":"1561","suppressedMessages":"1562","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1563","messages":"1564","suppressedMessages":"1565","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1566","messages":"1567","suppressedMessages":"1568","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1569","messages":"1570","suppressedMessages":"1571","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1572","messages":"1573","suppressedMessages":"1574","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1575","messages":"1576","suppressedMessages":"1577","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1578","messages":"1579","suppressedMessages":"1580","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1581","messages":"1582","suppressedMessages":"1583","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1584","messages":"1585","suppressedMessages":"1586","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1587","messages":"1588","suppressedMessages":"1589","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1590","messages":"1591","suppressedMessages":"1592","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1593","messages":"1594","suppressedMessages":"1595","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1596","messages":"1597","suppressedMessages":"1598","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1599","messages":"1600","suppressedMessages":"1601","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1602","messages":"1603","suppressedMessages":"1604","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1605","messages":"1606","suppressedMessages":"1607","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1608","messages":"1609","suppressedMessages":"1610","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1611","messages":"1612","suppressedMessages":"1613","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1614","messages":"1615","suppressedMessages":"1616","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1617","messages":"1618","suppressedMessages":"1619","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1620","messages":"1621","suppressedMessages":"1622","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1623","messages":"1624","suppressedMessages":"1625","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1626","messages":"1627","suppressedMessages":"1628","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1629","messages":"1630","suppressedMessages":"1631","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1632","messages":"1633","suppressedMessages":"1634","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1635","messages":"1636","suppressedMessages":"1637","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1638","messages":"1639","suppressedMessages":"1640","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1641","messages":"1642","suppressedMessages":"1643","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1644","messages":"1645","suppressedMessages":"1646","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1647","messages":"1648","suppressedMessages":"1649","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1650","messages":"1651","suppressedMessages":"1652","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1653","messages":"1654","suppressedMessages":"1655","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1656","messages":"1657","suppressedMessages":"1658","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1659","messages":"1660","suppressedMessages":"1661","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1662","messages":"1663","suppressedMessages":"1664","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1665","messages":"1666","suppressedMessages":"1667","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1668","messages":"1669","suppressedMessages":"1670","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1671","messages":"1672","suppressedMessages":"1673","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1674","messages":"1675","suppressedMessages":"1676","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1677","messages":"1678","suppressedMessages":"1679","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1680","messages":"1681","suppressedMessages":"1682","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1683","messages":"1684","suppressedMessages":"1685","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1686","messages":"1687","suppressedMessages":"1688","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1689","messages":"1690","suppressedMessages":"1691","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1692","messages":"1693","suppressedMessages":"1694","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1695","messages":"1696","suppressedMessages":"1697","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1698","messages":"1699","suppressedMessages":"1700","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1701","messages":"1702","suppressedMessages":"1703","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1704","messages":"1705","suppressedMessages":"1706","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1707","messages":"1708","suppressedMessages":"1709","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1710","messages":"1711","suppressedMessages":"1712","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1713","messages":"1714","suppressedMessages":"1715","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1716","messages":"1717","suppressedMessages":"1718","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1719","messages":"1720","suppressedMessages":"1721","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1722","messages":"1723","suppressedMessages":"1724","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1725","messages":"1726","suppressedMessages":"1727","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1728","messages":"1729","suppressedMessages":"1730","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1731","messages":"1732","suppressedMessages":"1733","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1734","messages":"1735","suppressedMessages":"1736","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1737","messages":"1738","suppressedMessages":"1739","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1740","messages":"1741","suppressedMessages":"1742","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1743","messages":"1744","suppressedMessages":"1745","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1746","messages":"1747","suppressedMessages":"1748","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1749","messages":"1750","suppressedMessages":"1751","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1752","messages":"1753","suppressedMessages":"1754","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1755","messages":"1756","suppressedMessages":"1757","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1758","messages":"1759","suppressedMessages":"1760","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1761","messages":"1762","suppressedMessages":"1763","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1764","messages":"1765","suppressedMessages":"1766","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1767","messages":"1768","suppressedMessages":"1769","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1770","messages":"1771","suppressedMessages":"1772","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1773","messages":"1774","suppressedMessages":"1775","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1776","messages":"1777","suppressedMessages":"1778","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1779","messages":"1780","suppressedMessages":"1781","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1782","messages":"1783","suppressedMessages":"1784","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1785","messages":"1786","suppressedMessages":"1787","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1788","messages":"1789","suppressedMessages":"1790","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1791","messages":"1792","suppressedMessages":"1793","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1794","messages":"1795","suppressedMessages":"1796","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1797","messages":"1798","suppressedMessages":"1799","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1800","messages":"1801","suppressedMessages":"1802","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1803","messages":"1804","suppressedMessages":"1805","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1806","messages":"1807","suppressedMessages":"1808","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1809","messages":"1810","suppressedMessages":"1811","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1812","messages":"1813","suppressedMessages":"1814","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1815","messages":"1816","suppressedMessages":"1817","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1818","messages":"1819","suppressedMessages":"1820","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1821","messages":"1822","suppressedMessages":"1823","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1824","messages":"1825","suppressedMessages":"1826","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1827","messages":"1828","suppressedMessages":"1829","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1830","messages":"1831","suppressedMessages":"1832","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1833","messages":"1834","suppressedMessages":"1835","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1836","messages":"1837","suppressedMessages":"1838","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1839","messages":"1840","suppressedMessages":"1841","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1842","messages":"1843","suppressedMessages":"1844","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1845","messages":"1846","suppressedMessages":"1847","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1848","messages":"1849","suppressedMessages":"1850","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1851","messages":"1852","suppressedMessages":"1853","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1854","messages":"1855","suppressedMessages":"1856","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1857","messages":"1858","suppressedMessages":"1859","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1860","messages":"1861","suppressedMessages":"1862","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1863","messages":"1864","suppressedMessages":"1865","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1866","messages":"1867","suppressedMessages":"1868","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1869","messages":"1870","suppressedMessages":"1871","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1872","messages":"1873","suppressedMessages":"1874","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1875","messages":"1876","suppressedMessages":"1877","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1878","messages":"1879","suppressedMessages":"1880","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1881","messages":"1882","suppressedMessages":"1883","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1884","messages":"1885","suppressedMessages":"1886","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1887","messages":"1888","suppressedMessages":"1889","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1890","messages":"1891","suppressedMessages":"1892","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1893","messages":"1894","suppressedMessages":"1895","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1896","messages":"1897","suppressedMessages":"1898","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1899","messages":"1900","suppressedMessages":"1901","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1902","messages":"1903","suppressedMessages":"1904","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1905","messages":"1906","suppressedMessages":"1907","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1908","messages":"1909","suppressedMessages":"1910","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1911","messages":"1912","suppressedMessages":"1913","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1914","messages":"1915","suppressedMessages":"1916","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1917","messages":"1918","suppressedMessages":"1919","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1920","messages":"1921","suppressedMessages":"1922","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1923","messages":"1924","suppressedMessages":"1925","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1926","messages":"1927","suppressedMessages":"1928","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1929","messages":"1930","suppressedMessages":"1931","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1932","messages":"1933","suppressedMessages":"1934","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1935","messages":"1936","suppressedMessages":"1937","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1938","messages":"1939","suppressedMessages":"1940","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1941","messages":"1942","suppressedMessages":"1943","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1944","messages":"1945","suppressedMessages":"1946","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1947","messages":"1948","suppressedMessages":"1949","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1950","messages":"1951","suppressedMessages":"1952","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1953","messages":"1954","suppressedMessages":"1955","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1956","messages":"1957","suppressedMessages":"1958","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1959","messages":"1960","suppressedMessages":"1961","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1962","messages":"1963","suppressedMessages":"1964","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1965","messages":"1966","suppressedMessages":"1967","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1968","messages":"1969","suppressedMessages":"1970","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1971","messages":"1972","suppressedMessages":"1973","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1974","messages":"1975","suppressedMessages":"1976","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1977","messages":"1978","suppressedMessages":"1979","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1980","messages":"1981","suppressedMessages":"1982","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1983","messages":"1984","suppressedMessages":"1985","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1986","messages":"1987","suppressedMessages":"1988","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1989","messages":"1990","suppressedMessages":"1991","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1992","messages":"1993","suppressedMessages":"1994","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1995","messages":"1996","suppressedMessages":"1997","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1998","messages":"1999","suppressedMessages":"2000","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2001","messages":"2002","suppressedMessages":"2003","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2004","messages":"2005","suppressedMessages":"2006","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2007","messages":"2008","suppressedMessages":"2009","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2010","messages":"2011","suppressedMessages":"2012","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2013","messages":"2014","suppressedMessages":"2015","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2016","messages":"2017","suppressedMessages":"2018","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2019","messages":"2020","suppressedMessages":"2021","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2022","messages":"2023","suppressedMessages":"2024","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2025","messages":"2026","suppressedMessages":"2027","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2028","messages":"2029","suppressedMessages":"2030","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2031","messages":"2032","suppressedMessages":"2033","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2034","messages":"2035","suppressedMessages":"2036","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2037","messages":"2038","suppressedMessages":"2039","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2040","messages":"2041","suppressedMessages":"2042","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2043","messages":"2044","suppressedMessages":"2045","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2046","messages":"2047","suppressedMessages":"2048","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2049","messages":"2050","suppressedMessages":"2051","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2052","messages":"2053","suppressedMessages":"2054","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2055","messages":"2056","suppressedMessages":"2057","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2058","messages":"2059","suppressedMessages":"2060","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2061","messages":"2062","suppressedMessages":"2063","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2064","messages":"2065","suppressedMessages":"2066","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2067","messages":"2068","suppressedMessages":"2069","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2070","messages":"2071","suppressedMessages":"2072","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2073","messages":"2074","suppressedMessages":"2075","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2076","messages":"2077","suppressedMessages":"2078","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2079","messages":"2080","suppressedMessages":"2081","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2082","messages":"2083","suppressedMessages":"2084","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2085","messages":"2086","suppressedMessages":"2087","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2088","messages":"2089","suppressedMessages":"2090","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2091","messages":"2092","suppressedMessages":"2093","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2094","messages":"2095","suppressedMessages":"2096","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2097","messages":"2098","suppressedMessages":"2099","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2100","messages":"2101","suppressedMessages":"2102","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2103","messages":"2104","suppressedMessages":"2105","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2106","messages":"2107","suppressedMessages":"2108","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2109","messages":"2110","suppressedMessages":"2111","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2112","messages":"2113","suppressedMessages":"2114","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2115","messages":"2116","suppressedMessages":"2117","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2118","messages":"2119","suppressedMessages":"2120","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2121","messages":"2122","suppressedMessages":"2123","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2124","messages":"2125","suppressedMessages":"2126","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2127","messages":"2128","suppressedMessages":"2129","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2130","messages":"2131","suppressedMessages":"2132","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2133","messages":"2134","suppressedMessages":"2135","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2136","messages":"2137","suppressedMessages":"2138","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2139","messages":"2140","suppressedMessages":"2141","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2142","messages":"2143","suppressedMessages":"2144","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2145","messages":"2146","suppressedMessages":"2147","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2148","messages":"2149","suppressedMessages":"2150","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2151","messages":"2152","suppressedMessages":"2153","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2154","messages":"2155","suppressedMessages":"2156","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2157","messages":"2158","suppressedMessages":"2159","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2160","messages":"2161","suppressedMessages":"2162","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2163","messages":"2164","suppressedMessages":"2165","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2166","messages":"2167","suppressedMessages":"2168","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2169","messages":"2170","suppressedMessages":"2171","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2172","messages":"2173","suppressedMessages":"2174","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2175","messages":"2176","suppressedMessages":"2177","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2178","messages":"2179","suppressedMessages":"2180","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2181","messages":"2182","suppressedMessages":"2183","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2184","messages":"2185","suppressedMessages":"2186","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2187","messages":"2188","suppressedMessages":"2189","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2190","messages":"2191","suppressedMessages":"2192","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2193","messages":"2194","suppressedMessages":"2195","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2196","messages":"2197","suppressedMessages":"2198","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2199","messages":"2200","suppressedMessages":"2201","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2202","messages":"2203","suppressedMessages":"2204","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2205","messages":"2206","suppressedMessages":"2207","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2208","messages":"2209","suppressedMessages":"2210","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2211","messages":"2212","suppressedMessages":"2213","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2214","messages":"2215","suppressedMessages":"2216","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2217","messages":"2218","suppressedMessages":"2219","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2220","messages":"2221","suppressedMessages":"2222","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2223","messages":"2224","suppressedMessages":"2225","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2226","messages":"2227","suppressedMessages":"2228","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2229","messages":"2230","suppressedMessages":"2231","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2232","messages":"2233","suppressedMessages":"2234","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2235","messages":"2236","suppressedMessages":"2237","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2238","messages":"2239","suppressedMessages":"2240","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2241","messages":"2242","suppressedMessages":"2243","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2244","messages":"2245","suppressedMessages":"2246","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2247","messages":"2248","suppressedMessages":"2249","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2250","messages":"2251","suppressedMessages":"2252","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2253","messages":"2254","suppressedMessages":"2255","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2256","messages":"2257","suppressedMessages":"2258","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2259","messages":"2260","suppressedMessages":"2261","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2262","messages":"2263","suppressedMessages":"2264","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2265","messages":"2266","suppressedMessages":"2267","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2268","messages":"2269","suppressedMessages":"2270","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2271","messages":"2272","suppressedMessages":"2273","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2274","messages":"2275","suppressedMessages":"2276","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2277","messages":"2278","suppressedMessages":"2279","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2280","messages":"2281","suppressedMessages":"2282","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2283","messages":"2284","suppressedMessages":"2285","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2286","messages":"2287","suppressedMessages":"2288","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2289","messages":"2290","suppressedMessages":"2291","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2292","messages":"2293","suppressedMessages":"2294","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2295","messages":"2296","suppressedMessages":"2297","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2298","messages":"2299","suppressedMessages":"2300","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2301","messages":"2302","suppressedMessages":"2303","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2304","messages":"2305","suppressedMessages":"2306","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2307","messages":"2308","suppressedMessages":"2309","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2310","messages":"2311","suppressedMessages":"2312","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2313","messages":"2314","suppressedMessages":"2315","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2316","messages":"2317","suppressedMessages":"2318","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2319","messages":"2320","suppressedMessages":"2321","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2322","messages":"2323","suppressedMessages":"2324","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2325","messages":"2326","suppressedMessages":"2327","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2328","messages":"2329","suppressedMessages":"2330","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2331","messages":"2332","suppressedMessages":"2333","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2334","messages":"2335","suppressedMessages":"2336","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2337","messages":"2338","suppressedMessages":"2339","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2340","messages":"2341","suppressedMessages":"2342","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2343","messages":"2344","suppressedMessages":"2345","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2346","messages":"2347","suppressedMessages":"2348","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2349","messages":"2350","suppressedMessages":"2351","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2352","messages":"2353","suppressedMessages":"2354","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2355","messages":"2356","suppressedMessages":"2357","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2358","messages":"2359","suppressedMessages":"2360","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2361","messages":"2362","suppressedMessages":"2363","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2364","messages":"2365","suppressedMessages":"2366","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2367","messages":"2368","suppressedMessages":"2369","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2370","messages":"2371","suppressedMessages":"2372","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2373","messages":"2374","suppressedMessages":"2375","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2376","messages":"2377","suppressedMessages":"2378","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2379","messages":"2380","suppressedMessages":"2381","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2382","messages":"2383","suppressedMessages":"2384","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2385","messages":"2386","suppressedMessages":"2387","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2388","messages":"2389","suppressedMessages":"2390","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2391","messages":"2392","suppressedMessages":"2393","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2394","messages":"2395","suppressedMessages":"2396","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2397","messages":"2398","suppressedMessages":"2399","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2400","messages":"2401","suppressedMessages":"2402","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2403","messages":"2404","suppressedMessages":"2405","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"2406","messages":"2407","suppressedMessages":"2408","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"/home/pooya/Code/nitro/AGENTS.md",[],[],"/home/pooya/Code/nitro/CHANGELOG.md",[],[],"/home/pooya/Code/nitro/CLAUDE.md",[],[],"/home/pooya/Code/nitro/CODE_OF_CONDUCT.md",[],[],"/home/pooya/Code/nitro/CONTRIBUTING.md",[],[],"/home/pooya/Code/nitro/README.md",[],[],"/home/pooya/Code/nitro/SECURITY.md",[],[],"/home/pooya/Code/nitro/automd.config.ts",[],[],"/home/pooya/Code/nitro/build.config.ts",[],[],"/home/pooya/Code/nitro/changelog.config.ts",[],[],"/home/pooya/Code/nitro/docs/.config/automd.config.ts",[],[],"/home/pooya/Code/nitro/eslint.config.mjs",[],[],"/home/pooya/Code/nitro/examples/api-routes/api/hello/[name].ts",[],[],"/home/pooya/Code/nitro/examples/api-routes/api/hello.ts",[],[],"/home/pooya/Code/nitro/examples/api-routes/api/test.get.ts",[],[],"/home/pooya/Code/nitro/examples/api-routes/api/test.post.ts",[],[],"/home/pooya/Code/nitro/examples/api-routes/nitro.config.ts",[],[],"/home/pooya/Code/nitro/examples/api-routes/vite.config.ts",[],[],"/home/pooya/Code/nitro/examples/auto-imports/nitro.config.ts",[],[],"/home/pooya/Code/nitro/examples/auto-imports/server/utils/hello.ts",[],[],"/home/pooya/Code/nitro/examples/auto-imports/server.ts",[],[],"/home/pooya/Code/nitro/examples/auto-imports/vite.config.ts",[],[],"/home/pooya/Code/nitro/examples/cached-handler/nitro.config.ts",[],[],"/home/pooya/Code/nitro/examples/cached-handler/server.ts",[],[],"/home/pooya/Code/nitro/examples/cached-handler/vite.config.ts",[],[],"/home/pooya/Code/nitro/examples/custom-error-handler/error.ts",[],[],"/home/pooya/Code/nitro/examples/custom-error-handler/nitro.config.ts",[],[],"/home/pooya/Code/nitro/examples/custom-error-handler/server.ts",[],[],"/home/pooya/Code/nitro/examples/custom-error-handler/vite.config.ts",[],[],"/home/pooya/Code/nitro/examples/database/nitro.config.ts",[],[],"/home/pooya/Code/nitro/examples/database/server.ts",[],[],"/home/pooya/Code/nitro/examples/database/tasks/db/migrate.ts",[],[],"/home/pooya/Code/nitro/examples/database/vite.config.ts",[],[],"/home/pooya/Code/nitro/examples/elysia/nitro.config.ts",[],[],"/home/pooya/Code/nitro/examples/elysia/server.ts",[],[],"/home/pooya/Code/nitro/examples/elysia/vite.config.ts",[],[],"/home/pooya/Code/nitro/examples/express/nitro.config.ts",[],[],"/home/pooya/Code/nitro/examples/express/server.node.ts",[],[],"/home/pooya/Code/nitro/examples/express/vite.config.ts",[],[],"/home/pooya/Code/nitro/examples/fastify/nitro.config.ts",[],[],"/home/pooya/Code/nitro/examples/fastify/server.node.ts",[],[],"/home/pooya/Code/nitro/examples/fastify/vite.config.ts",[],[],"/home/pooya/Code/nitro/examples/hello-world/nitro.config.ts",[],[],"/home/pooya/Code/nitro/examples/hello-world/server.ts",[],[],"/home/pooya/Code/nitro/examples/hello-world/vite.config.ts",[],[],"/home/pooya/Code/nitro/examples/hono/nitro.config.ts",[],[],"/home/pooya/Code/nitro/examples/hono/server.ts",[],[],"/home/pooya/Code/nitro/examples/hono/vite.config.ts",[],[],"/home/pooya/Code/nitro/examples/import-alias/nitro.config.ts",[],[],"/home/pooya/Code/nitro/examples/import-alias/server/routes/index.ts",[],[],"/home/pooya/Code/nitro/examples/import-alias/server/utils/math.ts",[],[],"/home/pooya/Code/nitro/examples/import-alias/vite.config.ts",[],[],"/home/pooya/Code/nitro/examples/middleware/nitro.config.ts",[],[],"/home/pooya/Code/nitro/examples/middleware/server/middleware/auth.ts",[],[],"/home/pooya/Code/nitro/examples/middleware/server.ts",[],[],"/home/pooya/Code/nitro/examples/middleware/vite.config.ts",[],[],"/home/pooya/Code/nitro/examples/mono-jsx/nitro.config.ts",[],[],"/home/pooya/Code/nitro/examples/mono-jsx/server.tsx",[],[],"/home/pooya/Code/nitro/examples/mono-jsx/vite.config.ts",[],[],"/home/pooya/Code/nitro/examples/nano-jsx/nitro.config.ts",[],[],"/home/pooya/Code/nitro/examples/nano-jsx/server.tsx",[],[],"/home/pooya/Code/nitro/examples/nano-jsx/vite.config.ts",[],[],"/home/pooya/Code/nitro/examples/plugins/nitro.config.ts",[],[],"/home/pooya/Code/nitro/examples/plugins/server/plugins/test.ts",[],[],"/home/pooya/Code/nitro/examples/plugins/server.ts",[],[],"/home/pooya/Code/nitro/examples/plugins/vite.config.ts",[],[],"/home/pooya/Code/nitro/examples/renderer/api/hello.ts",[],[],"/home/pooya/Code/nitro/examples/renderer/nitro.config.ts",[],[],"/home/pooya/Code/nitro/examples/renderer/renderer.ts",[],[],"/home/pooya/Code/nitro/examples/renderer/vite.config.ts",[],[],"/home/pooya/Code/nitro/examples/runtime-config/nitro.config.ts",[],[],"/home/pooya/Code/nitro/examples/runtime-config/server.ts",[],[],"/home/pooya/Code/nitro/examples/runtime-config/vite.config.ts",[],[],"/home/pooya/Code/nitro/examples/server-fetch/nitro.config.ts",[],[],"/home/pooya/Code/nitro/examples/server-fetch/routes/hello.ts",[],[],"/home/pooya/Code/nitro/examples/server-fetch/routes/index.ts",[],[],"/home/pooya/Code/nitro/examples/server-fetch/vite.config.ts",[],[],"/home/pooya/Code/nitro/examples/shiki/api/highlight.ts",[],[],"/home/pooya/Code/nitro/examples/shiki/nitro.config.ts",[],[],"/home/pooya/Code/nitro/examples/shiki/vite.config.ts",[],[],"/home/pooya/Code/nitro/examples/virtual-routes/nitro.config.ts",[],[],"/home/pooya/Code/nitro/examples/virtual-routes/vite.config.ts",[],[],"/home/pooya/Code/nitro/examples/vite-nitro-plugin/vite.config.mjs",[],[],"/home/pooya/Code/nitro/examples/vite-rsc/app/action.tsx",[],[],"/home/pooya/Code/nitro/examples/vite-rsc/app/client.tsx",[],[],"/home/pooya/Code/nitro/examples/vite-rsc/app/framework/entry.browser.tsx",[],["2409"],"/home/pooya/Code/nitro/examples/vite-rsc/app/framework/entry.rsc.tsx",[],["2410"],"/home/pooya/Code/nitro/examples/vite-rsc/app/framework/entry.ssr.tsx",[],[],"/home/pooya/Code/nitro/examples/vite-rsc/app/framework/error-boundary.tsx",[],[],"/home/pooya/Code/nitro/examples/vite-rsc/app/framework/request.tsx",[],[],"/home/pooya/Code/nitro/examples/vite-rsc/app/root.tsx",[],["2411"],"/home/pooya/Code/nitro/examples/vite-rsc/vite.config.ts",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-html/app/entry-server.ts",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-html/routes/quote.ts",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-html/vite.config.ts",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-preact/src/app.tsx",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-preact/src/entry-client.tsx",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-preact/src/entry-server.tsx",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-preact/vite.config.mjs",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-react/src/app.tsx",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-react/src/entry-client.tsx",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-react/src/entry-server.tsx",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-react/vite.config.mjs",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-solid/src/app.tsx",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-solid/src/entry-client.tsx",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-solid/src/entry-server.tsx",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-solid/vite.config.mjs",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-tsr-react/src/main.tsx",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-tsr-react/src/routes/__root.tsx",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-tsr-react/src/routes/index.tsx",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-tsr-react/vite.config.mjs",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-tss-react/server.ts",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-tss-react/src/router.tsx",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-tss-react/src/routes/__root.tsx",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-tss-react/src/routes/api/test.ts",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-tss-react/src/routes/index.tsx",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-tss-react/vite.config.mjs",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-vue-router/app/entry-client.ts",[],["2412"],"/home/pooya/Code/nitro/examples/vite-ssr-vue-router/app/entry-server.ts",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-vue-router/app/routes.ts",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-vue-router/app/shims.d.ts",[],[],"/home/pooya/Code/nitro/examples/vite-ssr-vue-router/vite.config.mjs",[],[],"/home/pooya/Code/nitro/examples/vite-trpc/server/trpc.ts",[],[],"/home/pooya/Code/nitro/examples/vite-trpc/vite.config.ts",[],[],"/home/pooya/Code/nitro/examples/websocket/nitro.config.ts",[],[],"/home/pooya/Code/nitro/examples/websocket/routes/_ws.ts",[],[],"/home/pooya/Code/nitro/examples/websocket/vite.config.ts",[],[],"/home/pooya/Code/nitro/lib/h3.d.mts",[],[],"/home/pooya/Code/nitro/lib/h3.mjs",[],[],"/home/pooya/Code/nitro/lib/vite.types.d.mts",[],[],"/home/pooya/Code/nitro/lib/vite.types.mjs",[],["2413"],"/home/pooya/Code/nitro/playground/nitro.config.ts",[],[],"/home/pooya/Code/nitro/playground/server.ts",[],[],"/home/pooya/Code/nitro/playground/vite.config.ts",[],[],"/home/pooya/Code/nitro/scripts/bump-nightly.ts",[],["2414","2415"],"/home/pooya/Code/nitro/scripts/gen-node-compat.ts",[],[],"/home/pooya/Code/nitro/scripts/gen-presets.ts",[],[],"/home/pooya/Code/nitro/src/build/assets.ts",[],[],"/home/pooya/Code/nitro/src/build/build.ts",[],[],"/home/pooya/Code/nitro/src/build/chunks.ts",[],[],"/home/pooya/Code/nitro/src/build/config.ts",[],[],"/home/pooya/Code/nitro/src/build/info.ts",[],[],"/home/pooya/Code/nitro/src/build/plugins/externals.ts",[],[],"/home/pooya/Code/nitro/src/build/plugins/oxc.ts",[],[],"/home/pooya/Code/nitro/src/build/plugins/raw.ts",[],[],"/home/pooya/Code/nitro/src/build/plugins/route-meta.ts",[],["2416"],"/home/pooya/Code/nitro/src/build/plugins/server-main.ts",[],[],"/home/pooya/Code/nitro/src/build/plugins/sourcemap-min.ts",[],[],"/home/pooya/Code/nitro/src/build/plugins/virtual.ts",[],[],"/home/pooya/Code/nitro/src/build/plugins.ts",[],[],"/home/pooya/Code/nitro/src/build/prepare.ts",[],[],"/home/pooya/Code/nitro/src/build/rolldown/build.ts",[],[],"/home/pooya/Code/nitro/src/build/rolldown/config.ts",[],[],"/home/pooya/Code/nitro/src/build/rolldown/dev.ts",[],[],"/home/pooya/Code/nitro/src/build/rolldown/prod.ts",[],[],"/home/pooya/Code/nitro/src/build/rollup/build.ts",[],[],"/home/pooya/Code/nitro/src/build/rollup/config.ts",[],[],"/home/pooya/Code/nitro/src/build/rollup/dev.ts",[],[],"/home/pooya/Code/nitro/src/build/rollup/error.ts",[],[],"/home/pooya/Code/nitro/src/build/rollup/prod.ts",[],[],"/home/pooya/Code/nitro/src/build/types.ts",[],[],"/home/pooya/Code/nitro/src/build/virtual/_all.ts",[],[],"/home/pooya/Code/nitro/src/build/virtual/database.ts",[],[],"/home/pooya/Code/nitro/src/build/virtual/error-handler.ts",[],[],"/home/pooya/Code/nitro/src/build/virtual/feature-flags.ts",[],[],"/home/pooya/Code/nitro/src/build/virtual/plugins.ts",[],[],"/home/pooya/Code/nitro/src/build/virtual/polyfills.ts",[],[],"/home/pooya/Code/nitro/src/build/virtual/public-assets.ts",[],[],"/home/pooya/Code/nitro/src/build/virtual/renderer-template.ts",[],[],"/home/pooya/Code/nitro/src/build/virtual/routing-meta.ts",[],[],"/home/pooya/Code/nitro/src/build/virtual/routing.ts",[],[],"/home/pooya/Code/nitro/src/build/virtual/runtime-config.ts",[],[],"/home/pooya/Code/nitro/src/build/virtual/server-assets.ts",[],[],"/home/pooya/Code/nitro/src/build/virtual/storage.ts",[],[],"/home/pooya/Code/nitro/src/build/virtual/tasks.ts",[],[],"/home/pooya/Code/nitro/src/build/vite/build.ts",[],[],"/home/pooya/Code/nitro/src/build/vite/bundler.ts",[],[],"/home/pooya/Code/nitro/src/build/vite/dev.ts",[],[],"/home/pooya/Code/nitro/src/build/vite/env.ts",[],[],"/home/pooya/Code/nitro/src/build/vite/plugin.ts",[],[],"/home/pooya/Code/nitro/src/build/vite/preview.ts",[],[],"/home/pooya/Code/nitro/src/build/vite/prod.ts",[],[],"/home/pooya/Code/nitro/src/build/vite/types.ts",[],[],"/home/pooya/Code/nitro/src/builder.ts",[],[],"/home/pooya/Code/nitro/src/cli/commands/build.ts",[],[],"/home/pooya/Code/nitro/src/cli/commands/dev.ts",[],[],"/home/pooya/Code/nitro/src/cli/commands/prepare.ts",[],[],"/home/pooya/Code/nitro/src/cli/commands/task/index.ts",[],[],"/home/pooya/Code/nitro/src/cli/commands/task/list.ts",[],[],"/home/pooya/Code/nitro/src/cli/commands/task/run.ts",[],["2417"],"/home/pooya/Code/nitro/src/cli/common.ts",[],[],"/home/pooya/Code/nitro/src/cli/index.ts",[],[],"/home/pooya/Code/nitro/src/config/defaults.ts",[],[],"/home/pooya/Code/nitro/src/config/loader.ts",[],[],"/home/pooya/Code/nitro/src/config/resolvers/assets.ts",[],[],"/home/pooya/Code/nitro/src/config/resolvers/builder.ts",[],[],"/home/pooya/Code/nitro/src/config/resolvers/compatibility.ts",[],[],"/home/pooya/Code/nitro/src/config/resolvers/database.ts",[],[],"/home/pooya/Code/nitro/src/config/resolvers/error.ts",[],[],"/home/pooya/Code/nitro/src/config/resolvers/export-conditions.ts",[],[],"/home/pooya/Code/nitro/src/config/resolvers/imports.ts",[],[],"/home/pooya/Code/nitro/src/config/resolvers/open-api.ts",[],[],"/home/pooya/Code/nitro/src/config/resolvers/paths.ts",[],[],"/home/pooya/Code/nitro/src/config/resolvers/route-rules.ts",[],[],"/home/pooya/Code/nitro/src/config/resolvers/runtime-config.ts",[],[],"/home/pooya/Code/nitro/src/config/resolvers/storage.ts",[],[],"/home/pooya/Code/nitro/src/config/resolvers/tsconfig.ts",[],[],"/home/pooya/Code/nitro/src/config/resolvers/unenv.ts",[],[],"/home/pooya/Code/nitro/src/config/resolvers/url.ts",[],[],"/home/pooya/Code/nitro/src/config/update.ts",[],[],"/home/pooya/Code/nitro/src/dev/app.ts",[],[],"/home/pooya/Code/nitro/src/dev/server.ts",[],[],"/home/pooya/Code/nitro/src/dev/vfs.ts",[],[],"/home/pooya/Code/nitro/src/global.ts",[],[],"/home/pooya/Code/nitro/src/module.ts",[],[],"/home/pooya/Code/nitro/src/nitro.ts",[],[],"/home/pooya/Code/nitro/src/prerender/prerender.ts",[],[],"/home/pooya/Code/nitro/src/prerender/utils.ts",[],[],"/home/pooya/Code/nitro/src/presets/_nitro/base-worker.ts",[],[],"/home/pooya/Code/nitro/src/presets/_nitro/nitro-dev.ts",[],[],"/home/pooya/Code/nitro/src/presets/_nitro/nitro-prerender.ts",[],[],"/home/pooya/Code/nitro/src/presets/_nitro/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/_nitro/runtime/nitro-dev.ts",[],["2418"],"/home/pooya/Code/nitro/src/presets/_nitro/runtime/nitro-prerenderer.ts",[],[],"/home/pooya/Code/nitro/src/presets/_nitro/runtime/service-worker.ts",[],[],"/home/pooya/Code/nitro/src/presets/_resolve.ts",[],[],"/home/pooya/Code/nitro/src/presets/_static/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/_utils/fs.ts",[],[],"/home/pooya/Code/nitro/src/presets/_utils/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/alwaysdata/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/aws-amplify/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/aws-amplify/runtime/aws-amplify.ts",[],[],"/home/pooya/Code/nitro/src/presets/aws-amplify/types.ts",[],[],"/home/pooya/Code/nitro/src/presets/aws-amplify/utils.ts",[],[],"/home/pooya/Code/nitro/src/presets/aws-lambda/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/aws-lambda/runtime/_utils.ts",[],[],"/home/pooya/Code/nitro/src/presets/aws-lambda/runtime/aws-lambda-streaming.ts",[],[],"/home/pooya/Code/nitro/src/presets/aws-lambda/runtime/aws-lambda.ts",[],[],"/home/pooya/Code/nitro/src/presets/aws-lambda/types.ts",[],[],"/home/pooya/Code/nitro/src/presets/azure/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/azure/runtime/_utils.ts",[],[],"/home/pooya/Code/nitro/src/presets/azure/runtime/azure-swa.ts",[],[],"/home/pooya/Code/nitro/src/presets/azure/types.ts",[],[],"/home/pooya/Code/nitro/src/presets/azure/utils.ts",[],[],"/home/pooya/Code/nitro/src/presets/bun/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/bun/runtime/bun.ts",[],[],"/home/pooya/Code/nitro/src/presets/cleavr/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/cloudflare/dev.ts",[],[],"/home/pooya/Code/nitro/src/presets/cloudflare/entry-exports.ts",[],[],"/home/pooya/Code/nitro/src/presets/cloudflare/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/cloudflare/runtime/_module-handler.ts",[],[],"/home/pooya/Code/nitro/src/presets/cloudflare/runtime/cloudflare-durable.ts",[],[],"/home/pooya/Code/nitro/src/presets/cloudflare/runtime/cloudflare-module.ts",[],[],"/home/pooya/Code/nitro/src/presets/cloudflare/runtime/cloudflare-pages.ts",[],[],"/home/pooya/Code/nitro/src/presets/cloudflare/runtime/plugin.dev.ts",[],[],"/home/pooya/Code/nitro/src/presets/cloudflare/runtime/shims/workers.dev.mjs",[],[],"/home/pooya/Code/nitro/src/presets/cloudflare/types.ts",[],[],"/home/pooya/Code/nitro/src/presets/cloudflare/unenv/node-compat.ts",[],[],"/home/pooya/Code/nitro/src/presets/cloudflare/unenv/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/cloudflare/utils.ts",[],[],"/home/pooya/Code/nitro/src/presets/cloudflare/wrangler/_utils.ts",[],[],"/home/pooya/Code/nitro/src/presets/cloudflare/wrangler/config.ts",[],[],"/home/pooya/Code/nitro/src/presets/cloudflare/wrangler/environment.ts",[],[],"/home/pooya/Code/nitro/src/presets/deno/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/deno/runtime/deno-deploy.ts",[],[],"/home/pooya/Code/nitro/src/presets/deno/runtime/deno-server.ts",[],[],"/home/pooya/Code/nitro/src/presets/deno/unenv/node-compat.ts",[],[],"/home/pooya/Code/nitro/src/presets/deno/unenv/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/digitalocean/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/firebase/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/firebase/types.ts",[],[],"/home/pooya/Code/nitro/src/presets/flightcontrol/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/genezio/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/heroku/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/iis/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/iis/utils.ts",[],[],"/home/pooya/Code/nitro/src/presets/index.ts",[],[],"/home/pooya/Code/nitro/src/presets/koyeb/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/netlify/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/netlify/runtime/netlify-edge.ts",[],[],"/home/pooya/Code/nitro/src/presets/netlify/runtime/netlify.ts",[],[],"/home/pooya/Code/nitro/src/presets/netlify/types.ts",[],[],"/home/pooya/Code/nitro/src/presets/netlify/utils.ts",[],[],"/home/pooya/Code/nitro/src/presets/node/cluster.ts",[],[],"/home/pooya/Code/nitro/src/presets/node/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/node/runtime/node-cluster.ts",[],[],"/home/pooya/Code/nitro/src/presets/node/runtime/node-middleware.ts",[],[],"/home/pooya/Code/nitro/src/presets/node/runtime/node-server.ts",[],[],"/home/pooya/Code/nitro/src/presets/platform.sh/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/render.com/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/standard/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/standard/runtime/server.ts",[],[],"/home/pooya/Code/nitro/src/presets/stormkit/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/stormkit/runtime/stormkit.ts",[],[],"/home/pooya/Code/nitro/src/presets/vercel/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/vercel/runtime/isr.ts",[],[],"/home/pooya/Code/nitro/src/presets/vercel/runtime/vercel.node.ts",[],[],"/home/pooya/Code/nitro/src/presets/vercel/runtime/vercel.web.ts",[],[],"/home/pooya/Code/nitro/src/presets/vercel/types.ts",[],[],"/home/pooya/Code/nitro/src/presets/vercel/utils.ts",[],[],"/home/pooya/Code/nitro/src/presets/winterjs/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/winterjs/runtime/winterjs.ts",[],[],"/home/pooya/Code/nitro/src/presets/zeabur/preset.ts",[],[],"/home/pooya/Code/nitro/src/presets/zeabur/runtime/zeabur.ts",[],[],"/home/pooya/Code/nitro/src/presets/zerops/preset.ts",[],[],"/home/pooya/Code/nitro/src/routing.ts",[],[],"/home/pooya/Code/nitro/src/runner/node.ts",[],["2419"],"/home/pooya/Code/nitro/src/runner/proxy.ts",[],[],"/home/pooya/Code/nitro/src/runtime/app.ts",[],[],"/home/pooya/Code/nitro/src/runtime/cache.ts",[],[],"/home/pooya/Code/nitro/src/runtime/config.ts",[],[],"/home/pooya/Code/nitro/src/runtime/context.ts",[],[],"/home/pooya/Code/nitro/src/runtime/database.ts",[],[],"/home/pooya/Code/nitro/src/runtime/internal/app.ts",[],[],"/home/pooya/Code/nitro/src/runtime/internal/cache.ts",[],[],"/home/pooya/Code/nitro/src/runtime/internal/context.ts",[],[],"/home/pooya/Code/nitro/src/runtime/internal/database.ts",[],[],"/home/pooya/Code/nitro/src/runtime/internal/empty.ts",[],[],"/home/pooya/Code/nitro/src/runtime/internal/error/dev.ts",[],[],"/home/pooya/Code/nitro/src/runtime/internal/error/hooks.ts",[],[],"/home/pooya/Code/nitro/src/runtime/internal/error/prod.ts",[],[],"/home/pooya/Code/nitro/src/runtime/internal/error/utils.ts",[],[],"/home/pooya/Code/nitro/src/runtime/internal/meta.ts",[],[],"/home/pooya/Code/nitro/src/runtime/internal/plugin.ts",[],[],"/home/pooya/Code/nitro/src/runtime/internal/route-rules.ts",[],[],"/home/pooya/Code/nitro/src/runtime/internal/routes/dev-tasks.ts",[],[],"/home/pooya/Code/nitro/src/runtime/internal/routes/openapi.ts",[],[],"/home/pooya/Code/nitro/src/runtime/internal/routes/renderer-template.dev.ts",[],[],"/home/pooya/Code/nitro/src/runtime/internal/routes/renderer-template.ts",[],[],"/home/pooya/Code/nitro/src/runtime/internal/routes/scalar.ts",[],[],"/home/pooya/Code/nitro/src/runtime/internal/routes/swagger.ts",[],[],"/home/pooya/Code/nitro/src/runtime/internal/runtime-config.ts",[],[],"/home/pooya/Code/nitro/src/runtime/internal/static.ts",[],[],"/home/pooya/Code/nitro/src/runtime/internal/storage.ts",[],[],"/home/pooya/Code/nitro/src/runtime/internal/task.ts",[],[],"/home/pooya/Code/nitro/src/runtime/internal/vite/dev-entry.mjs",[],[],"/home/pooya/Code/nitro/src/runtime/internal/vite/node-runner.mjs",[],["2420"],"/home/pooya/Code/nitro/src/runtime/internal/vite/ssr-renderer.mjs",[],[],"/home/pooya/Code/nitro/src/runtime/meta.ts",[],[],"/home/pooya/Code/nitro/src/runtime/nitro.ts",[],[],"/home/pooya/Code/nitro/src/runtime/runtime-config.ts",[],[],"/home/pooya/Code/nitro/src/runtime/storage.ts",[],[],"/home/pooya/Code/nitro/src/runtime/task.ts",[],[],"/home/pooya/Code/nitro/src/runtime/virtual/_runtime_warn.ts",[],[],"/home/pooya/Code/nitro/src/runtime/virtual/database.ts",[],[],"/home/pooya/Code/nitro/src/runtime/virtual/error-handler.ts",[],[],"/home/pooya/Code/nitro/src/runtime/virtual/feature-flags.ts",[],[],"/home/pooya/Code/nitro/src/runtime/virtual/plugins.ts",[],[],"/home/pooya/Code/nitro/src/runtime/virtual/polyfills.ts",[],[],"/home/pooya/Code/nitro/src/runtime/virtual/public-assets.ts",[],[],"/home/pooya/Code/nitro/src/runtime/virtual/renderer-template.ts",[],[],"/home/pooya/Code/nitro/src/runtime/virtual/routing-meta.ts",[],[],"/home/pooya/Code/nitro/src/runtime/virtual/routing.ts",[],[],"/home/pooya/Code/nitro/src/runtime/virtual/runtime-config.ts",[],[],"/home/pooya/Code/nitro/src/runtime/virtual/server-assets.ts",[],[],"/home/pooya/Code/nitro/src/runtime/virtual/storage.ts",[],[],"/home/pooya/Code/nitro/src/runtime/virtual/tasks.ts",[],[],"/home/pooya/Code/nitro/src/runtime/vite.ts",[],[],"/home/pooya/Code/nitro/src/scan.ts",[],[],"/home/pooya/Code/nitro/src/task.ts",[],[],"/home/pooya/Code/nitro/src/types/_utils.ts",[],["2421"],"/home/pooya/Code/nitro/src/types/build.ts",[],[],"/home/pooya/Code/nitro/src/types/config.ts",[],[],"/home/pooya/Code/nitro/src/types/fetch/_match.ts",[],[],"/home/pooya/Code/nitro/src/types/fetch/_serialize.ts",[],["2422"],"/home/pooya/Code/nitro/src/types/fetch/fetch.ts",[],["2423"],"/home/pooya/Code/nitro/src/types/fetch/index.ts",[],[],"/home/pooya/Code/nitro/src/types/global.ts",[],["2424"],"/home/pooya/Code/nitro/src/types/h3.ts",[],["2425"],"/home/pooya/Code/nitro/src/types/handler.ts",[],[],"/home/pooya/Code/nitro/src/types/hooks.ts",[],[],"/home/pooya/Code/nitro/src/types/index.ts",[],[],"/home/pooya/Code/nitro/src/types/module.ts",[],[],"/home/pooya/Code/nitro/src/types/nitro.ts",[],[],"/home/pooya/Code/nitro/src/types/openapi-ts.ts",[],[],"/home/pooya/Code/nitro/src/types/openapi.ts",[],[],"/home/pooya/Code/nitro/src/types/prerender.ts",[],[],"/home/pooya/Code/nitro/src/types/preset.ts",[],[],"/home/pooya/Code/nitro/src/types/route-rules.ts",[],[],"/home/pooya/Code/nitro/src/types/runner.ts",[],[],"/home/pooya/Code/nitro/src/types/runtime/asset.ts",[],[],"/home/pooya/Code/nitro/src/types/runtime/cache.ts",[],[],"/home/pooya/Code/nitro/src/types/runtime/index.ts",[],[],"/home/pooya/Code/nitro/src/types/runtime/nitro.ts",[],[],"/home/pooya/Code/nitro/src/types/runtime/task.ts",[],[],"/home/pooya/Code/nitro/src/types/srvx.ts",[],[],"/home/pooya/Code/nitro/src/utils/compress.ts",[],[],"/home/pooya/Code/nitro/src/utils/dep.ts",[],[],"/home/pooya/Code/nitro/src/utils/fs-tree.ts",[],[],"/home/pooya/Code/nitro/src/utils/fs.ts",[],["2426"],"/home/pooya/Code/nitro/src/utils/parallel.ts",[],[],"/home/pooya/Code/nitro/src/utils/regex.ts",[],[],"/home/pooya/Code/nitro/src/vite.ts",[],[],"/home/pooya/Code/nitro/test/examples.test.ts",[],[],"/home/pooya/Code/nitro/test/fixture/error.ts",[],[],"/home/pooya/Code/nitro/test/fixture/exports.cloudflare.ts",[],[],"/home/pooya/Code/nitro/test/fixture/nitro.config.ts",[],[],"/home/pooya/Code/nitro/test/fixture/public/foo.js",[],[],"/home/pooya/Code/nitro/test/fixture/server/files/sqlts.sql.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/middleware/_ignored.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/plugins/errors.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/plugins/vary.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/(route-group)/route-group.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/500.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/api/_ignored.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/api/cached.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/api/db.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/api/echo.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/api/error.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/api/errors.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/api/headers.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/api/hello.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/api/hey/index.get.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/api/kebab.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/api/meta/test.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/api/methods/foo.get.get.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/api/methods/get.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/api/param/[test-id].ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/api/storage/item.get.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/api/storage/item.put.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/api/upload.post.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/api/wildcard/[...param].ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/assets/[id].ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/assets/all.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/assets/md.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/config.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/context.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/env/index.dev.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/env/index.get.prod.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/error-stack.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/fetch.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/file.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/icon.png.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/imports.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/json-string.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/jsx.tsx",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/modules.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/node-compat.ts",[],["2427","2428","2429"],"/home/pooya/Code/nitro/test/fixture/server/routes/prerender-custom.html.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/prerender.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/raw.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/replace.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/rules/[...slug].ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/static-flags.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/stream.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/tasks/[...name].ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/wait-until.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/wasm/dynamic-import.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/routes/wasm/static-import.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/tasks/db/migrate.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/tasks/test.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/utils/foo/bar/test.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/utils/foo/test.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server/utils/test.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server.config.ts",[],[],"/home/pooya/Code/nitro/test/fixture/server.ts",[],[],"/home/pooya/Code/nitro/test/fixture/vite.config.ts",[],[],"/home/pooya/Code/nitro/test/minimal/minimal.test.ts",[],[],"/home/pooya/Code/nitro/test/minimal/nitro.config.ts",[],[],"/home/pooya/Code/nitro/test/minimal/server.ts",[],[],"/home/pooya/Code/nitro/test/minimal/vite.config.mjs",[],[],"/home/pooya/Code/nitro/test/presets/aws-lambda.test.ts",[],[],"/home/pooya/Code/nitro/test/presets/azure-swa.test.ts",[],[],"/home/pooya/Code/nitro/test/presets/bun.test.ts",[],[],"/home/pooya/Code/nitro/test/presets/cloudflare-module.test.ts",[],[],"/home/pooya/Code/nitro/test/presets/cloudflare-pages.test.ts",[],[],"/home/pooya/Code/nitro/test/presets/deno-server.test.ts",[],[],"/home/pooya/Code/nitro/test/presets/netlify.test.ts",[],[],"/home/pooya/Code/nitro/test/presets/nitro-dev.test.ts",[],[],"/home/pooya/Code/nitro/test/presets/node.test.ts",[],[],"/home/pooya/Code/nitro/test/presets/standard.test.ts",[],[],"/home/pooya/Code/nitro/test/presets/static.test.ts",[],[],"/home/pooya/Code/nitro/test/presets/vercel.test.ts",[],[],"/home/pooya/Code/nitro/test/presets/winterjs.test.ts",[],[],"/home/pooya/Code/nitro/test/scripts/gen-fixture-types.ts",[],[],"/home/pooya/Code/nitro/test/tests.ts",[],[],"/home/pooya/Code/nitro/test/unit/azure.utils.test.ts",[],[],"/home/pooya/Code/nitro/test/unit/runtime-config.env.test.ts",[],[],"/home/pooya/Code/nitro/test/unit/runtime-config.test.ts",[],[],"/home/pooya/Code/nitro/test/unit/virtual.test.ts",[],[],"/home/pooya/Code/nitro/vitest.config.ts",[],[],{"ruleId":"2430","severity":2,"message":"2431","line":139,"column":1,"nodeType":"2432","messageId":"2433","endLine":139,"endColumn":7,"suggestions":"2434","suppressions":"2435"},{"ruleId":"2436","severity":2,"message":"2437","line":53,"column":28,"nodeType":"2432","messageId":"2438","endLine":53,"endColumn":52,"suppressions":"2439"},{"ruleId":"2440","severity":2,"message":"2441","line":13,"column":23,"nodeType":"2442","messageId":"2443","endLine":13,"endColumn":30,"suggestions":"2444","suppressions":"2445"},{"ruleId":"2430","severity":2,"message":"2431","line":15,"column":1,"nodeType":"2432","messageId":"2433","endLine":15,"endColumn":7,"suggestions":"2446","suppressions":"2447"},{"ruleId":"2448","severity":2,"message":"2449","line":2,"column":8,"nodeType":"2450","messageId":"2451","endLine":2,"endColumn":10,"fix":"2452","suppressions":"2453"},{"ruleId":"2430","severity":2,"message":"2454","line":143,"column":8,"nodeType":"2455","messageId":"2456","endLine":143,"endColumn":13,"suppressions":"2457"},{"ruleId":"2458","severity":2,"message":"2459","line":146,"column":3,"nodeType":"2432","messageId":"2460","endLine":146,"endColumn":18,"suppressions":"2461"},{"ruleId":"2462","severity":2,"message":"2463","line":16,"column":21,"nodeType":"2442","messageId":"2464","endLine":16,"endColumn":45,"suppressions":"2465"},{"ruleId":"2458","severity":2,"message":"2459","line":55,"column":7,"nodeType":"2432","messageId":"2460","endLine":55,"endColumn":22,"suppressions":"2466"},{"ruleId":"2430","severity":2,"message":"2454","line":32,"column":4,"nodeType":"2455","messageId":"2456","endLine":32,"endColumn":9,"suppressions":"2467"},{"ruleId":"2468","severity":2,"message":"2469","line":124,"column":45,"nodeType":"2470","messageId":"2471","endLine":124,"endColumn":77,"fix":"2472","suppressions":"2473"},{"ruleId":"2430","severity":2,"message":"2474","line":185,"column":1,"nodeType":"2432","messageId":"2433","endLine":185,"endColumn":9,"suggestions":"2475","suppressions":"2476"},{"ruleId":"2477","severity":2,"message":"2478","line":16,"column":47,"nodeType":"2455","messageId":"2479","endLine":16,"endColumn":55,"suppressions":"2480"},{"ruleId":"2477","severity":2,"message":"2478","line":13,"column":37,"nodeType":"2455","messageId":"2479","endLine":13,"endColumn":45,"suppressions":"2481"},{"ruleId":"2448","severity":2,"message":"2449","line":116,"column":13,"nodeType":"2450","messageId":"2451","endLine":116,"endColumn":15,"fix":"2482","suppressions":"2483"},{"ruleId":"2448","severity":2,"message":"2449","line":22,"column":13,"nodeType":"2450","messageId":"2451","endLine":22,"endColumn":15,"fix":"2484","suppressions":"2485"},{"ruleId":"2448","severity":2,"message":"2449","line":28,"column":13,"nodeType":"2450","messageId":"2451","endLine":28,"endColumn":15,"fix":"2486","suppressions":"2487"},{"ruleId":"2462","severity":2,"message":"2463","line":32,"column":7,"nodeType":"2442","messageId":"2464","endLine":32,"endColumn":19,"suppressions":"2488"},{"ruleId":"2489","severity":2,"message":"2490","line":8,"column":41,"nodeType":"2455","messageId":"2491","endLine":8,"endColumn":47,"fix":"2492","suppressions":"2493"},{"ruleId":"2489","severity":2,"message":"2490","line":10,"column":50,"nodeType":"2455","messageId":"2491","endLine":10,"endColumn":56,"fix":"2494","suppressions":"2495"},{"ruleId":"2489","severity":2,"message":"2490","line":12,"column":53,"nodeType":"2455","messageId":"2491","endLine":12,"endColumn":59,"fix":"2496","suppressions":"2497"},"unicorn/prefer-top-level-await","Prefer top-level await over an async function `main` call.","CallExpression","identifier",["2498"],["2499"],"prefer-spread","Use the spread operator instead of '.apply()'.","preferSpread",["2500"],"unicorn/text-encoding-identifier-case","Prefer `utf-8` over `UTF-8`.","Literal","text-encoding-identifier/error",["2501"],["2502"],["2503"],["2504"],"unicorn/require-module-specifiers","export statement without specifiers is not allowed.","ExportNamedDeclaration","error",{"range":"2505","text":"2506"},["2507"],"Prefer top-level await over using a promise chain.","Identifier","promise",["2508"],"unicorn/no-process-exit","Only use `process.exit()` in CLI apps. Throw an error instead.","no-process-exit",["2509"],"no-control-regex","Unexpected control character(s) in regular expression: \\x00.","unexpected",["2510"],["2511"],["2512"],"unicorn/no-nested-ternary","Nested ternary expression should be parenthesized.","ConditionalExpression","should-parenthesized",{"range":"2513","text":"2514"},["2515"],"Prefer top-level await over an async function `reload` call.",["2516"],["2517"],"@typescript-eslint/no-unsafe-function-type","The `Function` type accepts any function-like value.\nPrefer explicitly defining any function parameters and return type.","bannedFunctionType",["2518"],["2519"],{"range":"2520","text":"2506"},["2521"],{"range":"2522","text":"2506"},["2523"],{"range":"2524","text":"2506"},["2525"],["2526"],"unicorn/prefer-global-this","Prefer `globalThis` over `global`.","prefer-global-this/error",{"range":"2527","text":"2528"},["2529"],{"range":"2530","text":"2528"},["2531"],{"range":"2532","text":"2528"},["2533"],{"messageId":"2534","fix":"2535","data":"2536","desc":"2537"},{"kind":"2538","justification":"2506"},{"kind":"2538","justification":"2506"},{"messageId":"2539","fix":"2540","data":"2541","desc":"2542"},{"kind":"2538","justification":"2506"},{"messageId":"2534","fix":"2543","data":"2544","desc":"2537"},{"kind":"2538","justification":"2506"},[62,72],"",{"kind":"2538","justification":"2506"},{"kind":"2538","justification":"2506"},{"kind":"2538","justification":"2506"},{"kind":"2538","justification":"2506"},{"kind":"2538","justification":"2506"},{"kind":"2538","justification":"2506"},[3173,3205],"(this.ready ? \"ready\" : \"pending\")",{"kind":"2538","justification":"2506"},{"messageId":"2534","fix":"2545","data":"2546","desc":"2537"},{"kind":"2538","justification":"2506"},{"kind":"2538","justification":"2506"},{"kind":"2538","justification":"2506"},[3539,3554],{"kind":"2538","justification":"2506"},[484,499],{"kind":"2538","justification":"2506"},[830,845],{"kind":"2538","justification":"2506"},{"kind":"2538","justification":"2506"},[256,262],"globalThis",{"kind":"2538","justification":"2506"},[372,378],{"kind":"2538","justification":"2506"},[498,504],{"kind":"2538","justification":"2506"},"add-await",{"range":"2547","text":"2548"},{"name":"2549"},"Insert `await`.","directive","text-encoding-identifier/suggestion",{"range":"2550","text":"2551"},{"value":"2552","replacement":"2551"},"Replace `UTF-8` with `utf-8`.",{"range":"2553","text":"2548"},{"name":"2549"},{"range":"2554","text":"2548"},{"name":"2555"},[4351,4351],"await ","main",[530,535],"utf-8","UTF-8",[414,414],[4829,4829],"reload"] \ No newline at end of file diff --git a/.github/agents/maintainer.agent.md b/.github/agents/maintainer.agent.md new file mode 100644 index 0000000000..ab425ccd0c --- /dev/null +++ b/.github/agents/maintainer.agent.md @@ -0,0 +1,31 @@ +--- +name: Maintainer +description: > + Nitro project maintainer agent. Handles bug fixes, feature implementation, + code review, and contributions following project conventions. Understands the + build system, runtime constraints, deployment presets, and testing strategy. +tools: + - "*" +--- + +You are a maintainer of the Nitro project. Follow all instructions in [AGENTS.md](../../AGENTS.md) strictly. + +For deeper architectural context, refer to the `.agents/` directory: + +- `.agents/architecture.md` — Core architecture, build system, config resolution, virtual modules, runtime internals. +- `.agents/presets.md` — Deployment presets, preset structure, resolution logic. +- `.agents/testing.md` — Test structure, adding regression tests, running tests. +- `.agents/vite.md` — Vite build system, plugin architecture, dev server, HMR. +- `.agents/docs.md` — Documentation conventions, H3 v2 API patterns. + +H3 v2 docs are at `node_modules/h3/skills/h3/docs/TOC.md`. + +## Key principles + +- Prefer minimal, targeted changes over large refactors. +- Code in `src/runtime/` must be runtime-agnostic (Web APIs, no Node.js-specific APIs). +- Use `pathe` instead of `node:path`. +- Use existing UnJS utilities (`defu`, `consola`, `unstorage`) before adding new packages. +- Bug fixes MUST include a failing regression test first. +- Always run `pnpm format` and `pnpm typecheck` after changes. +- Use semantic commit messages with scope (e.g., `fix(runtime): ...`). diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000000..af4dc1827c --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,3 @@ +@../AGENTS.md + +Refer to [AGENTS.md](../AGENTS.md) for project instructions. diff --git a/.github/workflows-disabled/codeql.yml b/.github/workflows-disabled/codeql.yml deleted file mode 100644 index f14400d427..0000000000 --- a/.github/workflows-disabled/codeql.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: "CodeQL" - -on: - push: - branches: ["main"] - pull_request: - branches: ["main"] - -jobs: - analyze: - name: Analyze - runs-on: "ubuntu-latest" - timeout-minutes: 360 - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: "javascript" - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 - with: - category: "/language:javascript" diff --git a/.github/workflows/autofix.yml b/.github/workflows/autofix.yml index 9a131bb5ae..187f8a0eac 100644 --- a/.github/workflows/autofix.yml +++ b/.github/workflows/autofix.yml @@ -3,7 +3,8 @@ name: autofix.ci # needed to securely identify the workflow on: pull_request: push: - branches: ["main"] + branches: + - main permissions: contents: read @@ -11,18 +12,19 @@ permissions: jobs: autofix: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - run: npm i -g --force corepack && corepack enable - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v6 with: - node-version: 22 + node-version: lts/* cache: "pnpm" - run: pnpm install - run: pnpm stub - run: pnpm gen-presets - name: Fix lint issues - run: npm run lint:fix - - uses: autofix-ci/action@ff86a557419858bb967097bfc916833f5647fa8c + run: npm run format + - uses: autofix-ci/action@7a166d7532b277f34e16238930461bf77f9d7ed8 with: commit-message: "chore: apply automated updates" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8c2e865b82..9096df2dbe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,66 +1,106 @@ name: ci on: - push: - branches: - - v2 - pull_request: - branches: - - v2 + push: { branches: [main] } + pull_request: { branches: [main] } jobs: - lint: - runs-on: ubuntu-latest + tests-checks: + runs-on: ${{ matrix.os }} + timeout-minutes: 10 + strategy: + matrix: + os: [ubuntu-latest] + steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 + - uses: actions/checkout@v6 - run: npm i -g --force corepack && corepack enable - - uses: actions/setup-node@v4 - with: - node-version: 22 - cache: pnpm + - uses: actions/setup-node@v6 + with: { node-version: lts/*, cache: pnpm } - run: pnpm install - - run: pnpm stub - - run: pnpm lint - - ci: + - run: pnpm stub && pnpm lint + - run: pnpm typecheck + - run: pnpm vitest run test/unit + - run: pnpm vitest run test/minimal + tests-rollup: runs-on: ${{ matrix.os }} + timeout-minutes: 10 strategy: matrix: os: [ubuntu-latest, windows-latest] steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 + - uses: actions/checkout@v6 - run: npm i -g --force corepack && corepack enable - - uses: actions/setup-node@v4 - with: - node-version: 22 - cache: pnpm + - uses: actions/setup-node@v6 + with: { node-version: lts/*, cache: pnpm } - uses: oven-sh/setup-bun@v2 if: ${{ matrix.os != 'windows-latest' }} - with: - bun-version: latest + with: { bun-version: latest } - uses: denoland/setup-deno@v1 if: ${{ matrix.os != 'windows-latest' }} - with: - deno-version: v2.x + with: { deno-version: 2.7.4 } + - run: node scripts/vite7.ts - run: pnpm install - - run: pnpm test:types + - run: pnpm stub && pnpm lint + if: ${{ matrix.os != 'windows-latest' }} + - run: pnpm build + - run: pnpm vitest run test/examples + env: { NITRO_BUILDER: rollup, NITRO_VITE_PKG: vite7 } + - run: pnpm vitest run test/presets + env: { NITRO_BUILDER: rollup, NITRO_VITE_PKG: vite7 } + + tests-rolldown: + runs-on: ${{ matrix.os }} + timeout-minutes: 10 + strategy: + matrix: + os: [ubuntu-latest, windows-latest] + + steps: + - uses: actions/checkout@v6 + - run: npm i -g --force corepack && corepack enable + - uses: actions/setup-node@v6 + with: { node-version: lts/*, cache: pnpm } + - uses: oven-sh/setup-bun@v2 if: ${{ matrix.os != 'windows-latest' }} + with: { bun-version: latest } + - uses: denoland/setup-deno@v1 + if: ${{ matrix.os != 'windows-latest' }} + with: { deno-version: 2.7.4 } + - run: pnpm install + - run: pnpm build + - run: pnpm vitest run test/examples + env: { NITRO_BUILDER: rolldown, NITRO_VITE_PKG: vite } + - run: pnpm vitest run test/presets + env: { NITRO_BUILDER: rolldown, NITRO_VITE_PKG: vite } + publish-pkg-pr-new: + runs-on: ubuntu-latest + timeout-minutes: 10 + needs: [tests-checks, tests-rollup, tests-rolldown] + steps: + - uses: actions/checkout@v6 + with: { fetch-depth: 0 } + - run: npm i -fg corepack && corepack enable + - uses: actions/setup-node@v6 + with: { node-version: lts/*, cache: "pnpm" } + - run: pnpm install + - run: pnpm build + - run: pnpm dlx pkg-pr-new publish || true + publish-nitro-nightly: + runs-on: ubuntu-latest + timeout-minutes: 10 + environment: npm-publish-nightly + permissions: { id-token: write, contents: read } + needs: [tests-checks, tests-rollup, tests-rolldown] + if: contains('refs/heads/main', github.ref) && github.event_name == 'push' + steps: + - uses: actions/checkout@v6 + with: { fetch-depth: 0 } + - run: npm i -fg corepack && corepack enable + - uses: actions/setup-node@v6 + with: { node-version: lts/*, cache: "pnpm" } + - run: pnpm install - run: pnpm build - - run: pnpm vitest --coverage - env: - NODE_OPTIONS: --experimental-vm-modules --enable-source-maps - # - uses: codecov/codecov-action@v3 - - name: Release Nightly - if: | - github.event_name == 'push' && - !contains(github.event.head_commit.message, '[skip-release]') && - !startsWith(github.event.head_commit.message, 'chore') && - !startsWith(github.event.head_commit.message, 'docs') - run: ./scripts/release-nightly.sh - env: - NODE_AUTH_TOKEN: ${{secrets.NODE_AUTH_TOKEN}} + - run: pnpm changelogen --bump -r 3.0.1 --canary nightly + - run: npm i -g npm@latest && npm publish --tag latest diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml new file mode 100644 index 0000000000..244aa86561 --- /dev/null +++ b/.github/workflows/copilot-setup-steps.yml @@ -0,0 +1,16 @@ +name: "Copilot Setup Steps" + +on: workflow_dispatch + +jobs: + copilot-setup-steps: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@v6 + - run: npm i -g --force corepack && corepack enable + - uses: actions/setup-node@v6 + with: { node-version: lts/*, cache: pnpm } + - run: pnpm install + - run: pnpm build --stub diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml new file mode 100644 index 0000000000..3f79aafeb5 --- /dev/null +++ b/.github/workflows/npm-publish.yml @@ -0,0 +1,51 @@ +name: npm-publish + +on: + push: + tags: + - "v*" + +permissions: {} + +jobs: + publish: + name: Publish to npm + runs-on: ubuntu-latest + if: github.repository == 'nitrojs/nitro' + timeout-minutes: 30 + environment: npm-publish + permissions: + contents: write + id-token: write + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + + - run: npm i -g --force corepack && corepack enable + + - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 + with: + node-version: lts/* + cache: pnpm + registry-url: https://registry.npmjs.org + + - run: pnpm install + - run: pnpm build + - run: pnpm lint + - run: pnpm typecheck + - run: pnpm test:rolldown + + - name: Publish to npm with provenance + # Uses OIDC trusted publishing — no NPM_TOKEN needed. + run: npm publish --provenance --access public --tag latest + + - name: Create GitHub Release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAG: ${{ github.ref_name }} + run: | + gh release create "$TAG" \ + --notes "$(pnpm changelogen --from=$(git describe --tags --abbrev=0 "$TAG^"))" \ + --title "$TAG" diff --git a/.gitignore b/.gitignore index 92973ce2bf..5bea3c68b3 100644 --- a/.gitignore +++ b/.gitignore @@ -68,7 +68,6 @@ Temporary Items .vercel .amplify-hosting staticwebapp.config.json -.eslintcache playground/firebase.json .zeabur .apphosting @@ -79,9 +78,6 @@ test/fixture/functions .pnpm-store .wrangler -# mirror pkg -.mirror - -# Generated types -*.d.ts -!runtime-meta.d.ts +CHANGELOG.md +RELEASE_NOTES.md +skills/nitro/docs diff --git a/.npmrc b/.npmrc deleted file mode 100644 index 7969496369..0000000000 --- a/.npmrc +++ /dev/null @@ -1,2 +0,0 @@ -ignore-workspace-root-check=true -shell-emulator=true diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000000..b009dfb9d9 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +lts/* diff --git a/.oxfmtrc.json b/.oxfmtrc.json new file mode 100644 index 0000000000..56771a53fc --- /dev/null +++ b/.oxfmtrc.json @@ -0,0 +1,5 @@ +{ + "$schema": "./node_modules/oxfmt/configuration_schema.json", + "trailingComma": "es5", + "ignorePatterns": ["*.md", "pnpm*.yaml", "**/*.gen.ts", "**/.docs", "**/dist/**"] +} diff --git a/.oxlintrc.json b/.oxlintrc.json new file mode 100644 index 0000000000..f16f730f66 --- /dev/null +++ b/.oxlintrc.json @@ -0,0 +1,13 @@ +{ + "$schema": "./node_modules/oxlint/configuration_schema.json", + "plugins": ["unicorn", "typescript", "oxc"], + "rules": { + "no-control-regex": "off", + "no-unused-expressions": "off", + "no-unused-vars": "off", + "typescript/no-useless-empty-export": "off", + "unicorn/no-empty-file": "off", + "unicorn/no-invalid-fetch-options": "off", + "unicorn/no-useless-spread": "off" + } +} diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index a1671b6e4f..0000000000 --- a/.prettierignore +++ /dev/null @@ -1,6 +0,0 @@ -*.md -**/*.gen.ts -node_modules -pnpm-lock.yaml -**/.docs -**/dist/** diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 757fd64caa..0000000000 --- a/.prettierrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "trailingComma": "es5" -} diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..9f3eb3d6f0 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,168 @@ +## Project Identity + +Nitro is a framework-agnostic and deployment-agnostic server framework powered by [H3](https://github.com/h3js/h3) (v2), [UnJS] (https://github.com/unjs), and Vite | Rolldown | Rollup. + +## First-time Setup for Development + +- Run `corepack enable` to ensure `pnpm` is available. +- Run `pnpm install` to install dependencies. +- Run `pnpm build --stub` to prepare development mode. + +## Key Scripts + +- `pnpm build --stub` — Fast stub build for development. +- `pnpm lint` — Lint and format code. +- `pnpm format` — Automatically fix lint and formatting issues. +- `pnpm test` — Run all tests. +- `pnpm typecheck` — Run type tests. + +**Always run** `pnpm format` and `pnpm typecheck` after making changes. + +## Repository Structure + +- `.github/` — GitHub Actions workflows. +- `docs/` — Documentation site built with [UnDocs](https://github.com/unjs/undocs). +- `examples/` — Example projects and integrations. +- `src/` — Project source code. +- `test/` — Unit, minimal, and end-to-end tests. + +### Code Structure + +Project source is centralized under `src/`: + +- `src/build` — Build logic (Vite | Rolldown | Rollup config, virtual templates, plugins). +- `src/cli` — `nitro` CLI subcommands (each file in `src/cli/commands` is a command). +- `src/config/` — Config defaults (`src/config/defaults.ts`) and resolvers/normalizers (`src/config/resolvers`). +- `src/dev` and `src/runner` — Development server logic. +- `src/prerender` — Prerender logic. +- `src/presets` — Deployment presets and runtime entry. +- `src/types` — Shared types. +- `src/utils` — Internal utilities. +- `src/runtime` — Runtime code that goes into the bundle (runtime and platform agnostic). + +### Why Changes in `src/` Are High-Impact + +Code in `src/` affects all Nitro users: + +- Changes in `src/runtime` are bundled and run across all deployment targets. +- Changes in `src/build` affect build output and performance. +- Changes in `src/presets` affect specific deployment platforms. +- Changes in `src/config` affect default behavior. + +Review these changes carefully for backwards compatibility, bundle size, and cross-runtime support. + +## Code Patterns & Conventions + +- `pathe` — Cross-platform path operations (always prefer over `node:path`). +- `defu` — Deep object merging and config defaults. +- `consola` — Logging in build/dev code (use `nitro.logger` when available). +- `unstorage` — Storage abstraction. + +### Runtime Constraints + +Code in `src/runtime/` must be runtime-agnostic: + +- **Don't use Node.js-specific APIs** (unless behind runtime checks). +- Prefer **Web APIs** (fetch, Request, Response, URL, etc.). +- Only use `console` for logging (no `consola` in runtime). +- Keep bundle size minimal and side-effect free. + +## Testing Strategy + +### Test Structure + +Main tests are defined in `test/tests.ts` and setup per each deployment provider in `test/presets` and run against `test/fixture` nitro app. Add new regression tests to `test/fixture`. + +Other tests: + +- **Unit** (`test/unit/`) — Isolated unit tests. +- **Minimal** (`test/minimal/`) — Smallest bundle output. + +### Testing Requirements + +- Run `pnpm run test` before submitting. +- **Bug fixes MUST include a failing test first** — add regression tests to `test/fixture/` and make sure test script fails before attempting the fix and resolves after. +- Keep tests deterministic and environment-independent. + +## Working with Presets + +Each preset in `src/presets/` defines deployment target behavior: + +- Runtime logic and entry is in `src/presets//runtime` +- Preset config and utils (build time) are in `src/presets//*.ts`. + +## Development Workflow + +### Making Changes + +1. Make changes in `src/`. +2. Run `pnpm build --stub` if you changed build logic. +3. Test with `pnpm test`. +4. Run `pnpm format`. +5. Run `pnpm typecheck`. +6. Run `pnpm vitest run`. + +## Contribution Principles + +- Prefer **minimal, targeted changes** over large refactors. +- Avoid introducing new dependencies unless strictly necessary. + Add them to `devDependencies` unless they are required in runtime logic. +- Be mindful of **bundle size**, startup cost, and runtime overhead. +- Maintain **backwards compatibility** unless explicitly instructed otherwise. +- Batch multiple related edits together. Avoid sequential micro-changes. +- Never modify files outside the scope of the requested change. + +## Common Gotchas + +- **Don't use Node.js-specific APIs in `src/runtime/`** — Code runs in multiple runtimes (Node, workers, edge). +- **Virtual modules must be registered** in `src/build/virtual.ts`. +- **CLI commands** are in `src/cli/commands/` — Each file exports a command definition. +- **Runtime size matters** — Check bundle impact with `pnpm build`. +- **Use `pathe` not `node:path`** — Ensures cross-platform compatibility. + +## Error & Logging Guidelines + +- Prefer explicit errors over silent failures. +- Use `nitro.logger` in build/dev code, `consola` as fallback. +- Use `console` only in `src/runtime/` code. +- Use warnings for recoverable situations; throw for invalid states. +- Include actionable context in error messages. + +## Documentation Requirements + +- Update `docs/` for user-facing changes. +- Update types and JSDoc for API changes. +- Examples in `examples/` should reflect best practices and be added for new integrations. +- Add migration notes for breaking changes. + +## Code Conventions + +- Use **ESM** and modern JavaScript; use explicit extensions (`.ts`, `.mjs`) in imports. +- For `.json` imports, use `with { "type": "json" }`. +- Avoid barrel files (`index.ts` re-exports); import directly from specific modules. +- Place non-exported/internal helpers at the end of the file. +- For multi-arg functions, use an options object as the second parameter. +- Split logic across files; avoid long single-file modules (>200 LoC). Use `_*` prefix for internal files. +- Prefer **Web APIs** over Node.js APIs where possible. +- Do not add comments explaining what the line does unless prompted. +- Before adding new code, study surrounding patterns, naming conventions, and architectural decisions. +- Use existing UnJS utilities and dependencies before adding new packages. +- Keep runtime code minimal and fast. + +## Commit Conventions + +- Use **semantic commit messages**, lower-case (e.g., `fix(cli): resolve path issue`). +- Prefer to include scope (e.g., `feat(runtime):`, `fix(build):`). +- Add a short description on the second line when helpful. + +## Detailed References + +For deeper context, see `.agents/`: + +- [`.agents/architecture.md`](.agents/architecture.md) — Full architecture: core instance, build system, config resolution, virtual modules, runtime internals, dev server, routing, key libraries. +- [`.agents/presets.md`](.agents/presets.md) — All 31 presets, preset structure, how to create presets, resolution logic. +- [`.agents/testing.md`](.agents/testing.md) — Test structure, how tests work, adding regression tests, running tests. +- [`.agents/vite.md`](.agents/vite.md) — Vite build system: plugin architecture (6 sub-plugins), environments API, dev server integration, production build stages, bundler config, HMR, runtime worker. +- [`.agents/docs.md`](.agents/docs.md) — Documentation conventions: structure, preset naming (underscore), H3 v2 API patterns, import paths, common mistakes. + +- **Important:** H3 v2 updated docs is at `node_modules/h3/skills/h3/docs/TOC.md` diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 66ccae3a80..0000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,3268 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. - -## v2.11.6 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.11.5...v2.11.6) - -### 🩹 Fixes - -- Update enenv and cloudflare node compat ([#3187](https://github.com/nitrojs/nitro/pull/3187)) -- **dev:** Use port for bun on windows ([#3188](https://github.com/nitrojs/nitro/pull/3188)) - -### 💅 Refactors - -- Remove extra space in logs ([#3181](https://github.com/nitrojs/nitro/pull/3181)) -- Remove dependency on unenv mock utils ([#3186](https://github.com/nitrojs/nitro/pull/3186)) - -### 📖 Documentation - -- **deploy:** Add warning about turborepo and zero config ([#3182](https://github.com/nitrojs/nitro/pull/3182)) -- **vercel:** Typo ([#3183](https://github.com/nitrojs/nitro/pull/3183)) -- **fetch:** Fix grammar ([#3184](https://github.com/nitrojs/nitro/pull/3184)) - -### 🏡 Chore - -- **release:** V2.11.5 ([8099ed86](https://github.com/nitrojs/nitro/commit/8099ed86)) -- Remove unused file ([8de0e8f3](https://github.com/nitrojs/nitro/commit/8de0e8f3)) -- Update minor dependencies and lock ([75d0d826](https://github.com/nitrojs/nitro/commit/75d0d826)) -- Update lock ([c2f8d066](https://github.com/nitrojs/nitro/commit/c2f8d066)) -- Update unenv ([b26d2b5a](https://github.com/nitrojs/nitro/commit/b26d2b5a)) - -### ✅ Tests - -- Update cloudflare-module ([0f3e4a3b](https://github.com/nitrojs/nitro/commit/0f3e4a3b)) - -### ❤️ Contributors - -- Pooya Parsa ([@pi0](https://github.com/pi0)) -- Nandesora Tjihero ([@Ombuweb](https://github.com/Ombuweb)) -- @beer ([@iiio2](https://github.com/iiio2)) -- Connor Roberts ([@murshex](https://github.com/murshex)) -- Restent Ou ([@gxres042](https://github.com/gxres042)) - -## v2.11.5 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.11.4...v2.11.5) - -### 🩹 Fixes - -- **dev:** Use abstract sockets on linux with node.js >=20 ([#3178](https://github.com/nitrojs/nitro/pull/3178)) -- **dev:** Use os tmp dir for unix sockets ([#3179](https://github.com/nitrojs/nitro/pull/3179)) - -### 📦 Build - -- Use upstream `youch` back ([#3175](https://github.com/nitrojs/nitro/pull/3175)) - -### 🌊 Types - -- Mark `$global` optional for `NitroRouteMeta` ([#3174](https://github.com/nitrojs/nitro/pull/3174)) - -### ❤️ Contributors - -- Pooya Parsa -- Léo Pradel - -## v2.11.4 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.11.3...v2.11.4) - -### 🩹 Fixes - -- **dev:** Auto fallback to port if socket listening failed ([#3165](https://github.com/nitrojs/nitro/pull/3165)) -- **dev:** Polyfill `globalThis.crypto` for Node.js 18 ([#3166](https://github.com/nitrojs/nitro/pull/3166)) -- **cli:** Add `globalThis.crypto` polyfill for Node.js 18 ([#3167](https://github.com/nitrojs/nitro/pull/3167)) -- **dev:** Polyfill `globalThis.crypto` for Node.js 18 ([#3168](https://github.com/nitrojs/nitro/pull/3168)) -- **dev:** Try normal socket for CI ([a4569493](https://github.com/nitrojs/nitro/commit/a4569493)) - -### 📦 Build - -- Inline youch dependency ([#3169](https://github.com/nitrojs/nitro/pull/3169)) -- Use `youch-redist` ([#3172](https://github.com/nitrojs/nitro/pull/3172)) - -### ❤️ Contributors - -- Pooya Parsa ([@pi0](https://github.com/pi0)) - -## v2.11.3 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.11.2...v2.11.3) - -### 🩹 Fixes - -- **cloudflare:** Support `wrangler.jsonc` ([#3162](https://github.com/nitrojs/nitro/pull/3162)) - -### 💅 Refactors - -- Expose default error to custom handler ([#3161](https://github.com/nitrojs/nitro/pull/3161)) -- **dev:** Only show force close warn in debug mode ([06147e7a](https://github.com/nitrojs/nitro/commit/06147e7a)) - -### 🏡 Chore - -- **release:** V2.11.2 ([e21ce69d](https://github.com/nitrojs/nitro/commit/e21ce69d)) -- Update devcontainer config ([92f1a37a](https://github.com/nitrojs/nitro/commit/92f1a37a)) -- Lowercase header ([e3866d04](https://github.com/nitrojs/nitro/commit/e3866d04)) - -### ❤️ Contributors - -- Pooya Parsa ([@pi0](https://github.com/pi0)) - -## v2.11.2 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.11.1...v2.11.2) - -### 🩹 Fixes - -- **prerender:** Ignore prefixed public assets ([#3093](https://github.com/nitrojs/nitro/pull/3093)) -- **dev:** Mark event as handled before sending proxy ([058819aa](https://github.com/nitrojs/nitro/commit/058819aa)) -- **dev:** Force close server immediately in test and ci ([97ed879a](https://github.com/nitrojs/nitro/commit/97ed879a)) -- **dev:** Close all connections when reloading ([5b5e10e7](https://github.com/nitrojs/nitro/commit/5b5e10e7)) -- **config:** Respect config overrides for defaults ([#3158](https://github.com/nitrojs/nitro/pull/3158)) - -### 💅 Refactors - -- Move handled set to proxy util ([67c396ba](https://github.com/nitrojs/nitro/commit/67c396ba)) - -### 🏡 Chore - -- **release:** V2.11.1 ([cd3b8724](https://github.com/nitrojs/nitro/commit/cd3b8724)) -- Update deps ([53da847b](https://github.com/nitrojs/nitro/commit/53da847b)) - -### ❤️ Contributors - -- Pooya Parsa ([@pi0](https://github.com/pi0)) -- Daniel Roe ([@danielroe](https://github.com/danielroe)) - -## v2.11.1 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.11.0...v2.11.1) - -### 🩹 Fixes - -- **dev:** Use full socket path for windows and linux ([#3152](https://github.com/nitrojs/nitro/pull/3152)) -- **dev:** Add random number to socket name ([#3153](https://github.com/nitrojs/nitro/pull/3153)) -- **dev:** Limit `/_vfs` to local ips only ([#3154](https://github.com/nitrojs/nitro/pull/3154)) -- **app:** Update `event` before calling `request` hook ([#3155](https://github.com/nitrojs/nitro/pull/3155)) - -### ❤️ Contributors - -- Balázs Németh ([@zsilbi](https://github.com/zsilbi)) -- Pooya Parsa - -## v2.11.0 - -Check [release notes](https://github.com/nitrojs/nitro/releases/tag/v2.11.0) - -## v2.10.4 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.10.3...v2.10.4) - -### 🔥 Performance - -- **raw:** Avoid extra `this.resolve` when possible ([#2857](https://github.com/nitrojs/nitro/pull/2857)) - -### 📖 Documentation - -- **config:** Tiny typos ([#2859](https://github.com/nitrojs/nitro/pull/2859)) - -### 🏡 Chore - -- Remove extra `NODE_OPTIONS` from scripts ([50ff48a6](https://github.com/nitrojs/nitro/commit/50ff48a6)) -- Update ci script ([f9c269fb](https://github.com/nitrojs/nitro/commit/f9c269fb)) - -### ✅ Tests - -- Add tests for #2838, #2836 ([#2838](https://github.com/nitrojs/nitro/issues/2838), [#2836](https://github.com/nitrojs/nitro/issues/2836)) -- Fix windows issue ([924eaa52](https://github.com/nitrojs/nitro/commit/924eaa52)) -- Enable dev tests on ci ([#2858](https://github.com/nitrojs/nitro/pull/2858)) - -### ❤️ Contributors - -- @beer ([@iiio2](http://github.com/iiio2)) -- Pooya Parsa ([@pi0](http://github.com/pi0)) -- Arkadiusz Sygulski - -## v2.10.3 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.10.2...v2.10.3) - -### 🩹 Fixes - -- Allow adding custom `Vary` to static assets handler ([#2835](https://github.com/nitrojs/nitro/pull/2835)) -- **netlify:** Only include env polyfill in `netlify-edge` ([#2851](https://github.com/nitrojs/nitro/pull/2851)) -- Scan env specific handlers without method in their name ([#2852](https://github.com/nitrojs/nitro/pull/2852)) -- **config:** Add back default storage mounts ([#2853](https://github.com/nitrojs/nitro/pull/2853)) - -### 📖 Documentation - -- **cloudflare:** Fix typo ([#2849](https://github.com/nitrojs/nitro/pull/2849)) - -### 🌊 Types - -- **cache:** Resolved value is not nullable ([#2848](https://github.com/nitrojs/nitro/pull/2848)) - -### ❤️ Contributors - -- Pooya Parsa -- Sandro Circi ([@sandros94](http://github.com/sandros94)) -- Jaga Santagostino -- Philippe Serhal -- Danila Rodichkin ([@daniluk4000](http://github.com/daniluk4000)) - -## v2.10.2 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.10.1...v2.10.2) - -### 🩹 Fixes - -- **rollup:** Pass options to `resolve` ([#2842](https://github.com/nitrojs/nitro/pull/2842)) - -### 📖 Documentation - -- **cloudflare:** Update `cloudflare-module` ([#2831](https://github.com/nitrojs/nitro/pull/2831)) -- Update nightly and experimental banners ([9ff37139](https://github.com/nitrojs/nitro/commit/9ff37139)) - -### ❤️ Contributors - -- Pooya Parsa ([@pi0](http://github.com/pi0)) -- Restent Ou ([@gxres042](http://github.com/gxres042)) - -## v2.10.1 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.10.0...v2.10.1) - -### 🩹 Fixes - -- **imports:** Use explicit import for `useDatabase` ([#2837](https://github.com/nitrojs/nitro/pull/2837)) -- **rollup:** Check raw extensions against resolved id ([#2838](https://github.com/nitrojs/nitro/pull/2838)) -- **imports:** Use explicit imports ([#2839](https://github.com/nitrojs/nitro/pull/2839)) -- Update `node_cluster` entry name ([#2840](https://github.com/nitrojs/nitro/pull/2840)) - -### ❤️ Contributors - -- Pooya Parsa ([@pi0](http://github.com/pi0)) - -## v2.10.0 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.9.6...v2.10.0) - -### 🚀 Enhancements - -- Generate types for runtime config ([#2306](https://github.com/nitrojs/nitro/pull/2306)) -- **serverAssets:** Support `ignore` option ([#2302](https://github.com/nitrojs/nitro/pull/2302)) -- Expose `getRouteRulesForPath` from nitro runtime ([#2238](https://github.com/nitrojs/nitro/pull/2238)) -- **openapi:** Support configuration via `openapi` ([#2299](https://github.com/nitrojs/nitro/pull/2299)) -- Environment specific event handlers ([#2272](https://github.com/nitrojs/nitro/pull/2272)) -- Experimental `defineRouteMeta` ([#2102](https://github.com/nitrojs/nitro/pull/2102)) -- **cloudflare-pages:** Generate `wrangler.toml` ([#2353](https://github.com/nitrojs/nitro/pull/2353)) -- Allow customizing `apiBaseURL`, `apiDir` and `routesDir` ([#1763](https://github.com/nitrojs/nitro/pull/1763)) -- **aws-lambda:** Experimental streaming support ([#2412](https://github.com/nitrojs/nitro/pull/2412)) -- **providers:** Add `gitlab-pages` static provider ([#2420](https://github.com/nitrojs/nitro/pull/2420)) -- **netlify:** Experimental support v2 functions ISR via targeted cache-control headers ([#2406](https://github.com/nitrojs/nitro/pull/2406)) -- Add compatibility date support ([#2511](https://github.com/nitrojs/nitro/pull/2511)) -- **cloudflare-module:** Support `cloudflare:email` and `cloudflare:queue` hooks ([#2487](https://github.com/nitrojs/nitro/pull/2487)) -- **defineCachedEventHandler:** Add `event.context.cache` ([#2519](https://github.com/nitrojs/nitro/pull/2519)) -- **core:** Warn if runtime config is not serializable ([#2542](https://github.com/nitrojs/nitro/pull/2542)) -- **netlify:** Use new `durable` cache-control directive for `isr` rule ([#2571](https://github.com/nitrojs/nitro/pull/2571)) -- **open-api:** Production mode ([#2570](https://github.com/nitrojs/nitro/pull/2570)) -- **deno-server:** Use output `node_modules` for `start` task ([#2687](https://github.com/nitrojs/nitro/pull/2687)) -- Add genezio preset ([#2637](https://github.com/nitrojs/nitro/pull/2637)) -- Add zerops preset ([#2698](https://github.com/nitrojs/nitro/pull/2698)) -- **dev-server:** Redirect requsts without base url ([#2713](https://github.com/nitrojs/nitro/pull/2713)) -- **firebase:** Upgrade default runtime to node 20 ([#2654](https://github.com/nitrojs/nitro/pull/2654)) -- Upgrade to jiti v2 ([#2742](https://github.com/nitrojs/nitro/pull/2742)) -- **raw:** Add `.sql` to raw file extensions ([#2745](https://github.com/nitrojs/nitro/pull/2745)) -- **scan:** Route groups ([#2664](https://github.com/nitrojs/nitro/pull/2664)) -- **renderer:** Add `render:before` hook ([#2770](https://github.com/nitrojs/nitro/pull/2770)) -- Add pdf and wasm to compressible mime types ([#2766](https://github.com/nitrojs/nitro/pull/2766)) -- **ws:** Upgrade crossws to 0.3.x ([#2776](https://github.com/nitrojs/nitro/pull/2776)) -- **vercel:** Allow fine-grained isr config via route rules ([#2780](https://github.com/nitrojs/nitro/pull/2780)) -- Update db0 to v0.2 ([3d5216be](https://github.com/nitrojs/nitro/commit/3d5216be)) -- **cloudflare-module:** Expose all handlers as runtime hooks ([#2795](https://github.com/nitrojs/nitro/pull/2795)) -- **cloudflare-module:** Use new workers static assets ([#2800](https://github.com/nitrojs/nitro/pull/2800)) -- Experimental `cloudflare-durable` preset ([#2801](https://github.com/nitrojs/nitro/pull/2801)) -- **aws-lambda:** Add streaming support to main preset ([#2786](https://github.com/nitrojs/nitro/pull/2786)) -- Include preset config in `.output/nitro.json` ([#2807](https://github.com/nitrojs/nitro/pull/2807)) -- **cache:** Set `ttl` for native expiration (with swr disabled) ([#2783](https://github.com/nitrojs/nitro/pull/2783)) - -### 🔥 Performance - -- Limit open files in generateFSTree ([#2458](https://github.com/nitrojs/nitro/pull/2458)) -- **netlify-legacy:** Exclude static paths from server handler ([#2823](https://github.com/nitrojs/nitro/pull/2823)) -- **netlify, netlify-edge:** Exclude static paths from server handler ([#2822](https://github.com/nitrojs/nitro/pull/2822)) - -### 🩹 Fixes - -- **github-pages:** Prerender `/` by default ([#2334](https://github.com/nitrojs/nitro/pull/2334)) -- **deno-server:** Always inject `process` from `node:process` ([#2372](https://github.com/nitrojs/nitro/pull/2372)) -- **deno-server:** Explicitly remove cert/key from options if either is not set ([#2373](https://github.com/nitrojs/nitro/pull/2373)) -- Deduplicate plugins ([#2391](https://github.com/nitrojs/nitro/pull/2391)) -- **iis:** Deep merge configs ([#2358](https://github.com/nitrojs/nitro/pull/2358)) -- **externals:** Compare package paths against normalized `id` ([#2371](https://github.com/nitrojs/nitro/pull/2371)) -- **azure:** Correctly handle `maxAge` cookie option ([#2400](https://github.com/nitrojs/nitro/pull/2400)) -- Add `.tsx` and `.jsx` to `node-resolve` extensions ([#2398](https://github.com/nitrojs/nitro/pull/2398)) -- Lower-case accepted handler method ([#2382](https://github.com/nitrojs/nitro/pull/2382)) -- Set `compilerOptions.noEmit` to avoid `tsconfig.json` warning ([#2402](https://github.com/nitrojs/nitro/pull/2402)) -- **prerender:** Only try to add `/` after `prerender:routes` hook ([#2348](https://github.com/nitrojs/nitro/pull/2348)) -- **azure:** Correctly handle maxAge cookie option ([#2403](https://github.com/nitrojs/nitro/pull/2403)) -- **aws-lambda-streaming:** Fix global lambda import pointing to wrong ([#2422](https://github.com/nitrojs/nitro/pull/2422)) -- **netlify:** Match ISR route rules when path has a query string ([#2440](https://github.com/nitrojs/nitro/pull/2440)) -- **preset-iis:** Parse without `explicitArray` to allow merging `web.config` ([#2457](https://github.com/nitrojs/nitro/pull/2457)) -- Pass custom entry filename when resolving prerenderer ([#2461](https://github.com/nitrojs/nitro/pull/2461)) -- **vercel:** Support custom `baseURL` ([#2464](https://github.com/nitrojs/nitro/pull/2464)) -- Use relative paths in `nitro-config.d.ts` ([#2471](https://github.com/nitrojs/nitro/pull/2471)) -- **netlify:** Added missing quotes in utils ([#2472](https://github.com/nitrojs/nitro/pull/2472)) -- Avoid named exports from `package.json` ([e6097ed7](https://github.com/nitrojs/nitro/commit/e6097ed7)) -- **cloudflare-pages:** Remove `.html` extension from `_routes.json` ([#2498](https://github.com/nitrojs/nitro/pull/2498)) -- More compatibility for import from `nitropack/runtime/*` ([#2501](https://github.com/nitrojs/nitro/pull/2501)) -- **build:** Correctly watch custom `apiDir` and `routesDir` ([#2502](https://github.com/nitrojs/nitro/pull/2502)) -- **public-assets:** Do not shadow paths that share prefix ([#2516](https://github.com/nitrojs/nitro/pull/2516)) -- **core:** Resolve modules with esm compatibility ([#2514](https://github.com/nitrojs/nitro/pull/2514)) -- **prerender:** Extract links from explicit html routes ([#2517](https://github.com/nitrojs/nitro/pull/2517)) -- Upate `cli` preset with esm module format ([#2539](https://github.com/nitrojs/nitro/pull/2539)) -- Make sure nitro runtime goes to one chunk ([#2547](https://github.com/nitrojs/nitro/pull/2547)) -- **types:** Infer types correctly when method is omitted ([#2551](https://github.com/nitrojs/nitro/pull/2551)) -- **renderer:** Check full path for `/favicon.ico` placeholder ([#2553](https://github.com/nitrojs/nitro/pull/2553)) -- **netlify:** Ensure preview command is correct ([#2561](https://github.com/nitrojs/nitro/pull/2561)) -- Backward compatibility types for v2 ([#2563](https://github.com/nitrojs/nitro/pull/2563)) -- **handler-meta:** Check for `.name` with `undefined` value in `ObjectExpression` ([#2565](https://github.com/nitrojs/nitro/pull/2565)) -- Hide unhandled error messages in prod ([#2591](https://github.com/nitrojs/nitro/pull/2591)) -- **prerender:** Allow ignoring errors in `prerender:generate` hook ([#2610](https://github.com/nitrojs/nitro/pull/2610)) -- Only hide message of unhandled errors in prod ([#2619](https://github.com/nitrojs/nitro/pull/2619)) -- **prerender:** Skip protocol relative links ([#2661](https://github.com/nitrojs/nitro/pull/2661)) -- Ensure legacy runtime config types are populated ([#2724](https://github.com/nitrojs/nitro/pull/2724)) -- Ensure legacy hook types are populated ([#2725](https://github.com/nitrojs/nitro/pull/2725)) -- Do not generate runtime config types with external framework ([#2732](https://github.com/nitrojs/nitro/pull/2732)) -- **prerender:** Log error stack traces ([#2720](https://github.com/nitrojs/nitro/pull/2720)) -- **cache:** Use top level `function` to avoid rollup chunk ordering issues ([#2741](https://github.com/nitrojs/nitro/pull/2741)) -- **cli:** Respect custom `buildDir` option for `tasks` subcommand ([#2635](https://github.com/nitrojs/nitro/pull/2635)) -- Initialize nitro app before plugins run ([#1906](https://github.com/nitrojs/nitro/pull/1906)) -- **cloudflare-module:** Use correct types for email and queue events/hooks ([#2711](https://github.com/nitrojs/nitro/pull/2711)) -- **azure-functions:** Follow symlinks in zip bundle ([#2769](https://github.com/nitrojs/nitro/pull/2769)) -- Use jiti with `{ default: true }` for importing modules ([d77288c2](https://github.com/nitrojs/nitro/commit/d77288c2)) -- **firebase:** Validate custom `serverFunctionName` ([#2773](https://github.com/nitrojs/nitro/pull/2773)) -- Add `db0` and `std-env` to `runtimeDependencies` ([a399e189](https://github.com/nitrojs/nitro/commit/a399e189)) -- **error:** Add `cache-control: no-cache` for 404 responses ([#2793](https://github.com/nitrojs/nitro/pull/2793)) -- **renderer:** Check `ctx.response` ([7a97b0a2](https://github.com/nitrojs/nitro/commit/7a97b0a2)) -- **cache:** Catch error when getting cache entry ([#2609](https://github.com/nitrojs/nitro/pull/2609), [#2820](https://github.com/nitrojs/nitro/pull/2820)) -- **cache:** Try decode path ([#2658](https://github.com/nitrojs/nitro/pull/2658)) -- **cloudflare:** Support custom `baseURL` ([#2821](https://github.com/nitrojs/nitro/pull/2821)) -- Handle incompatible compatibility date for presets ([#2828](https://github.com/nitrojs/nitro/pull/2828)) - -### 💅 Refactors - -- **openapi:** Update swagger-ui version to v5 for OpenAPI v3.1 support ([#2343](https://github.com/nitrojs/nitro/pull/2343)) -- **cloudflare-pages:** Update root `wrangler.toml` in CI ([#2355](https://github.com/nitrojs/nitro/pull/2355)) -- Strict typechecks ([#2370](https://github.com/nitrojs/nitro/pull/2370)) -- Convert `CapturedErrorContext` to interface to allow type augmentation ([#2393](https://github.com/nitrojs/nitro/pull/2393)) -- Overhaul presets structure ([#2446](https://github.com/nitrojs/nitro/pull/2446)) -- Structure overhaul ([#2473](https://github.com/nitrojs/nitro/pull/2473)) -- Remove dependency on `/runtime/internal/*` subpaths ([#2524](https://github.com/nitrojs/nitro/pull/2524)) -- Migrate to `colors` from `consola/utils` ([#2574](https://github.com/nitrojs/nitro/pull/2574)) -- Remove `fs-extra` dependency ([#2743](https://github.com/nitrojs/nitro/pull/2743)) -- **cache:** Remove unnecessary nullish coalescing operator ([#2608](https://github.com/nitrojs/nitro/pull/2608)) -- **dev:** Attach worker reload error as `cause` ([#2651](https://github.com/nitrojs/nitro/pull/2651)) -- Improve type definitions for `CacheOptions` ([#2700](https://github.com/nitrojs/nitro/pull/2700)) -- **cloudflare-module:** Extract reusable logic ([#2799](https://github.com/nitrojs/nitro/pull/2799)) - -### 📖 Documentation - -- Remove duplicate option definition ([#2339](https://github.com/nitrojs/nitro/pull/2339)) -- **fetch:** Unexpected spaces ([#2368](https://github.com/nitrojs/nitro/pull/2368)) -- Correct env variable to `NITRO_SHUTDOWN_DISABLED` ([#2377](https://github.com/nitrojs/nitro/pull/2377)) -- **caching:** Fix typos and rephrase for clarity ([#2380](https://github.com/nitrojs/nitro/pull/2380)) -- Add a usage example for server sent events ([#2379](https://github.com/nitrojs/nitro/pull/2379)) -- Correct directory name ([#2417](https://github.com/nitrojs/nitro/pull/2417)) -- Use `npx nypm install` in instead of `npm install` ([#2421](https://github.com/nitrojs/nitro/pull/2421)) -- **websocket:** Correct nuxt sse url ([#2430](https://github.com/nitrojs/nitro/pull/2430)) -- **node:** Fix `node-listener` example ([#2456](https://github.com/nitrojs/nitro/pull/2456)) -- Prefix `NITRO_` in `.env` file ([#2486](https://github.com/nitrojs/nitro/pull/2486)) -- Fix typo autoSubFolderIndex ~> autoSubfolderIndex ([#2494](https://github.com/nitrojs/nitro/pull/2494)) -- Correct h3 docs link to `event-handler` ([#2500](https://github.com/nitrojs/nitro/pull/2500)) -- Move `await` to explicit line for clarity ([#2577](https://github.com/nitrojs/nitro/pull/2577)) -- Fix typos ([#2578](https://github.com/nitrojs/nitro/pull/2578)) -- Fix typos ([#2589](https://github.com/nitrojs/nitro/pull/2589)) -- **storage:** Add await before `setItem` ([#2588](https://github.com/nitrojs/nitro/pull/2588)) -- Convert to underscore preset names ([#2592](https://github.com/nitrojs/nitro/pull/2592)) -- Fix title format ([#2594](https://github.com/nitrojs/nitro/pull/2594)) -- **cloudflare:** Add missing `await` ([#2601](https://github.com/nitrojs/nitro/pull/2601)) -- **compressPublicAssets:** Adjust formatting ([#2603](https://github.com/nitrojs/nitro/pull/2603)) -- **routing:** Add nested example ([#2625](https://github.com/nitrojs/nitro/pull/2625)) -- Fix mdc component usage and cloudflare preset reference ([#2600](https://github.com/nitrojs/nitro/pull/2600)) -- Fix grammar ([#2669](https://github.com/nitrojs/nitro/pull/2669)) -- **server routes:** Fix typo ([#2675](https://github.com/nitrojs/nitro/pull/2675)) -- **utils:** Update github link ([#2596](https://github.com/nitrojs/nitro/pull/2596)) -- **config:** Fix url for log level ([#2699](https://github.com/nitrojs/nitro/pull/2699)) -- Remove old components ([fc6c2fae](https://github.com/nitrojs/nitro/commit/fc6c2fae)) -- **config:** Fix typos ([#2728](https://github.com/nitrojs/nitro/pull/2728)) -- **cache:** Fix code format ([#2740](https://github.com/nitrojs/nitro/pull/2740)) -- **config:** Fix typo prerender retries -> retry ([#2746](https://github.com/nitrojs/nitro/pull/2746)) -- `/_nitro/scalar` general availability ([#2754](https://github.com/nitrojs/nitro/pull/2754)) -- Notice for OpenAPI paths changing in future versions ([#2755](https://github.com/nitrojs/nitro/pull/2755)) -- **node:** Fix typo ([#2761](https://github.com/nitrojs/nitro/pull/2761)) -- **routing:** Fix grammer ([#2763](https://github.com/nitrojs/nitro/pull/2763)) -- **routing:** Add error handling section ([#2733](https://github.com/nitrojs/nitro/pull/2733)) -- **tasks:** Fix grammar ([#2768](https://github.com/nitrojs/nitro/pull/2768)) -- **server-utils:** Fix typos ([#2790](https://github.com/nitrojs/nitro/pull/2790)) -- Update reference to old radix3 link ([#2787](https://github.com/nitrojs/nitro/pull/2787)) -- **typescript:** Tiny typos ([#2805](https://github.com/nitrojs/nitro/pull/2805)) -- **server-routes:** Typo ([#2808](https://github.com/nitrojs/nitro/pull/2808)) -- Fix nitro runtime hooks link ([#2826](https://github.com/nitrojs/nitro/pull/2826)) -- Use nitro.build as canonical ([78cd3e7b](https://github.com/nitrojs/nitro/commit/78cd3e7b)) - -### 📦 Build - -- Explicitly add `nitropack` to externals (nightly) ([b2831dd5](https://github.com/nitrojs/nitro/commit/b2831dd5)) -- Load presets from unbundled `nitropack/presets` ([#2459](https://github.com/nitrojs/nitro/pull/2459)) -- Update unbuild to 3.x ([c95dae55](https://github.com/nitrojs/nitro/commit/c95dae55)) -- Introduce `nitropack/meta` ([ca2282bb](https://github.com/nitrojs/nitro/commit/ca2282bb)) -- Improve chunk names ([4106750c](https://github.com/nitrojs/nitro/commit/4106750c)) -- Hotfix unbuild to resolve jiti stub await issue ([01128017](https://github.com/nitrojs/nitro/commit/01128017)) -- Mirror `nitro` and `nitropack` npm packages ([#2497](https://github.com/nitrojs/nitro/pull/2497)) - -### 🌊 Types - -- **firebase:** Support `22` for `nodeVersion` ([#2653](https://github.com/nitrojs/nitro/pull/2653)) - -### 🏡 Chore - -- **release:** V2.9.6 ([6f159205](https://github.com/nitrojs/nitro/commit/6f159205)) -- **docs:** Update lockfile ([7bfe4449](https://github.com/nitrojs/nitro/commit/7bfe4449)) -- Update deps ([b444f173](https://github.com/nitrojs/nitro/commit/b444f173)) -- Lint and migrate to eslint flat config ([#2352](https://github.com/nitrojs/nitro/pull/2352)) -- **cf-pages:** Only create wrangler.toml if config is not empty ([#2356](https://github.com/nitrojs/nitro/pull/2356)) -- Update deps ([8add14c7](https://github.com/nitrojs/nitro/commit/8add14c7)) -- Fix typos ([#2386](https://github.com/nitrojs/nitro/pull/2386)) -- Update eslint preset ([78ec24d1](https://github.com/nitrojs/nitro/commit/78ec24d1)) -- Update deps ([ad100f49](https://github.com/nitrojs/nitro/commit/ad100f49)) -- Format ([f95c4f53](https://github.com/nitrojs/nitro/commit/f95c4f53)) -- Update lockfile ([a14b1532](https://github.com/nitrojs/nitro/commit/a14b1532)) -- Disable flaky db test on windows ([ececd699](https://github.com/nitrojs/nitro/commit/ececd699)) -- Update deps and lockfile ([9642ef6c](https://github.com/nitrojs/nitro/commit/9642ef6c)) -- Update eslint and biome ([00097738](https://github.com/nitrojs/nitro/commit/00097738)) -- Ignore biome formatting `package.json` ([fe5da142](https://github.com/nitrojs/nitro/commit/fe5da142)) -- Update dependencies ([1fae1ce3](https://github.com/nitrojs/nitro/commit/1fae1ce3)) -- Update `@rollup/plugin-commonjs` ([eeae2262](https://github.com/nitrojs/nitro/commit/eeae2262)) -- Update `config.d.ts` ([0083c104](https://github.com/nitrojs/nitro/commit/0083c104)) -- Add compatibilityDate to fixture ([ced80b21](https://github.com/nitrojs/nitro/commit/ced80b21)) -- **playground:** Does not overwrite `tsconfig.paths` ([#2507](https://github.com/nitrojs/nitro/pull/2507)) -- Add missing `magicast` dep ([c84f676d](https://github.com/nitrojs/nitro/commit/c84f676d)) -- Update ci node version to 20 ([09c8267c](https://github.com/nitrojs/nitro/commit/09c8267c)) -- Prepare v2 branch ([d549634e](https://github.com/nitrojs/nitro/commit/d549634e)) -- Lint with biome ([#2525](https://github.com/nitrojs/nitro/pull/2525)) -- Improve internal `tsconfig.json` ([#2529](https://github.com/nitrojs/nitro/pull/2529)) -- Remove unused dependency `is-primitive` ([#2556](https://github.com/nitrojs/nitro/pull/2556)) -- Fix typegen script ([a4abb222](https://github.com/nitrojs/nitro/commit/a4abb222)) -- Remove extra space in banner ([#2573](https://github.com/nitrojs/nitro/pull/2573)) -- Update deps and lockfile ([c7435f07](https://github.com/nitrojs/nitro/commit/c7435f07)) -- Fix types ([2298d246](https://github.com/nitrojs/nitro/commit/2298d246)) -- Update tests ([3594a189](https://github.com/nitrojs/nitro/commit/3594a189)) -- Update undocs ([b37875ac](https://github.com/nitrojs/nitro/commit/b37875ac)) -- Update undocs ([7d9619fd](https://github.com/nitrojs/nitro/commit/7d9619fd)) -- Update non-major dependencies ([bb8c2071](https://github.com/nitrojs/nitro/commit/bb8c2071)) -- Fix type issues ([2615d392](https://github.com/nitrojs/nitro/commit/2615d392)) -- **renovate:** Ignore crossws ([95095fb3](https://github.com/nitrojs/nitro/commit/95095fb3)) -- Update to jiti 2.0.0 ([cb3fe58d](https://github.com/nitrojs/nitro/commit/cb3fe58d)) -- Update unbuild ([60502e4e](https://github.com/nitrojs/nitro/commit/60502e4e)) -- Add `compatibilityDate` for playground ([2c404995](https://github.com/nitrojs/nitro/commit/2c404995)) -- Update deps ([9092e2e2](https://github.com/nitrojs/nitro/commit/9092e2e2)) -- Add codeowners file ([1709b16c](https://github.com/nitrojs/nitro/commit/1709b16c)) -- Add `compatibilityDate` to all config files ([f70b03c6](https://github.com/nitrojs/nitro/commit/f70b03c6)) -- Lint ([811511ef](https://github.com/nitrojs/nitro/commit/811511ef)) -- Enable `interopDefault` for stub mode ([69b05a5e](https://github.com/nitrojs/nitro/commit/69b05a5e)) -- Update undocs ([062a2214](https://github.com/nitrojs/nitro/commit/062a2214)) -- Update jiti and deps ([817518bd](https://github.com/nitrojs/nitro/commit/817518bd)) -- Update deps ([12d3723a](https://github.com/nitrojs/nitro/commit/12d3723a)) -- Update deps ([e874c4ca](https://github.com/nitrojs/nitro/commit/e874c4ca)) -- Update deps ([313eac90](https://github.com/nitrojs/nitro/commit/313eac90)) -- **examples:** Clarify post handler ([#2781](https://github.com/nitrojs/nitro/pull/2781)) -- Update deps ([92519e02](https://github.com/nitrojs/nitro/commit/92519e02)) -- Update deps ([9d483939](https://github.com/nitrojs/nitro/commit/9d483939)) -- **examples:** Provide `event` in `defineEventHandler` function ([#2788](https://github.com/nitrojs/nitro/pull/2788)) -- **devcontainer:** Update node.js to v22 ([#2817](https://github.com/nitrojs/nitro/pull/2817)) -- **examples:** Change name in package.json ([#2816](https://github.com/nitrojs/nitro/pull/2816)) -- Update deps ([642c1009](https://github.com/nitrojs/nitro/commit/642c1009)) -- Update croner to v9 ([cffb3cd4](https://github.com/nitrojs/nitro/commit/cffb3cd4)) -- Remove unused `mri` dependency ([#2825](https://github.com/nitrojs/nitro/pull/2825)) -- Update deps ([32a4f867](https://github.com/nitrojs/nitro/commit/32a4f867)) -- Update nitro org ([9b02f572](https://github.com/nitrojs/nitro/commit/9b02f572)) - -### ✅ Tests - -- Avoid `toMatchInlineSnapshot` in shared tests ([966b3518](https://github.com/nitrojs/nitro/commit/966b3518)) - -### 🎨 Styles - -- Try biome formatter ([#2401](https://github.com/nitrojs/nitro/pull/2401)) -- Use prettier ([710765ea](https://github.com/nitrojs/nitro/commit/710765ea)) - -### 🤖 CI - -- Make nightly versions human readable ([37f0d4f4](https://github.com/nitrojs/nitro/commit/37f0d4f4)) - -### ❤️ Contributors - -- Pooya Parsa ([@pi0](http://github.com/pi0)) -- @beer ([@iiio2](http://github.com/iiio2)) -- Alexander ([@hywax](http://github.com/hywax)) -- Sébastien Chopin ([@atinux](http://github.com/atinux)) -- Connor Pearson ([@cjpearson](http://github.com/cjpearson)) -- Philippe Serhal -- Dax -- Dawit ([@oneminch](http://github.com/oneminch)) -- João Carmona ([@jpsc](http://github.com/jpsc)) -- Aarvin Roshin -- Jan-Henrik Damaschke -- Marvin ([@marvin-j97](http://github.com/marvin-j97)) -- Timur ([@Rewwoken](http://github.com/Rewwoken)) -- Horváth Bálint ([@horvbalint](http://github.com/horvbalint)) -- Horu ([@HigherOrderLogic](http://github.com/HigherOrderLogic)) -- Balázs Németh ([@zsilbi](http://github.com/zsilbi)) -- Yoones Khoshghadam -- Gautier Ben Aïm ([@GauBen](http://github.com/GauBen)) -- Lionel Paulus ([@LionelPaulus](http://github.com/LionelPaulus)) -- Gorbasch ([@mbegerau](http://github.com/mbegerau)) -- Harlan Wilton ([@harlan-zw](http://github.com/harlan-zw)) -- Tobias Diez -- Tim Blommestijn ([@TMBL-DEV](http://github.com/TMBL-DEV)) -- Daniel Roe ([@danielroe](http://github.com/danielroe)) -- Luke Nelson -- Nermal ([@nermalcat69](http://github.com/nermalcat69)) -- Tudor Pipernea ([@tudorpip](http://github.com/tudorpip)) -- Adam DeHaven ([@adamdehaven](http://github.com/adamdehaven)) -- Gerome Grignon ([@geromegrignon](http://github.com/geromegrignon)) -- Anbraten ([@anbraten](http://github.com/anbraten)) -- Chris Saganic ([@Saganic](http://github.com/Saganic)) -- Juho Rutila ([@nice-game-hints](http://github.com/nice-game-hints)) -- JinU Choi ([@dalbodeule](http://github.com/dalbodeule)) -- Estéban ([@Barbapapazes](http://github.com/Barbapapazes)) -- Maik Kowol ([@94726](http://github.com/94726)) -- VisuSubbaiyan -- Ashcolor ([@ashcolor](http://github.com/ashcolor)) -- Guten -- Matteo Rigoni ([@Rigo-m](http://github.com/Rigo-m)) -- Brandon Roberts ([@brandonroberts](http://github.com/brandonroberts)) -- Ariesly -- Star Knight ([@starknt](http://github.com/starknt)) -- Jonas Thelemann -- Dominik Rajkowski ([@dominiq007](http://github.com/dominiq007)) -- Julien Blatecky ([@julien1619](http://github.com/julien1619)) -- Ígor Jacaúna ([@igorjacauna](http://github.com/igorjacauna)) -- Leex -- Martins Zeltins -- Markthree ([@markthree](http://github.com/markthree)) -- Matej Černý ([@CernyMatej](http://github.com/CernyMatej)) -- Julien Huang -- Viktor Szépe ([@szepeviktor](http://github.com/szepeviktor)) -- Nicolas Payot ([@nicolaspayot](http://github.com/nicolaspayot)) -- BaboonKing -- Ēriks Lapiņš ([@eriksLapins](http://github.com/eriksLapins)) -- Yuurin ([@byyuurin](http://github.com/byyuurin)) -- Hans Pagel -- Sby1ce ([@sby1ce](http://github.com/sby1ce)) -- Rahul Mishra - -## v2.9.6 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.9.5...v2.9.6) - -### 🩹 Fixes - -- Generate root/src directory aliases ([#2318](https://github.com/nitrojs/nitro/pull/2318)) -- **externals:** Skip resolving virtual ids start with `\0` ([#2321](https://github.com/nitrojs/nitro/pull/2321)) -- **types:** Account for `undefined` value for `$fetch` return type ([#2327](https://github.com/nitrojs/nitro/pull/2327)) -- **cloudflare-pages:** Use predefined wildcards in `routes.exclude` ([#2319](https://github.com/nitrojs/nitro/pull/2319)) - -### 📖 Documentation - -- Remove outdated nightly warning ([#2317](https://github.com/nitrojs/nitro/pull/2317)) - -### 🏡 Chore - -- Update docs lockfile ([825d94fa](https://github.com/nitrojs/nitro/commit/825d94fa)) -- **docs:** Update lock ([c343a2d0](https://github.com/nitrojs/nitro/commit/c343a2d0)) -- Update lockfile ([fcc0f9a3](https://github.com/nitrojs/nitro/commit/fcc0f9a3)) - -### ❤️ Contributors - -- Peter Graugaard -- Damian Głowala ([@DamianGlowala](http://github.com/DamianGlowala)) -- Pooya Parsa ([@pi0](http://github.com/pi0)) -- Daniel Roe ([@danielroe](http://github.com/danielroe)) -- Stefan - -## v2.9.5 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.9.4...v2.9.5) - -### 🚀 Enhancements - -- **openapi:** Add experimental `/_nitro/scalar` endpoint ([#2252](https://github.com/nitrojs/nitro/pull/2252)) - -### 🩹 Fixes - -- **openapi:** Use dynamic host + port ([#2216](https://github.com/nitrojs/nitro/pull/2216)) -- **openapi:** Add `schema` to generated parameters ([#2235](https://github.com/nitrojs/nitro/pull/2235)) -- **openapi:** Avoid double slash for base ([fdf7e70a](https://github.com/nitrojs/nitro/commit/fdf7e70a)) -- **options:** Set `scheduledTasks` to an empty object by default ([#2285](https://github.com/nitrojs/nitro/pull/2285)) -- **prerender:** Call `nitroApp` close hook when done prerendering ([#2287](https://github.com/nitrojs/nitro/pull/2287)) -- **types:** Return `T` from `Serialize` when it extends `undefined` ([#2286](https://github.com/nitrojs/nitro/pull/2286)) -- **raw:** Exclude yaml from raw plugin ([#2275](https://github.com/nitrojs/nitro/pull/2275)) -- **externals:** Check explicit inline rules on resolved id ([#2288](https://github.com/nitrojs/nitro/pull/2288)) -- **raw:** Allow importing relative paths ([#2289](https://github.com/nitrojs/nitro/pull/2289)) -- **types:** Make c12 env types available for `NitroConfig` ([#2292](https://github.com/nitrojs/nitro/pull/2292)) -- **netlify-edge:** Write `_headers` and `_redirects` ([#2291](https://github.com/nitrojs/nitro/pull/2291)) -- **cloudflare-pages:** Write `_headers` and `_redirects` for non static builds ([#2290](https://github.com/nitrojs/nitro/pull/2290)) -- **netlify:** Allow writing `config.json` ([#2264](https://github.com/nitrojs/nitro/pull/2264)) -- Allow importing utils from `nitropack/runtime` ([#2314](https://github.com/nitrojs/nitro/pull/2314)) - -### 💅 Refactors - -- **openapi:** Upgrade to openapi 3.1 ([#2297](https://github.com/nitrojs/nitro/pull/2297)) - -### 📖 Documentation - -- **routing:** Add note about middleware execution order ([#2282](https://github.com/nitrojs/nitro/pull/2282)) -- **routing:** Fx link to h3 object syntax handler ([#2281](https://github.com/nitrojs/nitro/pull/2281)) -- Update tasks return value ([8a62e7db](https://github.com/nitrojs/nitro/commit/8a62e7db)) -- **cache:** Add a note for serverless environment ([dc83a2e2](https://github.com/nitrojs/nitro/commit/dc83a2e2)) -- Fix typo ([#2298](https://github.com/nitrojs/nitro/pull/2298)) - -### 📦 Build - -- Use `.d.ts` for runtime generated types ([#2313](https://github.com/nitrojs/nitro/pull/2313)) - -### 🏡 Chore - -- Lint ([f7330329](https://github.com/nitrojs/nitro/commit/f7330329)) -- Update docs ([00c308c1](https://github.com/nitrojs/nitro/commit/00c308c1)) -- Update deps and lockfile ([55fd222b](https://github.com/nitrojs/nitro/commit/55fd222b)) -- Remove unused imports ([#2293](https://github.com/nitrojs/nitro/pull/2293)) -- Update deps and lockfile ([40883766](https://github.com/nitrojs/nitro/commit/40883766)) -- Update radix3 and lockfile ([7429465f](https://github.com/nitrojs/nitro/commit/7429465f)) - -### ❤️ Contributors - -- Pooya Parsa ([@pi0](http://github.com/pi0)) -- Matt Kane -- Hans Pagel -- Jamaluddin Rumi <16121031@student.mercubuana-yogya.ac.id> -- Julien Huang -- Bobbie Goede -- Damian Głowala ([@DamianGlowala](http://github.com/DamianGlowala)) -- Daniel Roe ([@danielroe](http://github.com/danielroe)) -- Sébastien Chopin ([@Atinux](http://github.com/Atinux)) -- Neil Richter ([@noook](http://github.com/noook)) -- Samuel Burkhard -- Shoshana Connack ([@moshetanzer](http://github.com/moshetanzer)) -- Yuurin ([@byyuurin](http://github.com/byyuurin)) -- Markthree ([@markthree](http://github.com/markthree)) - -## v2.9.4 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.9.3...v2.9.4) - -### 🩹 Fixes - -- Handle path negations when scanning public assets ([#2250](https://github.com/nitrojs/nitro/pull/2250)) -- **pkg:** Add `ioredis` as unstorage peer dependency ([#2266](https://github.com/nitrojs/nitro/pull/2266)) - -### 📖 Documentation - -- Fix server assets example path ([#2248](https://github.com/nitrojs/nitro/pull/2248)) -- Remove duplicate `integrity` key ([#2246](https://github.com/nitrojs/nitro/pull/2246)) -- Fix wording ([#2261](https://github.com/nitrojs/nitro/pull/2261)) -- Remove nightly notice ([39bc3f2e](https://github.com/nitrojs/nitro/commit/39bc3f2e)) -- **tasks:** Update dev server usage ([#2240](https://github.com/nitrojs/nitro/pull/2240)) -- **cache:** Add example usage for `cache.varies` ([#2241](https://github.com/nitrojs/nitro/pull/2241)) - -### 🏡 Chore - -- Fix typo ([#2260](https://github.com/nitrojs/nitro/pull/2260)) -- Update lockfile ([d8fafe4d](https://github.com/nitrojs/nitro/commit/d8fafe4d)) -- Update ufo ([b6cc11c7](https://github.com/nitrojs/nitro/commit/b6cc11c7)) - -### ✅ Tests - -- Increase timeout ([0f089d3e](https://github.com/nitrojs/nitro/commit/0f089d3e)) - -### ❤️ Contributors - -- Adam DeHaven ([@adamdehaven](http://github.com/adamdehaven)) -- Neil Richter ([@noook](http://github.com/noook)) -- Pooya Parsa ([@pi0](http://github.com/pi0)) -- Alexander Lichter ([@manniL](http://github.com/manniL)) -- KobZ ([@devseckobz](http://github.com/devseckobz)) -- Klein Petr -- Daniel Roe ([@danielroe](http://github.com/danielroe)) - -## v2.9.3 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.9.2...v2.9.3) - -### 🩹 Fixes - -- **raw:** Use mime to check binary types and exclude `.json` ([#2239](https://github.com/nitrojs/nitro/pull/2239)) - -### 📖 Documentation - -- Fix typo ([a445fae6](https://github.com/nitrojs/nitro/commit/a445fae6)) - -### ❤️ Contributors - -- Pooya Parsa -- Keigo Nakao ([@kspace-trk](http://github.com/kspace-trk)) - -## v2.9.2 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.9.1...v2.9.2) - -### 🩹 Fixes - -- **database:** CamelCase the connector name ([#2228](https://github.com/nitrojs/nitro/pull/2228)) -- Respect `imports.autoImport: false` ([#2226](https://github.com/nitrojs/nitro/pull/2226)) -- **server-assets:** Mark `yaml`, `json`, `json5` and `csv` as text ([#2229](https://github.com/nitrojs/nitro/pull/2229)) -- **import-meta:** Import `process` from `node:process` for node compatible builds (deno) ([#2225](https://github.com/nitrojs/nitro/pull/2225)) - -### 📖 Documentation - -- **deploy:** Add link to zero config providers ([#2206](https://github.com/nitrojs/nitro/pull/2206)) -- **fetch:** Fix typo ([#2209](https://github.com/nitrojs/nitro/pull/2209)) -- Fix typo ([#2211](https://github.com/nitrojs/nitro/pull/2211)) -- Fix typo ([#2205](https://github.com/nitrojs/nitro/pull/2205)) -- Remove lagon ([#2204](https://github.com/nitrojs/nitro/pull/2204)) -- Update url for experimental database feature ([#2210](https://github.com/nitrojs/nitro/pull/2210)) -- **providers:** Improve formatting & use new `undocs` components ([#2202](https://github.com/nitrojs/nitro/pull/2202)) -- Improve cache page ([674089b3](https://github.com/nitrojs/nitro/commit/674089b3)) - -### 🏡 Chore - -- **release:** V2.9.1 ([d8491cdc](https://github.com/nitrojs/nitro/commit/d8491cdc)) -- **examples:** Update hello-world ([169ec572](https://github.com/nitrojs/nitro/commit/169ec572)) -- Update deps and lockfile ([3875e50d](https://github.com/nitrojs/nitro/commit/3875e50d)) -- Update lockfile ([e3f555ac](https://github.com/nitrojs/nitro/commit/e3f555ac)) -- Remove lagon ([#2203](https://github.com/nitrojs/nitro/pull/2203)) -- Update `hello-world` example ([920b399e](https://github.com/nitrojs/nitro/commit/920b399e)) -- Update lockfile ([08da539f](https://github.com/nitrojs/nitro/commit/08da539f)) -- Improve notes in pr template ([#2212](https://github.com/nitrojs/nitro/pull/2212)) -- Update dependencies ([be2c70be](https://github.com/nitrojs/nitro/commit/be2c70be)) -- Use type import in tests ([1cb410db](https://github.com/nitrojs/nitro/commit/1cb410db)) -- Increase test timeout ([7a65d1ef](https://github.com/nitrojs/nitro/commit/7a65d1ef)) - -### ❤️ Contributors - -- Pooya Parsa ([@pi0](http://github.com/pi0)) -- Divy Srivastava ([@littledivy](http://github.com/littledivy)) -- Alexander Lichter -- Daniel Roe ([@danielroe](http://github.com/danielroe)) -- Sébastien Chopin ([@Atinux](http://github.com/Atinux)) -- Christian Preston ([@cpreston321](http://github.com/cpreston321)) -- Phan Khắc Đạo -- Maxime Pauvert ([@maximepvrt](http://github.com/maximepvrt)) -- Jeff Galbraith ([@hawkeye64](http://github.com/hawkeye64)) -- Rajeev R Sharma -- Julien Vanelian ([@JulienVanelian](http://github.com/JulienVanelian)) -- Gangan ([@shinGangan](http://github.com/shinGangan)) - -## v2.9.1 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.9.0...v2.9.1) - -### 🩹 Fixes - -- Disable scheduled tasks in testing environment ([#2200](https://github.com/nitrojs/nitro/pull/2200)) - -### 📖 Documentation - -- Add websocket chat demo to websocket api page ([#2189](https://github.com/nitrojs/nitro/pull/2189)) -- Fix typo ([#2190](https://github.com/nitrojs/nitro/pull/2190)) -- Fix typo ([#2194](https://github.com/nitrojs/nitro/pull/2194)) - -### 🤖 CI - -- Skip `cloudflare-pages` test for windows ([#2199](https://github.com/nitrojs/nitro/pull/2199)) - -### ❤️ Contributors - -- Pooya Parsa -- Roman Nuritdinov ([@Ky6uk](http://github.com/Ky6uk)) -- Stefan -- Shoshana Connack - -## v2.9.0 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.8.1...v2.9.0) - -### 🚀 Enhancements - -- Support function/RegExp for `prerender.ignore` ([#1966](https://github.com/nitrojs/nitro/pull/1966)) -- Show meta framework name on server build success ([#1955](https://github.com/nitrojs/nitro/pull/1955)) -- Add zeabur preset ([#1942](https://github.com/nitrojs/nitro/pull/1942)) -- Experimental nitro tasks ([#1929](https://github.com/nitrojs/nitro/pull/1929)) -- Add `types:extend` hook ([#1715](https://github.com/nitrojs/nitro/pull/1715)) -- Allow oveeridng nested runtime config with env ([#1831](https://github.com/nitrojs/nitro/pull/1831)) -- **wasm:** Universal support with esm import syntax ([#2017](https://github.com/nitrojs/nitro/pull/2017)) -- **wasm:** Migrate to unjs/unwasm ([#2037](https://github.com/nitrojs/nitro/pull/2037)) -- **zeabur:** Support `zeaburStatic` and auto detect preset ([#2014](https://github.com/nitrojs/nitro/pull/2014)) -- **runtime-config:** Experimental env expansion support ([#2043](https://github.com/nitrojs/nitro/pull/2043)) -- Support binary server assets ([#2107](https://github.com/nitrojs/nitro/pull/2107)) -- Experimental websocket support ([#2170](https://github.com/nitrojs/nitro/pull/2170)) -- **dev:** Expose upgrade handler ([5374429f](https://github.com/nitrojs/nitro/commit/5374429f)) -- Experimental database layer ([#1351](https://github.com/nitrojs/nitro/pull/1351)) -- Experimental scheduled tasks ([#2179](https://github.com/nitrojs/nitro/pull/2179)) -- **cache:** Support async `shouldBypassCache` and `shouldInvalidateCache` ([#2181](https://github.com/nitrojs/nitro/pull/2181)) -- **prerender:** Add total prerender time ([#2130](https://github.com/nitrojs/nitro/pull/2130)) -- Add koyeb preset ([#1248](https://github.com/nitrojs/nitro/pull/1248)) -- **providers:** Support alwaysdata hosting provider ([#1790](https://github.com/nitrojs/nitro/pull/1790)) -- **routeRules:** Allow wildcard redirects ([#1976](https://github.com/nitrojs/nitro/pull/1976)) - -### 🩹 Fixes - -- **rollup:** Avoid preserving relative externals ([#1972](https://github.com/nitrojs/nitro/pull/1972)) -- **wasm:** Directly generate chunk exports ([#2003](https://github.com/nitrojs/nitro/pull/2003)) -- **iis-node:** Correctly escape backslashes for port fix ([#2020](https://github.com/nitrojs/nitro/pull/2020)) -- **deno-deploy:** Shim `x-forwarded-for` and `x-forwarded-proto` headers ([#2026](https://github.com/nitrojs/nitro/pull/2026)) -- Add `baseURL` to openapi generated url ([#2049](https://github.com/nitrojs/nitro/pull/2049)) -- **dev:** Correctly set `x-forwarded-*` headers ([29ddd948](https://github.com/nitrojs/nitro/commit/29ddd948)) -- **azure:** Add `18` and `20` to supported node versions ([#2077](https://github.com/nitrojs/nitro/pull/2077)) -- **azure:** Pass body to the context as-is ([#2079](https://github.com/nitrojs/nitro/pull/2079)) -- Only mock consola in production ([#2110](https://github.com/nitrojs/nitro/pull/2110)) -- Default to `bundler` module resolution ([#2120](https://github.com/nitrojs/nitro/pull/2120)) -- Handle optional `routeHandler.route` in rollup chunk ([#2152](https://github.com/nitrojs/nitro/pull/2152)) -- File extension stripping in `writeTypes` function ([#2139](https://github.com/nitrojs/nitro/pull/2139)) -- **cache:** Detect malformed data read from storage ([#2161](https://github.com/nitrojs/nitro/pull/2161)) -- **cacheEventHandler:** Provide `event.fetch` and `event.$fetch` ([#2066](https://github.com/nitrojs/nitro/pull/2066)) -- Resolve modules with jiti directly ([#2030](https://github.com/nitrojs/nitro/pull/2030)) -- **options:** Add `unwasm` condition when `experimental.wasm` is enabled ([376658ce](https://github.com/nitrojs/nitro/commit/376658ce)) - -### 💅 Refactors - -- Include framework name in more build packages ([#1973](https://github.com/nitrojs/nitro/pull/1973)) -- **cloudflare:** Remove `--local` from preview commands ([#1979](https://github.com/nitrojs/nitro/pull/1979)) -- **cloudflare:** Remove unused import ([#1980](https://github.com/nitrojs/nitro/pull/1980)) -- **rollup:** Improve generated chunk names ([#2004](https://github.com/nitrojs/nitro/pull/2004)) -- Use name exports in presets entry ([1abfc3e5](https://github.com/nitrojs/nitro/commit/1abfc3e5)) -- Reimplement wasm plugin ([#2031](https://github.com/nitrojs/nitro/pull/2031)) -- Various improvements around tasks api ([#2175](https://github.com/nitrojs/nitro/pull/2175)) -- **tasks:** Stabilize api ([#2178](https://github.com/nitrojs/nitro/pull/2178)) -- **github-pages:** Add `--dotfiles` to deploy command hint ([#2158](https://github.com/nitrojs/nitro/pull/2158)) - -### 📖 Documentation - -- **routing:** Update request filtering to match the type of `getRequestURL` ([#1977](https://github.com/nitrojs/nitro/pull/1977)) -- **config:** Fix `setResponseHeader` example params ([#2027](https://github.com/nitrojs/nitro/pull/2027)) -- **netlify:** Add note to make sure publish dist is set to `dist` ([#2035](https://github.com/nitrojs/nitro/pull/2035)) -- **cloudflare:** Various updates, cleanups and fixes ([#1981](https://github.com/nitrojs/nitro/pull/1981)) -- Deprecate lagon ([17f922aa](https://github.com/nitrojs/nitro/commit/17f922aa)) -- Update the routing page ([#2085](https://github.com/nitrojs/nitro/pull/2085)) -- Update the cache page ([#2087](https://github.com/nitrojs/nitro/pull/2087)) -- Close code-group in cache section ([#2093](https://github.com/nitrojs/nitro/pull/2093)) -- **routing:** Escape filename paths and prepend routes folder ([#2097](https://github.com/nitrojs/nitro/pull/2097)) -- **storage:** Fix unstorage links ([#2101](https://github.com/nitrojs/nitro/pull/2101)) -- **routing:** Fix typo for `getRouterParam` ([#2098](https://github.com/nitrojs/nitro/pull/2098)) -- Update the storage page ([#2086](https://github.com/nitrojs/nitro/pull/2086)) -- Add object syntax for event handler ([#2091](https://github.com/nitrojs/nitro/pull/2091)) -- Update the configuration page ([#2083](https://github.com/nitrojs/nitro/pull/2083)) -- Update the assets page ([#2088](https://github.com/nitrojs/nitro/pull/2088)) -- Create a page on built-in fetch ([#2089](https://github.com/nitrojs/nitro/pull/2089)) -- Add warning about azure functions stability ([#2092](https://github.com/nitrojs/nitro/pull/2092)) -- **cloudflare:** Update deployment guide ([#2074](https://github.com/nitrojs/nitro/pull/2074)) -- Fix icon of fetch page ([#2115](https://github.com/nitrojs/nitro/pull/2115)) -- Update getting started page ([#2082](https://github.com/nitrojs/nitro/pull/2082)) -- Fix links to /guide/auto-imports ([#2131](https://github.com/nitrojs/nitro/pull/2131)) -- Fix typo in defineCachedFunction example ([#2133](https://github.com/nitrojs/nitro/pull/2133)) -- Clarify difference between dir and baseURL ([#2144](https://github.com/nitrojs/nitro/pull/2144)) -- Migrate to undocs ([#2163](https://github.com/nitrojs/nitro/pull/2163)) -- **index:** Fix utils link ([#2172](https://github.com/nitrojs/nitro/pull/2172)) -- **websocket:** Fix typo ([#2173](https://github.com/nitrojs/nitro/pull/2173)) -- Fix typo ([3017e6e2](https://github.com/nitrojs/nitro/commit/3017e6e2)) -- **vercel:** Add monorepo info ([#2183](https://github.com/nitrojs/nitro/pull/2183)) -- Fix typo ([#2182](https://github.com/nitrojs/nitro/pull/2182)) -- **cloudflare:** Add local bindings usage ([#2135](https://github.com/nitrojs/nitro/pull/2135)) -- Fix link to h3 utils ([#2184](https://github.com/nitrojs/nitro/pull/2184)) -- **deploy:** Add `platform.sh` ([#1630](https://github.com/nitrojs/nitro/pull/1630)) -- Fix db config ([#2188](https://github.com/nitrojs/nitro/pull/2188)) - -### 📦 Build - -- Better dist chunk names ([#2005](https://github.com/nitrojs/nitro/pull/2005)) - -### 🏡 Chore - -- **release:** V2.8.1 ([48c79556](https://github.com/nitrojs/nitro/commit/48c79556)) -- Add missing `cloudflarePagesStatic` ([5ead36f7](https://github.com/nitrojs/nitro/commit/5ead36f7)) -- Update lockfile ([884a1e24](https://github.com/nitrojs/nitro/commit/884a1e24)) -- Update dev dependencies ([76776513](https://github.com/nitrojs/nitro/commit/76776513)) -- Downgrade `@azure/functions` back to v3 ([0a765f2d](https://github.com/nitrojs/nitro/commit/0a765f2d)) -- Downgrade undici until upgrading miniflare ([0b2e3b8e](https://github.com/nitrojs/nitro/commit/0b2e3b8e)) -- **docs:** Update lockfile ([0c216cf3](https://github.com/nitrojs/nitro/commit/0c216cf3)) -- Update lockfile ([444c9f22](https://github.com/nitrojs/nitro/commit/444c9f22)) -- Update type test ([50cd9173](https://github.com/nitrojs/nitro/commit/50cd9173)) -- Update type test to pass linter ([cbcafa14](https://github.com/nitrojs/nitro/commit/cbcafa14)) -- Update undocs ([e2fa76b0](https://github.com/nitrojs/nitro/commit/e2fa76b0)) -- Remove extra `.npmrc` ([55a22b9f](https://github.com/nitrojs/nitro/commit/55a22b9f)) -- Update readme ([d840eb9a](https://github.com/nitrojs/nitro/commit/d840eb9a)) -- Update dependencies ([#2169](https://github.com/nitrojs/nitro/pull/2169)) -- Update docs ([5b0e150e](https://github.com/nitrojs/nitro/commit/5b0e150e)) - -### ✅ Tests - -- **cloudflare:** Migrate to miniflare v3 ([#2018](https://github.com/nitrojs/nitro/pull/2018)) -- Enable azure tests behind a flag ([#2076](https://github.com/nitrojs/nitro/pull/2076)) -- Enable binary response test for all presets ([#2078](https://github.com/nitrojs/nitro/pull/2078)) -- Avoid prerendering `icon.png` ([cb220f7e](https://github.com/nitrojs/nitro/commit/cb220f7e)) - -### 🤖 CI - -- Fix nightly release job condition ([#1975](https://github.com/nitrojs/nitro/pull/1975)) - -### ❤️ Contributors - -- Pooya Parsa ([@pi0](http://github.com/pi0)) -- Cas Du Plessis -- Julien Huang -- Jasper Zonneveld -- M4dz ([@m4dz](http://github.com/m4dz)) -- Dominik Opyd -- Justin Ellingwood -- Connor Pearson -- Alexander Lichter ([@manniL](http://github.com/manniL)) -- David De Sloovere -- Dario Piotrowicz -- Balázs Németh -- Mehmet -- Markthree ([@markthree](http://github.com/markthree)) -- Arkadiusz Sygulski -- Jamaluddin Rumi -- McPizza -- Shoshana Connack -- Anthony Fu -- Jackson Tenclay -- Rihan ([@RihanArfan](http://github.com/RihanArfan)) -- Remonke -- Daniel Roe ([@danielroe](http://github.com/danielroe)) -- Estéban ([@Barbapapazes](http://github.com/Barbapapazes)) -- Gerard Wilkinson -- Tobias Lebeitsuk -- Alexander ([@cany748](http://github.com/cany748)) -- Kasper Kronborg -- Gustavo Alfredo Marín Sáez -- Alexandr -- Yuanlin Lin -- Mcremer-able -- Jasonleong -- METO ([@metowolf](http://github.com/metowolf)) -- Michael Brevard -- Bobbie Goede -- Becem ([@becem-gharbi](http://github.com/becem-gharbi)) -- Mukund Shah -- Ayo Ayco ([@ayoayco](http://github.com/ayoayco)) - -## v2.8.1 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.8.0...v2.8.1) - -### 🩹 Fixes - -- **dev:** Conditionally access worker address for build info ([#1947](https://github.com/nitrojs/nitro/pull/1947)) -- Force use wasm import strategy for windows ([e73b849f](https://github.com/nitrojs/nitro/commit/e73b849f)) -- **netlify-lambda:** Handle base64 encoded body ([#1940](https://github.com/nitrojs/nitro/pull/1940)) -- **cloudflare:** Wasm support with dynamic chunks ([#1957](https://github.com/nitrojs/nitro/pull/1957)) -- **prerenderer:** Write responses with json signature to original path ([#1963](https://github.com/nitrojs/nitro/pull/1963)) - -### 📖 Documentation - -- **cache:** Make default value `swr: true` more clear ([#1949](https://github.com/nitrojs/nitro/pull/1949)) - -### 🏡 Chore - -- Update lockfile ([716edd52](https://github.com/nitrojs/nitro/commit/716edd52)) -- **docs:** Update lockfile ([b4386f8c](https://github.com/nitrojs/nitro/commit/b4386f8c)) - -### ✅ Tests - -- Add tests for wasm ([#1951](https://github.com/nitrojs/nitro/pull/1951)) -- **cloudflare-pages:** Remover overlapping include rules ([789a13d3](https://github.com/nitrojs/nitro/commit/789a13d3)) - -### ❤️ Contributors - -- Pooya Parsa ([@pi0](http://github.com/pi0)) -- Becem -- Mick Lawitzke ([@MickL](http://github.com/MickL)) - -## v2.8.0 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.7.1...v2.8.0) - -### 🚀 Enhancements - -- Support modules to extend nitro builder ([#1789](https://github.com/nitrojs/nitro/pull/1789)) -- Support `inline` mode for `serveStatic` ([#1864](https://github.com/nitrojs/nitro/pull/1864)) -- Add experimental `winterjs` preset ([#1863](https://github.com/nitrojs/nitro/pull/1863)) -- Allow setting preset using `SERVER_PRESET` environment variable ([#1870](https://github.com/nitrojs/nitro/pull/1870)) -- **cloudflare-pages, cloudflare-module:** Enable code splitting by default ([#1905](https://github.com/nitrojs/nitro/pull/1905)) -- Support `framework` config ([#1843](https://github.com/nitrojs/nitro/pull/1843)) -- Add aws amplify hosting preset ([#1912](https://github.com/nitrojs/nitro/pull/1912)) -- Upgrade to rollup v4 ([#1927](https://github.com/nitrojs/nitro/pull/1927)) -- Improve `nitro.json` build info ([#1930](https://github.com/nitrojs/nitro/pull/1930)) -- **aws-amplify:** Support static builds ([#1933](https://github.com/nitrojs/nitro/pull/1933)) -- Add `defineNitroErrorHandler` type helper ([#1923](https://github.com/nitrojs/nitro/pull/1923)) - -### 🩹 Fixes - -- **cloudflare-pages:** Filter out overlapping public assets dirs ([#1859](https://github.com/nitrojs/nitro/pull/1859)) -- **winterjs:** 0.1.7 compatibility ([#1876](https://github.com/nitrojs/nitro/pull/1876)) -- **scanner:** Allow having http method as part of the route name ([#1895](https://github.com/nitrojs/nitro/pull/1895)) -- Generate route types with resolve path and stripped extension ([#1897](https://github.com/nitrojs/nitro/pull/1897)) -- Scan dirs for unimport on initialization ([#1908](https://github.com/nitrojs/nitro/pull/1908)) -- **aws-amplify:** Register and auto detect ([0f38eb6f](https://github.com/nitrojs/nitro/commit/0f38eb6f)) -- **prerender:** Decode generated routes ([#1914](https://github.com/nitrojs/nitro/pull/1914)) -- Disabled public asset handler name is `null` ([b7a6a1a6](https://github.com/nitrojs/nitro/commit/b7a6a1a6)) -- **prerender:** Decode uris in headers ([#1932](https://github.com/nitrojs/nitro/pull/1932)) -- **error:** Respect `accept: text/html` request header ([#1921](https://github.com/nitrojs/nitro/pull/1921)) -- **prerender:** Filter encoded links starting with `#` ([#1936](https://github.com/nitrojs/nitro/pull/1936)) - -### 💅 Refactors - -- **deno-deploy:** Use `Deno.serve` ([#1879](https://github.com/nitrojs/nitro/pull/1879)) -- Split preset types ([#1910](https://github.com/nitrojs/nitro/pull/1910)) - -### 📖 Documentation - -- **deploy:** Split runtimes from providers ([#1865](https://github.com/nitrojs/nitro/pull/1865)) -- **routing:** Add note about middleware returns ([#1884](https://github.com/nitrojs/nitro/pull/1884)) -- Update edge links to nightly ([#1902](https://github.com/nitrojs/nitro/pull/1902)) -- **deploy:** Add deno to runtime list ([#1899](https://github.com/nitrojs/nitro/pull/1899)) -- **cloudflare:** Updatge wrangler link ([#1913](https://github.com/nitrojs/nitro/pull/1913)) -- **aws-amplify:** Add custom `amplify.yml` ([f412af16](https://github.com/nitrojs/nitro/commit/f412af16)) -- **amplify:** Remove cache from config ([7bbb723e](https://github.com/nitrojs/nitro/commit/7bbb723e)) -- Hide winterjs due to unstability ([048c8ff0](https://github.com/nitrojs/nitro/commit/048c8ff0)) -- **aws-amplify:** Update regions ([#1931](https://github.com/nitrojs/nitro/pull/1931)) -- **aws-amplify:** Add step to enable SSR logging and remove experimental ([#1934](https://github.com/nitrojs/nitro/pull/1934)) -- **aws-amplify:** Remove workaround banner ([#1935](https://github.com/nitrojs/nitro/pull/1935)) - -### 🌊 Types - -- Export `SerializeTuple` and `SerializeObject` ([#1907](https://github.com/nitrojs/nitro/pull/1907)) - -### 🏡 Chore - -- **release:** V2.7.1 ([2d803a3c](https://github.com/nitrojs/nitro/commit/2d803a3c)) -- Add jsdoc for `cache.maxAge` ([#1878](https://github.com/nitrojs/nitro/pull/1878)) -- Update lockfile ([dbff232e](https://github.com/nitrojs/nitro/commit/dbff232e)) -- **docs:** Update dependencies ([28867009](https://github.com/nitrojs/nitro/commit/28867009)) -- **docs:** Fix prerender issues ([d2a7d84d](https://github.com/nitrojs/nitro/commit/d2a7d84d)) -- Update unstorage ([110bc4a3](https://github.com/nitrojs/nitro/commit/110bc4a3)) -- Update unstorage ([441db6ca](https://github.com/nitrojs/nitro/commit/441db6ca)) -- Fix typos in aws amplify ([963716dd](https://github.com/nitrojs/nitro/commit/963716dd)) -- Update lockfile ([926bcef4](https://github.com/nitrojs/nitro/commit/926bcef4)) - -### ✅ Tests - -- Hide winterjs due to unstability ([1b50a9a1](https://github.com/nitrojs/nitro/commit/1b50a9a1)) - -### 🤖 CI - -- Disable codecov and codeql ([fd4671ce](https://github.com/nitrojs/nitro/commit/fd4671ce)) - -### ❤️ Contributors - -- Pooya Parsa ([@pi0](http://github.com/pi0)) -- Siegerts -- Passionate-bram -- Daniel Roe -- Neil Richter ([@noook](http://github.com/noook)) -- Xin Du (Clark) -- Anthony Fu -- Dario Piotrowicz ([@dario-piotrowicz](http://github.com/dario-piotrowicz)) -- Kalwabed Rizki -- Thunfisch987 -- Oof2win2 -- Markthree ([@markthree](http://github.com/markthree)) -- Estéban ([@Barbapapazes](http://github.com/Barbapapazes)) - -## v2.7.1 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.7.0...v2.7.1) - -### 🩹 Fixes - -- Recursively simplify returned objects ([#1847](https://github.com/nitrojs/nitro/pull/1847)) -- **cache:** Fix `etag` and `last-modified` values ([#1855](https://github.com/nitrojs/nitro/pull/1855)) -- **cache:** Invalidate wrongly cached handler entities ([#1857](https://github.com/nitrojs/nitro/pull/1857)) - -### 🏡 Chore - -- Update dependencies ([7a6c61db](https://github.com/nitrojs/nitro/commit/7a6c61db)) -- Update lockfile ([9b5ed9a1](https://github.com/nitrojs/nitro/commit/9b5ed9a1)) -- Update lockfile ([b0ec181d](https://github.com/nitrojs/nitro/commit/b0ec181d)) - -### ❤️ Contributors - -- Pooya Parsa ([@pi0](http://github.com/pi0)) -- Daniel Roe - -## v2.7.0 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.6.3...v2.7.0) - -### 🚀 Enhancements - -- **vercel:** Support `bypassToken` for on-demand static reganaration ([#1723](https://github.com/nitrojs/nitro/pull/1723)) -- **prerender:** Support `retry` and `retryDelay` ([#1534](https://github.com/nitrojs/nitro/pull/1534)) -- Allow disabling compressed size calculation ([#1756](https://github.com/nitrojs/nitro/pull/1756)) - -### 🔥 Performance - -- Use native fetch for `node >= 18` to reduce `%40` of bundle size ([#1724](https://github.com/nitrojs/nitro/pull/1724)) - -### 🩹 Fixes - -- Sort dependencies in `.output/package.json` ([#1708](https://github.com/nitrojs/nitro/pull/1708)) -- Add `application/javascript` mime type in lambda utils ([#1737](https://github.com/nitrojs/nitro/pull/1737)) -- **renderer:** Allow all h3 handled body types ([#1755](https://github.com/nitrojs/nitro/pull/1755)) -- **dev:** Safe error message override ([#1712](https://github.com/nitrojs/nitro/pull/1712)) -- **azure:** Fix cookie format normalization ([#1753](https://github.com/nitrojs/nitro/pull/1753)) -- Exclude undefined from hook types ([#1769](https://github.com/nitrojs/nitro/pull/1769)) -- **iis-node:** Pass `PORT` as `NITRO_UNIX_SOCKET` ([#1783](https://github.com/nitrojs/nitro/pull/1783)) -- **aws-lambda:** Handle `event.isBase64Encoded` ([#1779](https://github.com/nitrojs/nitro/pull/1779)) -- **cache:** Allow overriding integrity ([#1791](https://github.com/nitrojs/nitro/pull/1791)) -- **cache:** Write swr and update errors to console ([#1794](https://github.com/nitrojs/nitro/pull/1794)) -- **cache:** Only return validated stale value ([#1795](https://github.com/nitrojs/nitro/pull/1795)) -- **cache:** Only invalidate if `validate` returns `false` ([#1796](https://github.com/nitrojs/nitro/pull/1796)) -- Watch plugins directory ([#1800](https://github.com/nitrojs/nitro/pull/1800)) -- **cache:** Allow setting multiple `set-cookie` headers (bad practice) ([#1838](https://github.com/nitrojs/nitro/pull/1838)) -- **prerender:** Decode html entities in rendered links ([#1824](https://github.com/nitrojs/nitro/pull/1824)) -- **storage:** Validate and skip invalid mounts ([#1805](https://github.com/nitrojs/nitro/pull/1805)) -- **cache:** Validate `entry.value` to have value for cached handlers ([84559382](https://github.com/nitrojs/nitro/commit/84559382)) -- **cache:** Fix event handler integrity hash generation ([#1820](https://github.com/nitrojs/nitro/pull/1820)) -- **cache:** Set cache item before returning response on first request ([#1813](https://github.com/nitrojs/nitro/pull/1813)) - -### 💅 Refactors - -- **iis:** Improve preset and docs ([#1784](https://github.com/nitrojs/nitro/pull/1784)) - -### 📖 Documentation - -- Update prerender options ([11a24124](https://github.com/nitrojs/nitro/commit/11a24124)) -- Fix typo ([#1722](https://github.com/nitrojs/nitro/pull/1722)) -- Register error handler using hook instead of `hookOnce` ([#1743](https://github.com/nitrojs/nitro/pull/1743)) -- Update lock file ([#1750](https://github.com/nitrojs/nitro/pull/1750)) -- Fix typo ([#1759](https://github.com/nitrojs/nitro/pull/1759)) -- Fix configuration file name of the custom preset ([#1760](https://github.com/nitrojs/nitro/pull/1760)) -- Typo in word "legacy" in Configuration docs ([#1780](https://github.com/nitrojs/nitro/pull/1780)) -- **cloudflare:** Add local dev section ([#1772](https://github.com/nitrojs/nitro/pull/1772)) - -### 🏡 Chore - -- **release:** V2.6.3 ([9bb55262](https://github.com/nitrojs/nitro/commit/9bb55262)) -- Add `.devcontainer` ([#1633](https://github.com/nitrojs/nitro/pull/1633)) -- Update dependencies ([d225d3be](https://github.com/nitrojs/nitro/commit/d225d3be)) -- Fix lint issue ([c3565d8c](https://github.com/nitrojs/nitro/commit/c3565d8c)) -- Update non-major dependencies ([9c2cab26](https://github.com/nitrojs/nitro/commit/9c2cab26)) -- Update lockfile ([179846c7](https://github.com/nitrojs/nitro/commit/179846c7)) -- Fix type issues ([0ff72e29](https://github.com/nitrojs/nitro/commit/0ff72e29)) -- Update vitest to `1.0.0-beta` ([#1776](https://github.com/nitrojs/nitro/pull/1776)) -- Update dependencies ([553e4534](https://github.com/nitrojs/nitro/commit/553e4534)) -- **app:** Fix `localFetch` type ([5f3b287c](https://github.com/nitrojs/nitro/commit/5f3b287c)) -- Use pnpm `shell-emulator` for windows local development ([#1828](https://github.com/nitrojs/nitro/pull/1828)) -- Update lockfile ([f4e33332](https://github.com/nitrojs/nitro/commit/f4e33332)) -- Use `nitropack-nightly` for nightly release channel ([#1841](https://github.com/nitrojs/nitro/pull/1841)) -- Increase codecov threshold ([bc464032](https://github.com/nitrojs/nitro/commit/bc464032)) -- Update lockfile ([f53e3575](https://github.com/nitrojs/nitro/commit/f53e3575)) - -### ✅ Tests - -- Temporarily disable dev test in ci ([53a96adb](https://github.com/nitrojs/nitro/commit/53a96adb)) -- Update deno test with explicit host ([8cce5085](https://github.com/nitrojs/nitro/commit/8cce5085)) -- Update response type check ([#1839](https://github.com/nitrojs/nitro/pull/1839)) - -### 🤖 CI - -- Run tests against node 18 ([#1713](https://github.com/nitrojs/nitro/pull/1713)) -- Run vitest with es and sourcemap support ([c4c00467](https://github.com/nitrojs/nitro/commit/c4c00467)) - -### ❤️ Contributors - -- Pooya Parsa ([@pi0](http://github.com/pi0)) -- Yasser Lahbibi ([@yassilah](http://github.com/yassilah)) -- Horu -- Michael Brevard -- Daniel Roe -- MiniDigger < Martin> -- Estéban ([@Barbapapazes](http://github.com/Barbapapazes)) -- Heb ([@Hebilicious](http://github.com/Hebilicious)) -- Henrique Lopes -- McPizza -- Michael BOUVY -- Jeremy Graziani -- Tobias Diez -- VALERIY SINEVICH -- Roman Zipp -- Benjamin GAYMAY ([@BenjaminGaymay](http://github.com/BenjaminGaymay)) -- Alexander Lichter ([@manniL](http://github.com/manniL)) -- Farnabaz ([@farnabaz](http://github.com/farnabaz)) -- Nils K -- Jonas Thelemann ([@dargmuesli](http://github.com/dargmuesli)) -- Jenjen75 -- Sébastien Chopin ([@Atinux](http://github.com/Atinux)) - -## v2.6.3 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.6.2...v2.6.3) - -### 🩹 Fixes - -- **firebase:** Apply region for gen2 deployments ([#1657](https://github.com/nitrojs/nitro/pull/1657)) -- **cloudflare-pages:** Autodetect static preset ([#1659](https://github.com/nitrojs/nitro/pull/1659)) -- Resolve output dirs relative to `rootDir` ([#1666](https://github.com/nitrojs/nitro/pull/1666)) -- **prerender:** Allow disabling html sub-folders ([#1676](https://github.com/nitrojs/nitro/pull/1676)) -- **firebase:** Use correct key when importing firebase `httpsOptions` ([#1663](https://github.com/nitrojs/nitro/pull/1663)) -- Await on `send()` calls ([#1701](https://github.com/nitrojs/nitro/pull/1701)) -- Bun dev compatibility ([#1702](https://github.com/nitrojs/nitro/pull/1702)) -- **aws-lambda,netlify-lambda:** Binary body v2 and cookies v1 ([#1683](https://github.com/nitrojs/nitro/pull/1683)) -- **iis:** Merge `web.config` ([#1658](https://github.com/nitrojs/nitro/pull/1658)) - -### 📖 Documentation - -- **render-com:** Add note about node version ([#1693](https://github.com/nitrojs/nitro/pull/1693)) -- Add instructions for using nuxt edge release channel ([#1688](https://github.com/nitrojs/nitro/pull/1688)) -- Add instructions for bun ([#1672](https://github.com/nitrojs/nitro/pull/1672)) - -### 🏡 Chore - -- **release:** V2.6.2 ([9d0a383c](https://github.com/nitrojs/nitro/commit/9d0a383c)) -- Tiny internal typo ([#1668](https://github.com/nitrojs/nitro/pull/1668)) -- Fix code comments ([#1673](https://github.com/nitrojs/nitro/pull/1673)) -- Update dependencies ([3134ba6d](https://github.com/nitrojs/nitro/commit/3134ba6d)) - -### ✅ Tests - -- Update test for bun headers ([#1684](https://github.com/nitrojs/nitro/pull/1684)) - -### ❤️ Contributors - -- Gavin Hardaker ([@Hardaker587](http://github.com/Hardaker587)) -- Heb ([@Hebilicious](http://github.com/Hebilicious)) -- Colin McDonnell ([@colinhacks](http://github.com/colinhacks)) -- Pooya Parsa ([@pi0](http://github.com/pi0)) -- Luke Nelson -- Rajeev R Sharma -- Markthree ([@markthree](http://github.com/markthree)) -- Daniel Roe -- Yuichi Takebe - -## v2.6.2 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.6.1...v2.6.2) - -### 🩹 Fixes - -- Use new h3 generics for `defineCachedEventHandler` ([#1640](https://github.com/nitrojs/nitro/pull/1640)) -- **aws-lambda, netlify:** Add `isBase64Encoded` response field ([#1645](https://github.com/nitrojs/nitro/pull/1645)) -- Exclude typed body from `cachedEventHandler` ([#1647](https://github.com/nitrojs/nitro/pull/1647)) -- **static:** Send immediate empty responses for 304 handling ([#1639](https://github.com/nitrojs/nitro/pull/1639)) - -### 🏡 Chore - -- **docs:** Update dependencies ([d4d622c2](https://github.com/nitrojs/nitro/commit/d4d622c2)) -- **docs:** Add hotfix for `micromark` import issue ([b1e676e6](https://github.com/nitrojs/nitro/commit/b1e676e6)) -- Update lockfile ([fffd8724](https://github.com/nitrojs/nitro/commit/fffd8724)) -- Update `listhen` ([62ac3065](https://github.com/nitrojs/nitro/commit/62ac3065)) - -### ✅ Tests - -- Add test for prerender ignored `data:` urls ([#1431](https://github.com/nitrojs/nitro/pull/1431)) - -### ❤️ Contributors - -- Pooya Parsa ([@pi0](http://github.com/pi0)) -- Markthree ([@markthree](http://github.com/markthree)) -- Daniel Roe -- Azcray - -## v2.6.1 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.6.0...v2.6.1) - -### 🩹 Fixes - -- Correctly mark `middleware: false` for scanned routes ([#1631](https://github.com/nitrojs/nitro/pull/1631)) -- Pass relative ignore paths when scanning public assets ([#1632](https://github.com/nitrojs/nitro/pull/1632)) - -### 🏡 Chore - -- Update dependencies ([a779ae79](https://github.com/nitrojs/nitro/commit/a779ae79)) -- Force cf pages headers type ([81ec33a0](https://github.com/nitrojs/nitro/commit/81ec33a0)) -- Update mlly ([f76f0daa](https://github.com/nitrojs/nitro/commit/f76f0daa)) - -### ❤️ Contributors - -- Pooya Parsa ([@pi0](http://github.com/pi0)) -- Daniel Roe - -## v2.6.0 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.5.2...v2.6.0) - -### 🚀 Enhancements - -- **storage:** Default data storage for `node` and dev presets ([#1352](https://github.com/nitrojs/nitro/pull/1352)) -- Support regexps in external options ([#1388](https://github.com/nitrojs/nitro/pull/1388)) -- Support `exportConditions` and add worker default conditions ([#1401](https://github.com/nitrojs/nitro/pull/1401)) -- `event.waitUntil` with cloudflare integration ([#1421](https://github.com/nitrojs/nitro/pull/1421)) -- `experimental.typescriptBundlerResolution` flag ([#1384](https://github.com/nitrojs/nitro/pull/1384)) -- Support `ignore` to ignore scanned files ([#1430](https://github.com/nitrojs/nitro/pull/1430)) -- Allow ignoring public assets with `ignore` options ([#945](https://github.com/nitrojs/nitro/pull/945)) -- Add `iis` server preset ([#1436](https://github.com/nitrojs/nitro/pull/1436)) -- Auto capture errors with `nitroApp.captureError` ([#1463](https://github.com/nitrojs/nitro/pull/1463)) -- **vercel:** Enable streaming support out of the box ([#1514](https://github.com/nitrojs/nitro/pull/1514)) -- Fully resolve type paths for auto-import declarations ([#1528](https://github.com/nitrojs/nitro/pull/1528)) -- Add `prerender:config`, `prerender:init` and `prerender:done` hooks ([#1519](https://github.com/nitrojs/nitro/pull/1519)) -- **cache:** Support cached event handlers with varies ([#1184](https://github.com/nitrojs/nitro/pull/1184)) -- **app:** Support `request`, `beforeResponse` and `afterResponse` hooks ([#1545](https://github.com/nitrojs/nitro/pull/1545)) -- Experimental composition api via `useEvent()` ans async context support ([#1546](https://github.com/nitrojs/nitro/pull/1546)) -- **prerenderer:** Support for query links exploration ([#1474](https://github.com/nitrojs/nitro/pull/1474)) -- **cloudflare-pages:** Add config to customize generated `_routes.json` ([#1312](https://github.com/nitrojs/nitro/pull/1312)) -- **firebase:** Add support for 2nd generation functions ([#1500](https://github.com/nitrojs/nitro/pull/1500)) -- **externals:** Resolve actual subpaths before guessing ([#527](https://github.com/nitrojs/nitro/pull/527)) -- **externals:** Support aliasing traced packages ([#1553](https://github.com/nitrojs/nitro/pull/1553)) -- **wasm:** Support output esm imports ([#1565](https://github.com/nitrojs/nitro/pull/1565)) -- Enable `timing` in debug mode ([#1577](https://github.com/nitrojs/nitro/pull/1577)) -- **prerender:** Preserve prerendered asset `content-type` header ([#1587](https://github.com/nitrojs/nitro/pull/1587)) -- **externals:** Improved output `package.json` ([#1607](https://github.com/nitrojs/nitro/pull/1607)) -- **firebase:** Support renaming exported server function ([#1377](https://github.com/nitrojs/nitro/pull/1377)) -- **azure:** Support custom configuration ([#1344](https://github.com/nitrojs/nitro/pull/1344)) -- **node-server:** Support listening to unix sockets using `NITRO_UNIX_SOCKET` ([#1201](https://github.com/nitrojs/nitro/pull/1201)) -- **cloudflare-module, cloudflare-pages:** Experimental dynamic imports ([#1172](https://github.com/nitrojs/nitro/pull/1172)) -- **cli:** Support `--preset` and `--minify`/`--no-minify` args for `build` ([#1621](https://github.com/nitrojs/nitro/pull/1621)) -- **cli:** Add listhen options for `dev` command ([#1622](https://github.com/nitrojs/nitro/pull/1622)) -- Handle stream and Uint8Array for lambda presets ([#1624](https://github.com/nitrojs/nitro/pull/1624)) - -### 🔥 Performance - -- Use `fsLite` driver for production `data:` storage ([dd290763](https://github.com/nitrojs/nitro/commit/dd290763)) -- Use inline http-graceful-shoutdown to reduce externals ([8053cca0](https://github.com/nitrojs/nitro/commit/8053cca0)) -- Remove `source-map-support` as node supports `--enable-source-maps` ([9ba8fe98](https://github.com/nitrojs/nitro/commit/9ba8fe98)) -- Bundle runtime dependencies ([#1554](https://github.com/nitrojs/nitro/pull/1554)) -- Use local fetch for proxy route rules ([#1609](https://github.com/nitrojs/nitro/pull/1609)) - -### 🩹 Fixes - -- **rollup:** Replace `globalThis.process.` with `process.` ([#1360](https://github.com/nitrojs/nitro/pull/1360)) -- **types:** Enable `allowSyntheticDefaultImports` option by default ([#1383](https://github.com/nitrojs/nitro/pull/1383)) -- **cache:** Try to call `event.waitUntil` ([#1422](https://github.com/nitrojs/nitro/pull/1422)) -- **defineCachedFunction:** Properly infer function type ([#1423](https://github.com/nitrojs/nitro/pull/1423)) -- **static:** Safe decode path ([#1459](https://github.com/nitrojs/nitro/pull/1459)) -- Split cookie headers ([#1452](https://github.com/nitrojs/nitro/pull/1452)) -- **deno-deploy:** Treat all `https://` modules as external ([#1438](https://github.com/nitrojs/nitro/pull/1438)) -- **cache:** Call `event.waitUntil` on main resolver when expired ([421d6255](https://github.com/nitrojs/nitro/commit/421d6255)) -- **prerender:** Skip redirects ([#1448](https://github.com/nitrojs/nitro/pull/1448)) -- **aws-lambda,netlify:** Base64 encode binary responses ([#1274](https://github.com/nitrojs/nitro/pull/1274)) -- **app:** Enable router preemptive mode ([#1504](https://github.com/nitrojs/nitro/pull/1504)) -- **vercel:** Allow arbitrary function configuration ([#1508](https://github.com/nitrojs/nitro/pull/1508)) -- Use relative paths in `tsconfig.json` ([#1518](https://github.com/nitrojs/nitro/pull/1518)) -- **prerender:** Free up memory after each route is written to the disk ([#1536](https://github.com/nitrojs/nitro/pull/1536)) -- **prerender:** Call `prerender:route` before freeing up memory ([#1537](https://github.com/nitrojs/nitro/pull/1537)) -- **prerender:** Only match `href` attribute after whitespace ([#1530](https://github.com/nitrojs/nitro/pull/1530)) -- **externals:** Absolute paths are inlined ([#1429](https://github.com/nitrojs/nitro/pull/1429)) -- **openapi:** Merge handlers with same route and different method ([#1497](https://github.com/nitrojs/nitro/pull/1497)) -- **prerender:** Exclude encoded `href` attributes from link extraction ([#1485](https://github.com/nitrojs/nitro/pull/1485)) -- **externals:** Increase score for npm package name patterns to avoid breaking changes ([#1548](https://github.com/nitrojs/nitro/pull/1548)) -- **deno-deploy:** Decode static asset path before reading from filesystem ([#1494](https://github.com/nitrojs/nitro/pull/1494)) -- Remove non-standard `module` export condition ([#1559](https://github.com/nitrojs/nitro/pull/1559)) -- **externals:** Trace externals with their commonjs / esm status ([#1562](https://github.com/nitrojs/nitro/pull/1562)) -- Use relative paths in generated tsconfig ([#1572](https://github.com/nitrojs/nitro/pull/1572)) -- **app:** Use `event.path` instead of `event.url` ([41a76c0f](https://github.com/nitrojs/nitro/commit/41a76c0f)) -- **cache:** Don't use `_originalPath` ([#1576](https://github.com/nitrojs/nitro/pull/1576)) -- **types:** Use relative type path to nitro `#internal/nitro` ([#1584](https://github.com/nitrojs/nitro/pull/1584)) -- Disable sourcemap minify for dev ([e38f3586](https://github.com/nitrojs/nitro/commit/e38f3586)) -- Use relative source map paths and add test ([#1582](https://github.com/nitrojs/nitro/pull/1582)) -- **pkg:** Remove node 14 from supported `engines` ([#1585](https://github.com/nitrojs/nitro/pull/1585)) -- **prerender:** Use decoded asset id to access prerendered asset header overrides ([#1588](https://github.com/nitrojs/nitro/pull/1588)) -- Add `consola/core` alias ([#1591](https://github.com/nitrojs/nitro/pull/1591)) -- **vercel,netlify:** Don't deprecate `swr` when `cache: false` ([#1603](https://github.com/nitrojs/nitro/pull/1603)) -- **build:** Workaround bun's difference in `function.toString()` ([#1606](https://github.com/nitrojs/nitro/pull/1606)) -- **firebase:** Ignore `fsevent` dependency ([#1610](https://github.com/nitrojs/nitro/pull/1610)) -- Directly pass `localFetch` to route rules handler ([#1611](https://github.com/nitrojs/nitro/pull/1611)) -- **stormkit:** Properly send buffer responses ([#1616](https://github.com/nitrojs/nitro/pull/1616)) -- Add parent `node_modules` of nitro to modules dir for pnpm compat ([#1618](https://github.com/nitrojs/nitro/pull/1618)) -- **deno-server:** Fix injections and enable back tests ([#1625](https://github.com/nitrojs/nitro/pull/1625)) - -### 💅 Refactors - -- **cloudflare:** Use `wrangler deploy` instead of `publish` ([#1372](https://github.com/nitrojs/nitro/pull/1372)) -- **cloudflare:** Use `wrangler deploy` in more places ([#1393](https://github.com/nitrojs/nitro/pull/1393)) -- Add internal types for public assets ([#1460](https://github.com/nitrojs/nitro/pull/1460)) -- **prerender:** Improve console formatting for failed routes ([#1471](https://github.com/nitrojs/nitro/pull/1471)) -- Reduce usage of `event.node.req` ([#1511](https://github.com/nitrojs/nitro/pull/1511)) -- Reduce usage of `event.node.res` ([#1513](https://github.com/nitrojs/nitro/pull/1513)) -- **timing:** Hide debug logs with 0ms ([8a44d19c](https://github.com/nitrojs/nitro/commit/8a44d19c)) -- **firebase:** Update generated `package.json` ([#1608](https://github.com/nitrojs/nitro/pull/1608)) -- Migrate from `http-proxy` to `unjs/httpxy` ([#1623](https://github.com/nitrojs/nitro/pull/1623)) -- Simplify `normalizeLambdaOutgoingBody` ([58b4853b](https://github.com/nitrojs/nitro/commit/58b4853b)) -- Expose body type for lambda presets ([e5f095d6](https://github.com/nitrojs/nitro/commit/e5f095d6)) - -### 📖 Documentation - -- **vercel:** Add note about top level `api/` directory ([#1386](https://github.com/nitrojs/nitro/pull/1386)) -- Upgrade Docus ([26dd16a0](https://github.com/nitrojs/nitro/commit/26dd16a0)) -- Update nitro ([1a14a312](https://github.com/nitrojs/nitro/commit/1a14a312)) -- Fix crawler error ([c5e53cc8](https://github.com/nitrojs/nitro/commit/c5e53cc8)) -- Update ([03540d98](https://github.com/nitrojs/nitro/commit/03540d98)) -- Add nitro plugins examples ([#1403](https://github.com/nitrojs/nitro/pull/1403)) -- Add custom preset instructions ([#1409](https://github.com/nitrojs/nitro/pull/1409)) -- **aws:** Add note about inlining dynamic chunks ([#650](https://github.com/nitrojs/nitro/pull/650)) -- Fixed typo of the word `discussions` ([#1433](https://github.com/nitrojs/nitro/pull/1433)) -- Fix typo ([#1446](https://github.com/nitrojs/nitro/pull/1446)) -- Use `defineEventHandler` instead of `eventHandler` ([#1442](https://github.com/nitrojs/nitro/pull/1442)) -- Remove auto-imported `defineNitroConfig` ([#1441](https://github.com/nitrojs/nitro/pull/1441)) -- Add utils directory ([#1451](https://github.com/nitrojs/nitro/pull/1451)) -- **storage:** Add runtime storage configuration examples ([#1456](https://github.com/nitrojs/nitro/pull/1456)) -- Prefer snake_case for preset names ([#1499](https://github.com/nitrojs/nitro/pull/1499)) -- **routing:** Add middleware section ([#1307](https://github.com/nitrojs/nitro/pull/1307)) -- **plugins:** Add runtime hooks section ([#1521](https://github.com/nitrojs/nitro/pull/1521)) -- **config:** Add runtime config and environment variables section ([#1550](https://github.com/nitrojs/nitro/pull/1550)) -- **firebase:** Improve docs ([#1556](https://github.com/nitrojs/nitro/pull/1556)) -- **cloudflare:** Add environment variables instructions ([#1547](https://github.com/nitrojs/nitro/pull/1547)) - -### 📦 Build - -- Upgrade to unbuild v2 ([27f2cc48](https://github.com/nitrojs/nitro/commit/27f2cc48)) - -### 🏡 Chore - -- **release:** V2.5.2 ([b8b6defe](https://github.com/nitrojs/nitro/commit/b8b6defe)) -- Update lockfile ([976ec35c](https://github.com/nitrojs/nitro/commit/976ec35c)) -- Update references to `nuxt/nuxt` ([#1465](https://github.com/nitrojs/nitro/pull/1465)) -- Update github templates ([#1502](https://github.com/nitrojs/nitro/pull/1502)) -- Typo in bug report template ([#1507](https://github.com/nitrojs/nitro/pull/1507)) -- Update dependencies ([#1509](https://github.com/nitrojs/nitro/pull/1509)) -- Upgrade to `h3@1.8-rc` ([#1510](https://github.com/nitrojs/nitro/pull/1510)) -- Add codeql ci ([#1542](https://github.com/nitrojs/nitro/pull/1542)) -- Add `security.md` ([30b3578e](https://github.com/nitrojs/nitro/commit/30b3578e)) -- Update lockfile ([fc555506](https://github.com/nitrojs/nitro/commit/fc555506)) -- Update h3 ([bdf91c55](https://github.com/nitrojs/nitro/commit/bdf91c55)) -- Update dependencies ([de6d2d0b](https://github.com/nitrojs/nitro/commit/de6d2d0b)) -- **firebase:** Fix typos in warning message ([#1561](https://github.com/nitrojs/nitro/pull/1561)) -- Update dependencies ([e86f1464](https://github.com/nitrojs/nitro/commit/e86f1464)) -- Lint test files as well ([#1589](https://github.com/nitrojs/nitro/pull/1589)) -- Update dependencies ([6cb72e69](https://github.com/nitrojs/nitro/commit/6cb72e69)) -- Update dependencies ([8aa94ad2](https://github.com/nitrojs/nitro/commit/8aa94ad2)) -- Update dependencies ([8d7e6607](https://github.com/nitrojs/nitro/commit/8d7e6607)) -- Update dependencies ([b4d86b25](https://github.com/nitrojs/nitro/commit/b4d86b25)) -- Remove accidental console log ([2ece2a3a](https://github.com/nitrojs/nitro/commit/2ece2a3a)) - -### ✅ Tests - -- Improve external modules test ([#1428](https://github.com/nitrojs/nitro/pull/1428)) -- Run tests even if not `serveStatic` ([#1590](https://github.com/nitrojs/nitro/pull/1590)) -- Add tests for environment variables and runtime config overrides ([#1549](https://github.com/nitrojs/nitro/pull/1549)) -- Fix netlify tests ([880c20e4](https://github.com/nitrojs/nitro/commit/880c20e4)) -- **netlify:** Run after ([8a6ed77b](https://github.com/nitrojs/nitro/commit/8a6ed77b)) -- Fix netlify dirs ([8c7ca39d](https://github.com/nitrojs/nitro/commit/8c7ca39d)) - -### 🤖 CI - -- Use conventional commit message for autofix ([#1501](https://github.com/nitrojs/nitro/pull/1501)) -- Use `h3-nightly@latest` for edge releases ([#1563](https://github.com/nitrojs/nitro/pull/1563)) -- Avoid installing with edge dependency changes ([c431b719](https://github.com/nitrojs/nitro/commit/c431b719)) - -### ❤️ Contributors - -- Pooya Parsa ([@pi0](http://github.com/pi0)) -- Daniel Roe -- Utsob Roy ([@uroybd](http://github.com/uroybd)) -- Nick Dawson -- AlexLavoie42 ([@AlexLavoie42](http://github.com/AlexLavoie42)) -- Heb ([@Hebilicious](http://github.com/Hebilicious)) -- Dave Caruso ([@paperdave](http://github.com/paperdave)) -- Anthony Fu -- Luke Nelson -- Eduardo San Martin Morote -- Asher White ([@AWBroch](http://github.com/AWBroch)) -- Nikhil Saraf ([@nksaraf](http://github.com/nksaraf)) -- Velka -- Andreas Botzler -- Farnabaz -- Leo Bourbon -- Gnoeley -- Estéban ([@Barbapapazes](http://github.com/Barbapapazes)) -- Marshall Thompson ([@marshallswain](http://github.com/marshallswain)) -- Harlan Wilton ([@harlan-zw](http://github.com/harlan-zw)) -- Qin Guan -- Aaron Dewes -- Ccccccjh -- Antony Konstantinidis -- Arjun-re -- Morty Li -- Hebilicious ([@Hebilicious](http://github.com/Hebilicious)) -- Sébastien Chopin ([@Atinux](http://github.com/Atinux)) -- Rieger -- James Ross ([@Cherry](http://github.com/Cherry)) - -## v2.5.2 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.5.1...v2.5.2) - - -### 🩹 Fixes - - - Add `envPrefix` to `runtimeConfig.nitro` types ([#1336](https://github.com/nitrojs/nitro/pull/1336)) - - **prerender:** Allow to fetch static files ([#1340](https://github.com/nitrojs/nitro/pull/1340)) - - **options:** Default target to `static` when `static` override is set ([#1342](https://github.com/nitrojs/nitro/pull/1342)) - - Correct default `node-server` target ([7976318](https://github.com/nitrojs/nitro/commit/7976318)) - - **vercel, netlify:** Always check `nativeSWR` future flag ([ccebe4e](https://github.com/nitrojs/nitro/commit/ccebe4e)) - - **vercel, netlify:** Handle boolean values for route rule deprecation ([dfd8bbd](https://github.com/nitrojs/nitro/commit/dfd8bbd)) - - Dedup `unstorage` dependency and use subpath alias ([#1164](https://github.com/nitrojs/nitro/pull/1164)) - - **dev:** Ensure socket path is accessible ([#1115](https://github.com/nitrojs/nitro/pull/1115)) - - Type `event.$fetch` and `event.fetch` ([#1343](https://github.com/nitrojs/nitro/pull/1343)) - - Allow configuring esbuild transform plugin ([#1347](https://github.com/nitrojs/nitro/pull/1347)) - -### 📖 Documentation - - - Add reference to install azure functions core tools to the swa section ([#1339](https://github.com/nitrojs/nitro/pull/1339)) - -### 🏡 Chore - - - **release:** V2.5.1 ([21a2595](https://github.com/nitrojs/nitro/commit/21a2595)) - - Add `.data` to gitignore ([cff7bf0](https://github.com/nitrojs/nitro/commit/cff7bf0)) - - Update deps and lockfile ([373f34c](https://github.com/nitrojs/nitro/commit/373f34c)) - - Update unimport ([ef7eaf2](https://github.com/nitrojs/nitro/commit/ef7eaf2)) - -### ❤️ Contributors - -- Pooya Parsa ([@pi0](http://github.com/pi0)) -- Daniel Roe -- Stefan Bittmann -- Nick Dawson - -## v2.5.1 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.5.0...v2.5.1) - - -### 📖 Documentation - - - Fix typo in Flightcontrol deployment option ([#1332](https://github.com/nitrojs/nitro/pull/1332)) - -### 📦 Build - - - Avoid doubly-bundling runtime types ([#1334](https://github.com/nitrojs/nitro/pull/1334)) - -### 🌊 Types - - - Avoid overriding app runtime config namespace ([#1333](https://github.com/nitrojs/nitro/pull/1333)) - -### ❤️ Contributors - -- Daniel Roe -- ModupeD - -## v2.5.0 - -[compare changes](https://github.com/nitrojs/nitro/compare/v0.0.2...v2.5.0) - - -### 🚀 Enhancements - - - Allow customising generated tsConfig ([#1266](https://github.com/nitrojs/nitro/pull/1266)) - - Type `useRuntimeConfig` with `NitroRuntimeConfig` ([#1311](https://github.com/nitrojs/nitro/pull/1311)) - - Type nitro app runtime hooks ([#1316](https://github.com/nitrojs/nitro/pull/1316)) - - Add `cloudflare-pages-static` preset ([#1310](https://github.com/nitrojs/nitro/pull/1310)) - - Add experimental `deno-server` preset ([#592](https://github.com/nitrojs/nitro/pull/592)) - - Add `flightcontrol` preset ([#970](https://github.com/nitrojs/nitro/pull/970), [#1250](https://github.com/nitrojs/nitro/pull/1250)) - - Support `jsx` and `tsx` out of the box ([#1303](https://github.com/nitrojs/nitro/pull/1303)) - - Add support for `failOnError` ([#1294](https://github.com/nitrojs/nitro/pull/1294)) - - UseStorage generic support ([#1279](https://github.com/nitrojs/nitro/pull/1279)) - - Provide static `process.*` and `import.meta.*` build flags ([#1331](https://github.com/nitrojs/nitro/pull/1331)) - -### 🩹 Fixes - - - **bun:** Resolve internal dependencies with `bun` export condition ([#1313](https://github.com/nitrojs/nitro/pull/1313)) - - **deno:** Support environment variables ([88b4e11](https://github.com/nitrojs/nitro/commit/88b4e11)) - - Respect `static` flag when auto detecting preset ([#1321](https://github.com/nitrojs/nitro/pull/1321)) - - **prerenderer:** Don't inherit `static` config ([#1324](https://github.com/nitrojs/nitro/pull/1324)) - - **vercel:** Add check for index route rule ([#1290](https://github.com/nitrojs/nitro/pull/1290)) - - Use `event.handled` guard before sending direct responses ([#1326](https://github.com/nitrojs/nitro/pull/1326)) - - Import `NitroRuntimeHooks` from runtime dir ([#1328](https://github.com/nitrojs/nitro/pull/1328)) - - Generate types for `#imports` ([#1329](https://github.com/nitrojs/nitro/pull/1329)) - -### 📖 Documentation - - - Update docus version ([848c86a](https://github.com/nitrojs/nitro/commit/848c86a)) - - Update cloudflare-pages preset ([#1304](https://github.com/nitrojs/nitro/pull/1304)) - - Add an example for `devHandlers` config ([#1295](https://github.com/nitrojs/nitro/pull/1295)) - -### 🏡 Chore - - - Update dependencies ([db93afa](https://github.com/nitrojs/nitro/commit/db93afa)) - - Apply new lint rules ([879a7c3](https://github.com/nitrojs/nitro/commit/879a7c3)) - - Update all non major dependencies ([9bb674f](https://github.com/nitrojs/nitro/commit/9bb674f)) - - Update dependencies ([46e6f10](https://github.com/nitrojs/nitro/commit/46e6f10)) - - Update unstorage ([bac3b0d](https://github.com/nitrojs/nitro/commit/bac3b0d)) - -### ❤️ Contributors - -- Pooya Parsa ([@pi0](http://github.com/pi0)) -- 魔王少年 ([@maou-shonen](http://github.com/maou-shonen)) -- Daniel Roe -- Andrew -- Estéban ([@Barbapapazes](http://github.com/Barbapapazes)) -- Dunqing ([@Dunqing](http://github.com/Dunqing)) -- Frantz Kati -- Mike Laumann Bellika -- Sébastien Chopin ([@Atinux](http://github.com/Atinux)) -- Hebilicious ([@Hebilicious](http://github.com/Hebilicious)) - -## v2.4.0 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.3.3...v2.4.0) - - -### 🚀 Enhancements - - - Add cloudflare module worker support ([#681](https://github.com/nitrojs/nitro/pull/681)) - - **vercel, netlify:** Introduce `isr` route rule ([#1124](https://github.com/nitrojs/nitro/pull/1124)) - - Add `static` preset ([#1127](https://github.com/nitrojs/nitro/pull/1127)) - - Add `vercel-static` and `netlify-static` presets ([#1073](https://github.com/nitrojs/nitro/pull/1073)) - - Add `github-pages` preset ([#1133](https://github.com/nitrojs/nitro/pull/1133)) - - Pass resolved config to `rollup:before` hook ([#1160](https://github.com/nitrojs/nitro/pull/1160)) - - Config reload support for `nitro dev` ([#1173](https://github.com/nitrojs/nitro/pull/1173)) - - Config hmr support for `routeRules` and `rutimeConfig` ([#1175](https://github.com/nitrojs/nitro/pull/1175)) - - Support dynamic app config and runtime config ([#1154](https://github.com/nitrojs/nitro/pull/1154)) - - Experimental `/_nitro/openapi.json` and `/_nitro/swagger` for dev mode ([#1162](https://github.com/nitrojs/nitro/pull/1162)) - - **vercel:** Add support for specifying edge regions ([#1192](https://github.com/nitrojs/nitro/pull/1192)) - - `future.nativeSWR` ([#1212](https://github.com/nitrojs/nitro/pull/1212)) - -### 🔥 Performance - - - Export `defineNitroConfig` from `nitro/config` ([#1174](https://github.com/nitrojs/nitro/pull/1174)) - -### 🩹 Fixes - - - Separate `typesDir` from `tsConfigDir` ([#1146](https://github.com/nitrojs/nitro/pull/1146)) - - **cloudflare:** Expose env from module context ([#1147](https://github.com/nitrojs/nitro/pull/1147)) - - **proxy:** Append request query params for single proxy route rules ([#1163](https://github.com/nitrojs/nitro/pull/1163)) - - **vercel, netlify:** Keep default behavior for `static` and `swr` to `isr` mapping ([#1155](https://github.com/nitrojs/nitro/pull/1155)) - - Apply `chunkFileNames` on windows ([#1189](https://github.com/nitrojs/nitro/pull/1189)) - - **pkg:** Allow installing on node v20 and above ([#1204](https://github.com/nitrojs/nitro/pull/1204)) - -### 💅 Refactors - - - Rename `build` option to `static` ([#1144](https://github.com/nitrojs/nitro/pull/1144)) - - **cli:** Migrate to citty ([#1157](https://github.com/nitrojs/nitro/pull/1157)) - - Move swagger/openapi behind experimental flag ([2079cab](https://github.com/nitrojs/nitro/commit/2079cab)) - -### 📖 Documentation - - - Fix typo ([#1131](https://github.com/nitrojs/nitro/pull/1131)) - - Update serverAssets example ([#1156](https://github.com/nitrojs/nitro/pull/1156)) - - Add edge releases channel ([2793f51](https://github.com/nitrojs/nitro/commit/2793f51)) - - **get-started:** H2 instead of h3 ([ff3964e](https://github.com/nitrojs/nitro/commit/ff3964e)) - - **routing:** Add route rules ([46740e6](https://github.com/nitrojs/nitro/commit/46740e6)) - - **routing:** Add missing import ([30675d4](https://github.com/nitrojs/nitro/commit/30675d4)) - - Fix syntax issue in guide > storage ([#1180](https://github.com/nitrojs/nitro/pull/1180)) - - Update ([1e5bb86](https://github.com/nitrojs/nitro/commit/1e5bb86)) - - Fix typo ([#1185](https://github.com/nitrojs/nitro/pull/1185)) - - Fix typo ([#1190](https://github.com/nitrojs/nitro/pull/1190)) - - **vercel:** Add vercel kv storage section ([#1210](https://github.com/nitrojs/nitro/pull/1210)) - - Update branding ([#1188](https://github.com/nitrojs/nitro/pull/1188)) - - Update vercel-storage ([ffff9db](https://github.com/nitrojs/nitro/commit/ffff9db)) - -### 🏡 Chore - - - Update dependencies ([39d1f27](https://github.com/nitrojs/nitro/commit/39d1f27)) - - **release:** V2.3.3 ([2d55caf](https://github.com/nitrojs/nitro/commit/2d55caf)) - - Update dependencies and lockfile ([eea8943](https://github.com/nitrojs/nitro/commit/eea8943)) - - Update unenv ([ba81902](https://github.com/nitrojs/nitro/commit/ba81902)) - - Update lockfile ([6a4e57e](https://github.com/nitrojs/nitro/commit/6a4e57e)) - - Update lockfile ([0793451](https://github.com/nitrojs/nitro/commit/0793451)) - - **docs:** Move `vercel.json` ([00502d0](https://github.com/nitrojs/nitro/commit/00502d0)) - - **docs:** Update deps ([4a95c96](https://github.com/nitrojs/nitro/commit/4a95c96)) - - Update deps ([6b08d37](https://github.com/nitrojs/nitro/commit/6b08d37)) - -### ✅ Tests - - - Enable `vercel-edge` test ([7951532](https://github.com/nitrojs/nitro/commit/7951532)) - -### ❤️ Contributors - -- Pooya Parsa ([@pi0](http://github.com/pi0)) -- Sébastien Chopin ([@Atinux](http://github.com/Atinux)) -- Daniel Roe -- AaronBeaudoin -- Oumar Barry ([@oumarbarry](http://github.com/oumarbarry)) -- G-Cyrille -- 魔王少年 -- Iho Somnam -- Timhanlon - -## v2.3.3 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.3.2...v2.3.3) - - -### 🚀 Enhancements - - - Upgrade to consola v3 (prerelease) ([50e9f8e](https://github.com/nitrojs/nitro/commit/50e9f8e)) - -### 🩹 Fixes - - - **prerender:** Show generated routes with error in logs ([8e06f2e](https://github.com/nitrojs/nitro/commit/8e06f2e)) - - **prerender:** Respect output path from main preset ([#1114](https://github.com/nitrojs/nitro/pull/1114)) - -### 📖 Documentation - - - Fix typos in storage and cache guides ([#1086](https://github.com/nitrojs/nitro/pull/1086)) - - Use unjs logo ([#1104](https://github.com/nitrojs/nitro/pull/1104)) - - Fix typo in cachedEventHandler options ([#1110](https://github.com/nitrojs/nitro/pull/1110)) - - Use consistent quotes in the routeRules example ([#1108](https://github.com/nitrojs/nitro/pull/1108)) - - Fix typo in server assets mount point ([#1119](https://github.com/nitrojs/nitro/pull/1119)) - - Improve `publicAssets` config details ([#1102](https://github.com/nitrojs/nitro/pull/1102)) - -### 🏡 Chore - - - **doc:** Fix small typo in plugin filename ([#1081](https://github.com/nitrojs/nitro/pull/1081)) - - Update unenv and semver ([363e2ea](https://github.com/nitrojs/nitro/commit/363e2ea)) - - Update consola ([5d77615](https://github.com/nitrojs/nitro/commit/5d77615)) - - Bump to consola v3 stable ([ea5ea88](https://github.com/nitrojs/nitro/commit/ea5ea88)) - - Update dependencies ([39d1f27](https://github.com/nitrojs/nitro/commit/39d1f27)) - -### ❤️ Contributors - -- Pooya Parsa ([@pi0](http://github.com/pi0)) -- Gabriel Cipriano ([@gabrielcipriano](http://github.com/gabrielcipriano)) -- Daniel Roe -- Yassine El Ouazzani ([@kwarkjes](http://github.com/kwarkjes)) -- Inesh Bose -- Andre Hammons -- Michael BOUVY - -## v2.3.2 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.3.1...v2.3.2) - - -### 🩹 Fixes - - - Sanitize `statusMessage` of disallowed chars ([#1057](https://github.com/nitrojs/nitro/pull/1057)) - - **types:** Sync vercel build config types ([#1056](https://github.com/nitrojs/nitro/pull/1056)) - - **azure:** Support custom baseURL ([#1062](https://github.com/nitrojs/nitro/pull/1062)) - - **vercel-edge:** Fix route generation ([#1071](https://github.com/nitrojs/nitro/pull/1071)) - - Mark `options.renderer` as optional ([#1069](https://github.com/nitrojs/nitro/pull/1069)) - - **types:** Make $Fetch types less complex ([#1059](https://github.com/nitrojs/nitro/pull/1059)) - -### 💅 Refactors - - - Add type safety to auto-detected providers ([#1072](https://github.com/nitrojs/nitro/pull/1072)) - -### 📖 Documentation - - - Fixed link path ([#1053](https://github.com/nitrojs/nitro/pull/1053)) - - Fix typo ([#1068](https://github.com/nitrojs/nitro/pull/1068)) - - **routing:** Add `$fetch` usage note ([#1070](https://github.com/nitrojs/nitro/pull/1070)) - -### ❤️ Contributors - -- Mahdi Boomeri -- Daniel Roe -- Shohei Maeda -- Lucas ([@Draichi](http://github.com/Draichi)) -- Nobkd -- Honza Pobořil - -## v2.3.1 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.3.0...v2.3.1) - - -### 🩹 Fixes - - - **types:** Don't simplify type of serialized return ([#1050](https://github.com/nitrojs/nitro/pull/1050)) - -### 🏡 Chore - - - Add `codecov.yml` ([6fe7f64](https://github.com/nitrojs/nitro/commit/6fe7f64)) - -### ❤️ Contributors - -- Pooya Parsa ([@pi0](http://github.com/pi0)) -- Daniel Roe - -## v2.3.0 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.2.3...v2.3.0) - - -### 🚀 Enhancements - - - **vercel:** Add functions config ([#976](https://github.com/nitrojs/nitro/pull/976)) - - Add support for `sourceMap` values `hidden` and `inline` ([#998](https://github.com/nitrojs/nitro/pull/998)) - - **lagon:** Write `.lagon/config.json` on build ([#996](https://github.com/nitrojs/nitro/pull/996)) - - **types:** Type $fetch to match json serialization output ([#1002](https://github.com/nitrojs/nitro/pull/1002)) - - Support base in `useStorage(base?: string)` and improve docs ([#1012](https://github.com/nitrojs/nitro/pull/1012)) - - **cloudflare-pages:** Rewrite with module syntax ([#1004](https://github.com/nitrojs/nitro/pull/1004)) - - Allow customising generated tsconfig path ([#1021](https://github.com/nitrojs/nitro/pull/1021)) - - Support app config ([#1022](https://github.com/nitrojs/nitro/pull/1022)) - -### 🩹 Fixes - - - **cloudflare-pages:** Only allow 100 rules combined ([#973](https://github.com/nitrojs/nitro/pull/973)) - - Only mock `debug` in production ([#990](https://github.com/nitrojs/nitro/pull/990)) - - Scan middleware and print tree list in ascending alphabetical order ([#981](https://github.com/nitrojs/nitro/pull/981)) - - **externals:** Correctly specify multiple external dependencies in package.json ([#1013](https://github.com/nitrojs/nitro/pull/1013)) - - **static:** Use correct format for last modified ([#1017](https://github.com/nitrojs/nitro/pull/1017)) - - **cache:** Remove rejected cache promise from pending list. ([#995](https://github.com/nitrojs/nitro/pull/995)) - - Expose `useStorage` with types ([#1026](https://github.com/nitrojs/nitro/pull/1026)) - - **prerender:** Allow spaces in `href` value regex ([#1030](https://github.com/nitrojs/nitro/pull/1030)) - - **cache:** Use stale value by default when `swr` is enabled ([#1038](https://github.com/nitrojs/nitro/pull/1038)) - - Resolve types relative to custom tsconfig path ([#1041](https://github.com/nitrojs/nitro/pull/1041)) - - Remove duplicate import in generated code ([#1043](https://github.com/nitrojs/nitro/pull/1043)) - - **types:** Exclude non serializable options from route rules ([#1047](https://github.com/nitrojs/nitro/pull/1047)) - -### 💅 Refactors - - - Use unimport built-in type gen for dirs ([#994](https://github.com/nitrojs/nitro/pull/994)) - - Split out api types ([#1027](https://github.com/nitrojs/nitro/pull/1027)) - -### 📖 Documentation - - - Update to latest docus and various improvements ([#975](https://github.com/nitrojs/nitro/pull/975)) - - Up docus and add back ellipsis ([38b1f34](https://github.com/nitrojs/nitro/commit/38b1f34)) - - Remove tailwind module ([b3b7e87](https://github.com/nitrojs/nitro/commit/b3b7e87)) - - **lock:** Update ([7efa31f](https://github.com/nitrojs/nitro/commit/7efa31f)) - - More improvements ([#985](https://github.com/nitrojs/nitro/pull/985)) - - Remove fluid layout ([d83f2b6](https://github.com/nitrojs/nitro/commit/d83f2b6)) - - Update color ([18674c5](https://github.com/nitrojs/nitro/commit/18674c5)) - - Add unjs icon in footer ([6d36ceb](https://github.com/nitrojs/nitro/commit/6d36ceb)) - - Update docus ([5fcc127](https://github.com/nitrojs/nitro/commit/5fcc127)) - - Add button to open on CodeSandBox ([ad120ac](https://github.com/nitrojs/nitro/commit/ad120ac)) - - Update deployment example for configuration ([#972](https://github.com/nitrojs/nitro/pull/972)) - - Update dependencies ([c923fed](https://github.com/nitrojs/nitro/commit/c923fed)) - - **cache:** Improve documentation and `cachedFunction` default options ([#1011](https://github.com/nitrojs/nitro/pull/1011)) - - Improve readme and getting started ([94d95fa](https://github.com/nitrojs/nitro/commit/94d95fa)) - - Fix on mobile long path ([1d2f57e](https://github.com/nitrojs/nitro/commit/1d2f57e)) - - Improvements ([f78619f](https://github.com/nitrojs/nitro/commit/f78619f)) - - Add `prerender.ignore` description ([#1032](https://github.com/nitrojs/nitro/pull/1032)) - - Improve configuration page ([554b358](https://github.com/nitrojs/nitro/commit/554b358)) - - Improve plugins section ([f36a6e0](https://github.com/nitrojs/nitro/commit/f36a6e0)) - - Update readme ([c58a764](https://github.com/nitrojs/nitro/commit/c58a764)) - - Update homepage hero ([b848e5a](https://github.com/nitrojs/nitro/commit/b848e5a)) - - Update meta tags ([70f00e5](https://github.com/nitrojs/nitro/commit/70f00e5)) - - More improvements ([#1039](https://github.com/nitrojs/nitro/pull/1039)) - - Update docus version ([f31240b](https://github.com/nitrojs/nitro/commit/f31240b)) - - Upgrade docus ([a6ce587](https://github.com/nitrojs/nitro/commit/a6ce587)) - - **deploy/workers:** Fix typo of bundle ([#1046](https://github.com/nitrojs/nitro/pull/1046)) - -### 🏡 Chore - - - **readme:** Various improvements ([#1009](https://github.com/nitrojs/nitro/pull/1009)) - - Fix tests ([#1014](https://github.com/nitrojs/nitro/pull/1014)) - - **docs:** Use pnpm ([39f117a](https://github.com/nitrojs/nitro/commit/39f117a)) - - Add autofix-ci action ([8f9c3e2](https://github.com/nitrojs/nitro/commit/8f9c3e2)) - - Remove old docs commands ([#1042](https://github.com/nitrojs/nitro/pull/1042)) - - Update dependencies ([02c48f2](https://github.com/nitrojs/nitro/commit/02c48f2)) - - Maintain lockfile ([ac81602](https://github.com/nitrojs/nitro/commit/ac81602)) - - Use single undici version for testing ([00743bc](https://github.com/nitrojs/nitro/commit/00743bc)) - -### ❤️ Contributors - -- Pooya Parsa ([@pi0](http://github.com/pi0)) -- Daniel Roe -- Felix De Montis -- Sébastien Chopin ([@Atinux](http://github.com/Atinux)) -- Hannes Küttner -- Julie Saia -- Ted De Koning -- Jan Johansen -- Tobias Diez -- Elian ☕️ -- Mahdi Boomeri -- Anthony Fu -- Tom Lienard ([@QuiiBz](http://github.com/QuiiBz)) -- Alex Korytskyi ([@alex-key](http://github.com/alex-key)) -- Shohei Maeda - -## v2.2.3 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.2.2...v2.2.3) - - -### 🚀 Enhancements - - - Add lagon preset ([#964](https://github.com/nitrojs/nitro/pull/964)) - -### 🩹 Fixes - - - **node-cluster:** Default number of workers ([#963](https://github.com/nitrojs/nitro/pull/963)) - - **cloudflare-pages:** Exclude assets from function call ([#965](https://github.com/nitrojs/nitro/pull/965)) - - **cloudflare-pages:** Handle assets only for get requests ([#968](https://github.com/nitrojs/nitro/pull/968)) - - Render json errors for cors requests ([#969](https://github.com/nitrojs/nitro/pull/969)) - - Use json response for errors in `/api/` routes ([#971](https://github.com/nitrojs/nitro/pull/971)) - -### 💅 Refactors - - - **externals:** Sort `bundledDependencies` keys in output `package.json` ([#967](https://github.com/nitrojs/nitro/pull/967)) - -### 📖 Documentation - - - **cloudflare:** Add info regarding `runtimeConfig` and environment variables ([#958](https://github.com/nitrojs/nitro/pull/958)) - - Prevent ellipsis overflow on small screens ([#956](https://github.com/nitrojs/nitro/pull/956)) - - **deploy:** Add workers page for edge limitations ([#953](https://github.com/nitrojs/nitro/pull/953)) - -### 🏡 Chore - - - **cli:** Mention `prepare` command in usage ([#959](https://github.com/nitrojs/nitro/pull/959)) - - Update dependencies ([2658072](https://github.com/nitrojs/nitro/commit/2658072)) - -### ❤️ Contributors - -- Pooya Parsa ([@pi0](http://github.com/pi0)) -- Daniel Roe -- Jan-Henrik Damaschke -- Bogdan Kostyuk -- Hminghe ([@hminghe](http://github.com/hminghe)) -- Alexander Lichter ([@manniL](http://github.com/manniL)) - -## v2.2.2 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.2.1...v2.2.2) - - -### 🩹 Fixes - - - Correct `access-control-allow-methods` cors header name ([#944](https://github.com/nitrojs/nitro/pull/944)) - - Allow overriding assets `maxAge` using route rules ([db6e6c2](https://github.com/nitrojs/nitro/commit/db6e6c2)) - - **rollup:** Use mlly as fallback resolver when externals disabled ([#948](https://github.com/nitrojs/nitro/pull/948)) - - Don't render json response if url contains `/api/` ([#951](https://github.com/nitrojs/nitro/pull/951)) - -### 🏡 Chore - - - Update unjs dependencies ([b852c23](https://github.com/nitrojs/nitro/commit/b852c23)) - - Update jiti dependency ([716dc1a](https://github.com/nitrojs/nitro/commit/716dc1a)) - - Updare unbuild ([044bb6a](https://github.com/nitrojs/nitro/commit/044bb6a)) - -### ✅ Tests - - - **vercel:** Move custom test to additional tests ([fb361f8](https://github.com/nitrojs/nitro/commit/fb361f8)) - -### ❤️ Contributors - -- Pooya Parsa -- Daniel Roe - -## v2.2.1 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.2.0...v2.2.1) - - -### 🩹 Fixes - - - **static:** Remove `cache-control` headers when asset is not found ([e3d57fc](https://github.com/nitrojs/nitro/commit/e3d57fc)) - - Avoid circular imports ([#936](https://github.com/nitrojs/nitro/pull/936)) - -### 🏡 Chore - - - Update changelog ([8dde296](https://github.com/nitrojs/nitro/commit/8dde296)) - -### ❤️ Contributors - -- Pooya Parsa - -## v2.2.0 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.1.2...v2.2.0) - -### ⭐ What is new? - -- Runtime proxy support using route rules ([learn more](https://github.com/nitrojs/nitro/pull/926)) -- Nested fetch calls with incoming headers and context in event context ([learn more](https://github.com/nitrojs/nitro/pull/930)) -- Binary and Raw storage operations support ([learn more](https://github.com/unjs/unstorage/pull/141)) -- [Cloudflare] Exposed `event.context.cf` ([learn more](https://github.com/nitrojs/nitro/pull/927)) -- Built-in session support ([learn more](https://github.com/unjs/h3/pull/315)) - -### 🚀 Enhancements - -- Support runtime proxy using route rules ([#926](https://github.com/nitrojs/nitro/pull/926)) -- **cloudflare:** `cacheControl` support for public assets with with `maxAge` ([#922](https://github.com/nitrojs/nitro/pull/922)) -- **cloudflare:** Expose `event.context.cf` ([#927](https://github.com/nitrojs/nitro/pull/927)) -- **firebase:** Use nodejs 18 as default runtime ([#925](https://github.com/nitrojs/nitro/pull/925)) -- Support `event.fetch` and `event.$fetch` ([#930](https://github.com/nitrojs/nitro/pull/930)) -- **vercel:** Auto-detect runtime version ([#879](https://github.com/nitrojs/nitro/pull/879)) - -### 🩹 Fixes - -- Apply cached rules to overlapping wildcard patterns ([#906](https://github.com/nitrojs/nitro/pull/906)) -- **cloudflare:** Use full mime db ([#933](https://github.com/nitrojs/nitro/pull/933)) - -### ❤️ Contributors - -- Pooya Parsa -- Shohei Maeda -- Luke Nelson -- Oleg Khalin -- Daniel Roe - -## v2.1.2 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.1.1...v2.1.2) - -### 🩹 Fixes - -- **types:** Allow narrowing of the method option in `NitroFetchOptions` ([#883](https://github.com/nitrojs/nitro/pull/883)) -- **vercel-edge:** Add temporary workaround for ‍`process.cwd‍` usage ([#898](https://github.com/nitrojs/nitro/pull/898)) -- **dev:** Don't overwrite proxy headers if already set ([#896](https://github.com/nitrojs/nitro/pull/896)) -- Provide fallback string values for undefined `runtimeConfig` ([#907](https://github.com/nitrojs/nitro/pull/907)) -- **vercel:** Allow non-glob cache rules to apply to `/` ([#908](https://github.com/nitrojs/nitro/pull/908)) -- **externals:** Use stable dependency tree ([#909](https://github.com/nitrojs/nitro/pull/909)) -- **dev:** Mount `src` and `root` as read-only by default ([#920](https://github.com/nitrojs/nitro/pull/920)) - -### 📖 Documentation - -- Fix heroku typo ([#900](https://github.com/nitrojs/nitro/pull/900)) -- Fix stormkit images path ([#903](https://github.com/nitrojs/nitro/pull/903)) -- Fix path for server assets ([#917](https://github.com/nitrojs/nitro/pull/917)) - -### 🏡 Chore - -- Update dependencies ([dbb89a1](https://github.com/nitrojs/nitro/commit/dbb89a1)) -- Update unenv ([91c32c9](https://github.com/nitrojs/nitro/commit/91c32c9)) - -### ✅ Tests - -- Update fixture ([e7209cb](https://github.com/nitrojs/nitro/commit/e7209cb)) -- Fix type test only ([e1e686f](https://github.com/nitrojs/nitro/commit/e1e686f)) - -### ❤️ Contributors - -- Pooya Parsa -- SerKo -- Daniel Roe -- Renato Lacerda -- Chad Lew -- Mike Laumann Bellika -- Harlan Wilton -- Dany Sluijk - -## v2.1.1 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.1.0...v2.1.1) - -### 🩹 Fixes - -- Resolve server assets dir relative to `srcDir` ([#893](https://github.com/nitrojs/nitro/pull/893)) -- **prerender:** Encode urls passed to local fetch ([#891](https://github.com/nitrojs/nitro/pull/891)) - -### 🏡 Chore - -- Update unenv ([b77f082](https://github.com/nitrojs/nitro/commit/b77f082)) -- Format code ([50e1a8f](https://github.com/nitrojs/nitro/commit/50e1a8f)) - -### ❤️ Contributors - -- Pooya Parsa -- Manh-gntvn -- Daniel Roe - -## v2.1.0 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.0.0...v2.1.0) - -### 🚀 Enhancements - -- Add `shouldBypassCache` option to cache utils ([#874](https://github.com/nitrojs/nitro/pull/874)) -- **cache:** Allow async `getKey` option ([#878](https://github.com/nitrojs/nitro/pull/878)) - -### 🩹 Fixes - -- **scan:** Do not dedup middleware handlers ([#880](https://github.com/nitrojs/nitro/pull/880)) -- **externals:** Use portable symlinks ([#882](https://github.com/nitrojs/nitro/pull/882)) - -### 📖 Documentation - -- **deployment:** Heroku with nginx ([#873](https://github.com/nitrojs/nitro/pull/873)) -- **netlify:** Clarify placement of `_redirects` file ([#870](https://github.com/nitrojs/nitro/pull/870)) -- **digitalocean:** Update deployment guide ([#862](https://github.com/nitrojs/nitro/pull/862)) - -### 🏡 Chore - -- Update dependencies ([963c587](https://github.com/nitrojs/nitro/commit/963c587)) - -### ❤️ Contributors - -- Pooya Parsa -- Daniel Roe -- MiniDigger < Martin> -- Christopher Lis -- Ola Alsaker -- Adeyemi Adetayo - -## v2.0.0 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.0.0-rc.1...v2.0.0) - -### 🩹 Fixes - -- Add node16 compatible type declaration ([#868](https://github.com/nitrojs/nitro/pull/868)) -- **externals:** Improve multi version handling ([#871](https://github.com/nitrojs/nitro/pull/871)) - -### ❤️ Contributors - -- Pooya Parsa -- Daniel Roe - -## v2.0.0-rc.1 - -[compare changes](https://github.com/nitrojs/nitro/compare/v2.0.0-rc.0...v2.0.0-rc.1) - -### 🚀 Enhancements - -- **externals:** Apply `production` condition to package.exports ([#867](https://github.com/nitrojs/nitro/pull/867)) -- Enable auto imports from `utils` dir ([#866](https://github.com/nitrojs/nitro/pull/866)) - -### 🩹 Fixes - -- **prerender:** Update preview command to serve matching routes ([#864](https://github.com/nitrojs/nitro/pull/864)) -- **externals:** Support orphan files in `node_modules` ([#865](https://github.com/nitrojs/nitro/pull/865)) -- Avoid hiding original rollup error message ([a5586f8](https://github.com/nitrojs/nitro/commit/a5586f8)) -- **cache:** Only update cache in storage once per pending request ([#861](https://github.com/nitrojs/nitro/pull/861)) - -### 🏡 Chore - -- Lint with `eslint --cache` and improve types in `.eslintrc` ([#863](https://github.com/nitrojs/nitro/pull/863)) -- Update dependencies ([c52d256](https://github.com/nitrojs/nitro/commit/c52d256)) -- Remove random import ([246b726](https://github.com/nitrojs/nitro/commit/246b726)) - -### ❤️ Contributors - -- Pooya Parsa -- Yasser Lahbibi -- O-az -- Daniel Roe - -## v2.0.0-rc.0 - -[compare changes](https://github.com/nitrojs/nitro/compare/v1.0.0...v2.0.0-rc.0) - -### 🚀 Enhancements - -- ⚠️ Upgrade rollup to 3.x ([#580](https://github.com/nitrojs/nitro/pull/580)) -- **types:** Correctly type $fetch based on the method ([#686](https://github.com/nitrojs/nitro/pull/686)) -- **cli:** `prepare` command ([#774](https://github.com/nitrojs/nitro/pull/774)) -- **cache:** Allow setting custom `getKey` for `defineCachedEventHandler` ([#744](https://github.com/nitrojs/nitro/pull/744)) -- **dev:** Support for `/_vfs.json` ([#809](https://github.com/nitrojs/nitro/pull/809)) -- **netlify:** Use esm entrypoint ([#833](https://github.com/nitrojs/nitro/pull/833)) -- ⚠️ Rewrite external copy with multi version hoisting support ([#782](https://github.com/nitrojs/nitro/pull/782)) -- Add `shouldInvalidateCache ` option to cache utils ([#746](https://github.com/nitrojs/nitro/pull/746)) -- `edgio` preset (replacing `layer0`) ([#858](https://github.com/nitrojs/nitro/pull/858)) -- Support `maxAge` for public assets ([#860](https://github.com/nitrojs/nitro/pull/860)) -- Support `staleMaxAge: -1` to always respond stale value ([#857](https://github.com/nitrojs/nitro/pull/857)) - -### 🩹 Fixes - -- GitHub template ([#712](https://github.com/nitrojs/nitro/pull/712)) -- **deno:** Implement readAsset ([#694](https://github.com/nitrojs/nitro/pull/694)) -- Normalize nitro plugin paths to url in development ([#732](https://github.com/nitrojs/nitro/pull/732)) -- Use file urls for auto-imports in development ([#733](https://github.com/nitrojs/nitro/pull/733)) -- Initialise imports.imports ([#737](https://github.com/nitrojs/nitro/pull/737)) -- Allow optional `output` property in user rollup config ([#751](https://github.com/nitrojs/nitro/pull/751)) -- Accept both upper/lower-case methods ([#752](https://github.com/nitrojs/nitro/pull/752)) -- **prerender:** Check each segment length is less than 255 chars and whole path 1024 ([#757](https://github.com/nitrojs/nitro/pull/757)) -- Include only compressible mime types ([#761](https://github.com/nitrojs/nitro/pull/761)) -- Remove base url before calculating route rules ([#767](https://github.com/nitrojs/nitro/pull/767)) -- **netlify, vercel:** Order route rules from most specific + avoid double-rendering root ([#768](https://github.com/nitrojs/nitro/pull/768)) -- **build:** Correctly formatted fs tree ([#778](https://github.com/nitrojs/nitro/pull/778)) -- **prerender:** Decode urls to allow comma in the `x-nitro-prerender` header ([#799](https://github.com/nitrojs/nitro/pull/799)) -- **build:** Do not override publicAssets ([#817](https://github.com/nitrojs/nitro/pull/817)) -- **dev:** Improve vfs ui ([#802](https://github.com/nitrojs/nitro/pull/802)) -- Resolve and include scanDirs within `node_modules` for auto import ([#812](https://github.com/nitrojs/nitro/pull/812)) -- **netlify, vercel:** Explicit server rendering with disabled cache/swr ([#829](https://github.com/nitrojs/nitro/pull/829)) -- **prerender:** Check link's pathname only for extensions ([#791](https://github.com/nitrojs/nitro/pull/791)) -- **runtime:** Disable server-timing header via options.timing ([#823](https://github.com/nitrojs/nitro/pull/823)) -- Avoid using file urls for normalized paths in options ([7517293](https://github.com/nitrojs/nitro/commit/7517293)) -- Rollup treeshake is dump ([2ce4edb](https://github.com/nitrojs/nitro/commit/2ce4edb)) -- **externals:** Normalize `inline` and `external` windows paths ([0638f64](https://github.com/nitrojs/nitro/commit/0638f64)) -- **netlify, aws:** Omit cookies from v1 response ([#834](https://github.com/nitrojs/nitro/pull/834)) -- Filter unique scanned handlers ([#807](https://github.com/nitrojs/nitro/pull/807)) -- **nitro:** Resolve server asset dirs relative to `srcDir` ([#825](https://github.com/nitrojs/nitro/pull/825)) -- **public-assets:** Mock readAsset promise properly ([#851](https://github.com/nitrojs/nitro/pull/851)) -- **externals:** Avoid recursive package links ([b77735e](https://github.com/nitrojs/nitro/commit/b77735e)) - -### 💅 Refactors - -- Upgrade and reduce usage of `fs-extra` ([cfbd029](https://github.com/nitrojs/nitro/commit/cfbd029)) -- Update `event.` to `event.node.` ([#828](https://github.com/nitrojs/nitro/pull/828)) - -### 📖 Documentation - -- Fix url in auto-imports guide ([#683](https://github.com/nitrojs/nitro/pull/683)) -- Fix spelling of cluster ([#720](https://github.com/nitrojs/nitro/pull/720)) -- Wording change ([#724](https://github.com/nitrojs/nitro/pull/724)) -- Fix readme grammar ([#813](https://github.com/nitrojs/nitro/pull/813)) -- Fix deprecated function in routing example ([#816](https://github.com/nitrojs/nitro/pull/816)) -- Add new render deployment example & steps ([#811](https://github.com/nitrojs/nitro/pull/811)) -- Fix typo in code block ([#830](https://github.com/nitrojs/nitro/pull/830)) -- Add cache base option example & description ([#781](https://github.com/nitrojs/nitro/pull/781)) - -### 🏡 Chore - -- Lint repository with eslint config and format with prettier ([#739](https://github.com/nitrojs/nitro/pull/739)) -- Limit prettier lint to src ([6a735b1](https://github.com/nitrojs/nitro/commit/6a735b1)) -- Fix type issue ([a60e4bd](https://github.com/nitrojs/nitro/commit/a60e4bd)) -- Fix lint issues ([7ee8e7f](https://github.com/nitrojs/nitro/commit/7ee8e7f)) -- Disable failing api type tests ([1d9102a](https://github.com/nitrojs/nitro/commit/1d9102a)) -- Fix lint issue ([30e4d32](https://github.com/nitrojs/nitro/commit/30e4d32)) -- Add missing parenthesis in header ([#801](https://github.com/nitrojs/nitro/pull/801)) -- Add lint fix command shortcut ([#835](https://github.com/nitrojs/nitro/pull/835)) -- Update lockfile ([bb9ac5b](https://github.com/nitrojs/nitro/commit/bb9ac5b)) - -### ✅ Tests - -- Add tests for dev server and proxy ([#644](https://github.com/nitrojs/nitro/pull/644)) -- Re-enable api type tests and fix type assertion ([#772](https://github.com/nitrojs/nitro/pull/772)) -- Update fixtures ([a52c832](https://github.com/nitrojs/nitro/commit/a52c832)) - -### 🎨 Styles - -- Lint code ([15edef0](https://github.com/nitrojs/nitro/commit/15edef0)) - -### 🤖 CI - -- Run tests against windows as well ([#837](https://github.com/nitrojs/nitro/pull/837)) - -#### ⚠️ Breaking Changes - -- ⚠️ Upgrade rollup to 3.x ([#580](https://github.com/nitrojs/nitro/pull/580)) -- ⚠️ Rewrite external copy with multi version hoisting support ([#782](https://github.com/nitrojs/nitro/pull/782)) - -### ❤️ Contributors - -- Pooya Parsa -- Yasser Lahbibi -- Harlan Wilton -- Christian Preston -- Louis Haftmann -- Daniel Roe -- Xin Du (Clark) -- Jonas Thelemann -- Shoubhit Dash -- Anthony Fu -- Chambers -- Patrick Schnyder -- Alvar Lagerlöf -- Pascal -- Eduardo San Martin Morote -- Johann Schopplich -- Nathan Chase -- Dany Sluijk -- Alexander Lichter -- Nobody5050 -- Ʀᴀʏ -- Nozomu Ikuta -- James Ray -- SerKo - -## [1.0.0](https://github.com/nitrojs/nitro/compare/v1.0.0-1...v1.0.0) (2022-11-16) - -## [1.0.0-1](https://github.com/nitrojs/nitro/compare/v1.0.0-0...v1.0.0-1) (2022-11-16) - -### Features - -- **vercel:** incremental static generation + swr ([#545](https://github.com/nitrojs/nitro/issues/545)) ([88ce2de](https://github.com/nitrojs/nitro/commit/88ce2de96ef5bab1e945e539e61581cd33aaf54b)) - -### Bug Fixes - -- upgrade hookable to 5.x ([dc3383b](https://github.com/nitrojs/nitro/commit/dc3383b4c74f2411600af271ccc30753a727e1fb)) - -## [1.0.0-0](https://github.com/nitrojs/nitro/compare/v0.6.2...v1.0.0-0) (2022-11-15) - -### ⚠ BREAKING CHANGES - -- remove deprecated `autoImport` - -- remove deprecated `autoImport` ([c99fa44](https://github.com/nitrojs/nitro/commit/c99fa441eeb1992af087a6bec85ea868a5eb1e62)) - -### [0.6.2](https://github.com/nitrojs/nitro/compare/v0.6.1...v0.6.2) (2022-11-15) - -### Bug Fixes - -- **cloudflare:** pass raw body instead of parsing it ([#629](https://github.com/nitrojs/nitro/issues/629)) ([837f894](https://github.com/nitrojs/nitro/commit/837f894c310ad27854cfa0dc538c6c033e2a3d41)) - -## 0.4.24 - -### 🚀 Enhancements - -- Add cloudflare-pages preset (#210) -- Support prerendering binary files (#320) -- Opt-in option to compress public assets using `gzip` and `br` (#449) -- Allow specifying wasm plugin options (#450) -- Allow using `extends` alongside with `preset` (6a43985) - -### 🩹 Fixes - -- **azure:** Fix route name (#430) -- Update types for defu usage (0f241bc) -- Add resolved side-effect for node-fetch-native (#435) -- **aws-lambda:** Join cookies with semicolon (#356) -- **aws-lambda:** Fix normalizeIncomingHeaders (#418) -- **aws-lambda:** Return outgoing cookies on response objects (#357) -- **aws-lambda:** Add `multiValueQueryStringParameters` to aws preset (#398) -- ⚠️ Update unenv to 0.6.x (#438) -- Add code location and codeframe for rollup errors (#406) -- **prerender:** Allow updating route contents (#452) -- **externals:** ⚠️ Fall back to `mlly` resolver in more cases (#431) -- ⚠️ `NITRO_PRESET` should have highest periority (92d711f) - -### 💅 Refactors - -- ⚠️ Rename options `autoImport` to `imports` (#433) -- Utilize knitwork to generate safe variable names (#447) - -### 📖 Documentation - -- Migrate to docus (#365) -- Simplify deploy index route (a1d7b17) -- **storage:** Fix typo (#424) - -### 🏡 Chore - -- Update lock (4ceeee2) -- Narrow plugin override type (b4e24f6) -- Add `@vitest/coverage-c8` (4a5e565) -- Remove unused `@types/jsdom` from dependencies (#429) -- Add vitest config (ab59150) - -### 📦 Build - -- Expose `package.json` subpath export (d0029c0) -- Use changelogen to bump edge and generate chagelog (679e356) - -#### ⚠️ Breaking Changes - -- ⚠️ Update unenv to 0.6.x (#438) -- **externals:** ⚠️ Fall back to `mlly` resolver in more cases (#431) -- ⚠️ `NITRO_PRESET` should have highest periority (92d711f) -- ⚠️ Rename options `autoImport` to `imports` (#433) - -### ❤️ Contributors - -- Ahad Birang -- Alexander Lichter -- Anthony Fu -- Daniel Roe -- Dániel Földi -- Eckhardt (Kaizen) Dreyer -- Julien Huang -- Pooya Parsa -- Sören Schwert -- Tobias Diez -- Yaël Guilloux - -### [0.4.24](https://github.com/nitrojs/nitro/compare/v0.4.23...v0.4.24) (2022-08-12) - -### Bug Fixes - -- **renderer:** do not use default error fallback ([80081b0](https://github.com/nitrojs/nitro/commit/80081b0b70d845c29ec24d98573c2179590fafc8)) - -### [0.4.23](https://github.com/nitrojs/nitro/compare/v0.4.22...v0.4.23) (2022-08-12) - -### Bug Fixes - -- **renderer:** handle unhandled errors ([319b277](https://github.com/nitrojs/nitro/commit/319b27789d5c5a7bb154bd264408dc0689104732)) - -### [0.4.22](https://github.com/nitrojs/nitro/compare/v0.4.21...v0.4.22) (2022-08-11) - -### Bug Fixes - -- fix dist dir check regex ([6cad682](https://github.com/nitrojs/nitro/commit/6cad6821039328e099b4b1a6cba5f73eba42a111)) - -### [0.4.21](https://github.com/nitrojs/nitro/compare/v0.4.20...v0.4.21) (2022-08-11) - -### Bug Fixes - -- properly resolve dist dir ([d7c65e6](https://github.com/nitrojs/nitro/commit/d7c65e6c4c2257e044c8c6e0f46b0b1739af1a4d)) - -### [0.4.20](https://github.com/nitrojs/nitro/compare/v0.4.19...v0.4.20) (2022-08-11) - -### [0.4.19](https://github.com/nitrojs/nitro/compare/v0.4.18...v0.4.19) (2022-08-11) - -### Bug Fixes - -- only log unhandled and fatal errors ([#407](https://github.com/nitrojs/nitro/issues/407)) ([2d5b039](https://github.com/nitrojs/nitro/commit/2d5b039499f30ed9fbef19495503f95225a59159)) - -### [0.4.18](https://github.com/nitrojs/nitro/compare/v0.4.17...v0.4.18) (2022-08-09) - -### Bug Fixes - -- **netlify:** update rollup output file ([8965bd5](https://github.com/nitrojs/nitro/commit/8965bd5b72c2599e20e1592175ef154449613358)) - -### [0.4.17](https://github.com/nitrojs/nitro/compare/v0.4.16...v0.4.17) (2022-08-09) - -### Features - -- **netlify:** emit `server.js` to leverage native esm ([#401](https://github.com/nitrojs/nitro/issues/401)) ([8304ae2](https://github.com/nitrojs/nitro/commit/8304ae24b5397c1a9dd64d1a5eb25d62069da900)) - -### [0.4.16](https://github.com/nitrojs/nitro/compare/v0.4.15...v0.4.16) (2022-08-09) - -### Bug Fixes - -- **prerender:** prerender `x-nitro` links without crawlLinks option ([46b445f](https://github.com/nitrojs/nitro/commit/46b445f8b21409540a66973be8fb693cce7812dc)) - -### [0.4.15](https://github.com/nitrojs/nitro/compare/v0.4.14...v0.4.15) (2022-08-09) - -### Features - -- **prerender:** basic ignore support ([a6cbbbe](https://github.com/nitrojs/nitro/commit/a6cbbbe482243a3d8dc4c3917ec406b74fdb2a8f)) - -### Bug Fixes - -- **prerender:** apply extension filter only to parsed links ([541b0b0](https://github.com/nitrojs/nitro/commit/541b0b0662017ee8d1f5448a985d27c70a9e6303)) -- set `x-nitro-prerender` header as lower-case ([9cee698](https://github.com/nitrojs/nitro/commit/9cee698c4c12b10cd588efc3234b69acdedb252d)) - -### [0.4.14](https://github.com/nitrojs/nitro/compare/v0.4.13...v0.4.14) (2022-08-08) - -### Features - -- call `render:response` hook for `defineRenderHandler` ([8238f38](https://github.com/nitrojs/nitro/commit/8238f3801aa959f8707c48e2d5777b54a6a7f74d)) - -### Bug Fixes - -- expose `RenderResponse` and `RenderHandler` types ([e0ec2b2](https://github.com/nitrojs/nitro/commit/e0ec2b21c706e3882e57f70f0054c84a0e18186a)) - -### [0.4.13](https://github.com/nitrojs/nitro/compare/v0.4.12...v0.4.13) (2022-08-08) - -### Features - -- `defineRenderHandler` ([#395](https://github.com/nitrojs/nitro/issues/395)) ([758b046](https://github.com/nitrojs/nitro/commit/758b0463f19764ea799502795b52d6a547b37f81)) -- add h3 auto imports preset ([#397](https://github.com/nitrojs/nitro/issues/397)) ([fbadeb7](https://github.com/nitrojs/nitro/commit/fbadeb77b867869a6a9268115531fe4d06cb677f)) -- auto scan plugins ([0d1cd4d](https://github.com/nitrojs/nitro/commit/0d1cd4d7638797c7c5ec7fc21c28eca0f81edf01)) -- enable response type infer for API routes with params ([#222](https://github.com/nitrojs/nitro/issues/222)) ([082d58f](https://github.com/nitrojs/nitro/commit/082d58fd6dc736047d69d41510d63111c7b16cc6)) - -### Bug Fixes - -- **cache:** generate hashed path keys ([6104c54](https://github.com/nitrojs/nitro/commit/6104c54b946b616d475f970d02b7605fd69211a9)) -- **config:** enable dotenv in development ([#347](https://github.com/nitrojs/nitro/issues/347)) ([ec086c6](https://github.com/nitrojs/nitro/commit/ec086c6a33f84ace17d2a40b8703d3e1ca97d7ae)) -- include dotfiles in public assets ([#361](https://github.com/nitrojs/nitro/issues/361)) ([8a744fb](https://github.com/nitrojs/nitro/commit/8a744fbb38bc9b3c6a01d6bbce08c4aa64e7734a)) -- **options:** add default aliases and resolve plugins ([f04560b](https://github.com/nitrojs/nitro/commit/f04560b6b92317a45ed384f61b5c74e9aa1f825d)) -- **options:** exclude `buildDir` for auto-imports ([#355](https://github.com/nitrojs/nitro/issues/355)) ([5219c53](https://github.com/nitrojs/nitro/commit/5219c53d5c5dd1aacc5a9647831a5131a85078d5)) -- **prerender:** remove `baseURL` from generated file paths ([#329](https://github.com/nitrojs/nitro/issues/329)) ([26c15ca](https://github.com/nitrojs/nitro/commit/26c15ca02e332643e06949fa4f1dbf7bee8a479d)) -- **server-assets:** escape asset file names ([7aaab6d](https://github.com/nitrojs/nitro/commit/7aaab6d0262ceb6cd8487fc046eb4f866394cfe9)) -- sort aliases to ensure priority is given to more specific aliases ([#388](https://github.com/nitrojs/nitro/issues/388)) ([2a36b1e](https://github.com/nitrojs/nitro/commit/2a36b1e7390681092d10f0d2c308f7e651fa4e9a)) -- update scule to handle runtime config with numbers ([64b740e](https://github.com/nitrojs/nitro/commit/64b740eea43be93ed5c56da30cd0eaf28305c352)), closes [nuxt/framework#6172](https://github.com/nuxt/framework/issues/6172) -- update unstorage to prevent path traverse ([d5d802f](https://github.com/nitrojs/nitro/commit/d5d802f3e18257b4dab4c2f8bcc27d455543fe22)) -- **worker:** preserve esmodule symbol for dynamic imports ([#354](https://github.com/nitrojs/nitro/issues/354)) ([0cd5121](https://github.com/nitrojs/nitro/commit/0cd51217d857b8f7090989d92fe3f1d99f41b0f6)) - -### [0.4.12](https://github.com/nitrojs/nitro/compare/v0.4.11...v0.4.12) (2022-07-13) - -### Bug Fixes - -- **vercel, vercel-edge:** set version as number ([f476cfc](https://github.com/nitrojs/nitro/commit/f476cfc3e33d0b759e604ff6c0c61ea272e1379a)) - -### [0.4.11](https://github.com/nitrojs/nitro/compare/v0.4.10...v0.4.11) (2022-07-13) - -### Bug Fixes - -- **vercel-edge:** properly set rollup options ([ad5b735](https://github.com/nitrojs/nitro/commit/ad5b7355d0a4463c0bebd1386ebf2049360bc3e1)) - -### [0.4.10](https://github.com/nitrojs/nitro/compare/v0.4.9...v0.4.10) (2022-07-13) - -### Features - -- `vercel-edge` provider ([#337](https://github.com/nitrojs/nitro/issues/337)) ([ad2b976](https://github.com/nitrojs/nitro/commit/ad2b976536c80a423b48facda455efce6b0be365)) -- **rollup:** support `development` and `production` export conditions ([f60e6eb](https://github.com/nitrojs/nitro/commit/f60e6eba50e4db4dc48c5d4f860d61f1cc55613b)) -- **vercel:** update to the v3 output api ([#336](https://github.com/nitrojs/nitro/issues/336)) ([9ac4be2](https://github.com/nitrojs/nitro/commit/9ac4be267d380851c469a299c9834e9200836d3a)) - -### Bug Fixes - -- call `rollup:before` before generating rollup config ([#335](https://github.com/nitrojs/nitro/issues/335)) ([292b495](https://github.com/nitrojs/nitro/commit/292b495e8c1eb620202cd3f1639c59f0a3ce203f)) -- **vercel-edge:** use esm default export ([7d251f5](https://github.com/nitrojs/nitro/commit/7d251f5ff0041cccc308ae7f144dcf2a0017559b)) -- **vercel:** add back filesystem route handlers ([bba4064](https://github.com/nitrojs/nitro/commit/bba4064356bf8340ed8e9eaca0d7deadbcc904fb)) -- **vercel:** update output config ([daecb91](https://github.com/nitrojs/nitro/commit/daecb91ae27e8f77ea0aa7e61a6dc383707a0c49)), closes [#336](https://github.com/nitrojs/nitro/issues/336) - -### [0.4.9](https://github.com/nitrojs/nitro/compare/v0.4.8...v0.4.9) (2022-06-29) - -### Features - -- expose router in NitroApp ([#302](https://github.com/nitrojs/nitro/issues/302)) ([ef5e7f1](https://github.com/nitrojs/nitro/commit/ef5e7f19cd9d332b4fdb97477d05f6d319b6d2c5)) -- **service-worker:** inject registration script to all pages ([#299](https://github.com/nitrojs/nitro/issues/299)) ([486f236](https://github.com/nitrojs/nitro/commit/486f236c1e96134c0ee8021ff5d04e93fe819e75)) - -### Bug Fixes - -- get storage mounts type from unstorage ([134f89f](https://github.com/nitrojs/nitro/commit/134f89f5d0c3045e3435b27c56f89171379c4c81)) -- **azure:** pass query params to local call ([#318](https://github.com/nitrojs/nitro/issues/318)) ([f1fe6cd](https://github.com/nitrojs/nitro/commit/f1fe6cd9ad9621546eb66a9b8484d1870ae86110)) -- export runtime types directly from `nitropack` ([#301](https://github.com/nitrojs/nitro/issues/301)) ([34b8c4d](https://github.com/nitrojs/nitro/commit/34b8c4d921b2c6dc708ad6c11cb765935b66b3c0)) -- **isPublicAssetURL:** assets should treat as public ([#312](https://github.com/nitrojs/nitro/issues/312)) ([e165b3b](https://github.com/nitrojs/nitro/commit/e165b3bdabf8a0082387060df89a1726a3056e0a)) -- **prerender:** avoid adding duplicate `baseURL` for local fetch ([#289](https://github.com/nitrojs/nitro/issues/289)) ([cbc7ba3](https://github.com/nitrojs/nitro/commit/cbc7ba3835df539116ca6560a85365615af55fbb)) -- **types:** allow `autoImport` option to be false ([#296](https://github.com/nitrojs/nitro/issues/296)) ([3aa3bcf](https://github.com/nitrojs/nitro/commit/3aa3bcfef4b98528db6b31d620177a57a69afdf4)) - -### [0.4.8](https://github.com/nitrojs/nitropack/compare/v0.4.7...v0.4.8) (2022-06-15) - -### Bug Fixes - -- disable auto import include for scanDirs ([4c057cd](https://github.com/nitrojs/nitropack/commit/4c057cdd939485c4f416f33d776dadaeb498ed3e)), closes [#277](https://github.com/nitrojs/nitropack/issues/277) - -### [0.4.7](https://github.com/nitrojs/nitropack/compare/v0.4.6...v0.4.7) (2022-06-14) - -### Bug Fixes - -- check if socket address/port/family are set ([#287](https://github.com/nitrojs/nitropack/issues/287)) ([8fb3ad9](https://github.com/nitrojs/nitropack/commit/8fb3ad93b9c2d0da9a95183818cf228c1b16b99b)) -- don't use file url when building prerenderer ([#286](https://github.com/nitrojs/nitropack/issues/286)) ([2e7c548](https://github.com/nitrojs/nitropack/commit/2e7c5482c736d8c749d9151bc2f588ebb69a4a83)) - -### [0.4.6](https://github.com/nitrojs/nitropack/compare/v0.4.5...v0.4.6) (2022-06-13) - -### Features - -- update unstorage to 0.5.x ([c5cabbf](https://github.com/nitrojs/nitropack/commit/c5cabbf6453fe7da46f52a899d2c79fdb56d5b2c)) - -### [0.4.5](https://github.com/nitrojs/nitropack/compare/v0.4.4...v0.4.5) (2022-06-12) - -### Features - -- **dev:** add `x-forwarded` headers ([#247](https://github.com/nitrojs/nitropack/issues/247)) ([2d50312](https://github.com/nitrojs/nitropack/commit/2d50312c6f84f4a5ea152556ecd143a0944f9fc1)) - -### Bug Fixes - -- add `scanDirs` to auto-import include ([#277](https://github.com/nitrojs/nitropack/issues/277)) ([3f8a08e](https://github.com/nitrojs/nitropack/commit/3f8a08ec6e8421c7311fad8c306fe28586ee83f8)) -- append .cache to the key of cached routes/functions ([#249](https://github.com/nitrojs/nitropack/issues/249)) ([1d4328c](https://github.com/nitrojs/nitropack/commit/1d4328cceb4245ef01ce789ba6b85a7d4956e22c)) -- avoid empty scanned route (resolves [#283](https://github.com/nitrojs/nitropack/issues/283)) ([a087673](https://github.com/nitrojs/nitropack/commit/a0876732acadfda2e2c2699a947ea08e6af28d0d)) -- **cache:** expose all cache aliases and types ([361d12f](https://github.com/nitrojs/nitropack/commit/361d12f61a102caac7c9c32ab25d3e662cec80a9)) -- **cache:** invalidate entry before calling resolver ([#271](https://github.com/nitrojs/nitropack/issues/271)) ([7358d5b](https://github.com/nitrojs/nitropack/commit/7358d5bdc8131f98d1d29aff23dceb4bb702b879)) -- **cache:** normalize path keys for `defineCachedEventHandler` ([97625ec](https://github.com/nitrojs/nitropack/commit/97625ec7fc4d44529fe7e2be16bbeaa3e4f38b98)) -- **cloudflare:** use `@cloudflare/wrangler` until we support wrangler 2 ([#265](https://github.com/nitrojs/nitropack/issues/265)) ([d7fa6ce](https://github.com/nitrojs/nitropack/commit/d7fa6ce00a97f0573c5524fb0ee4080b2aa58542)) -- exclude internal `/_*`, `/api/_*` routes from NitroFetchRequest type ([#232](https://github.com/nitrojs/nitropack/issues/232)) ([00aa131](https://github.com/nitrojs/nitropack/commit/00aa13161f3c8da451614925daf4cd897a838aa3)) -- **stormkit:** update request signature ([#264](https://github.com/nitrojs/nitropack/issues/264)) ([78bf46a](https://github.com/nitrojs/nitropack/commit/78bf46a324b304516574c538b9b59f50b1f21ed0)) - -### [0.4.4](https://github.com/nitrojs/nitropack/compare/v0.4.3...v0.4.4) (2022-05-11) - -### Bug Fixes - -- update `NitroFetchRequest` type to support `string` type ([#226](https://github.com/nitrojs/nitropack/issues/226)) ([3542b61](https://github.com/nitrojs/nitropack/commit/3542b6148a4068e4c2dc74c617fa6e225739bf12)) -- update unenv and add `node-fetch-native/polyfill` to `moduleSideEffects` ([e70a9f0](https://github.com/nitrojs/nitropack/commit/e70a9f0b4333ab4804a4afc31e7c666e4ca77e59)) - -### [0.4.3](https://github.com/nitrojs/nitropack/compare/v0.4.2...v0.4.3) (2022-05-10) - -### Features - -- add `NitroFetchRequest` type and enhance $fetch's request type ([#209](https://github.com/nitrojs/nitropack/issues/209)) ([57b9ed0](https://github.com/nitrojs/nitropack/commit/57b9ed0bc4ef15dc36a58ae60810feaedd367c15)) -- add `prerender:route` hook ([#213](https://github.com/nitrojs/nitropack/issues/213)) ([9c9fb34](https://github.com/nitrojs/nitropack/commit/9c9fb3401246e534374588c681cb77871b0efaaa)) -- **prerender:** add preview command ([#217](https://github.com/nitrojs/nitropack/issues/217)) ([08614c5](https://github.com/nitrojs/nitropack/commit/08614c50f0365c6d68cf2b18841ac13a3c62cdaa)) -- show stack-trace of unhandled errors with `DEBUG` env ([#212](https://github.com/nitrojs/nitropack/issues/212)) ([b366f3f](https://github.com/nitrojs/nitropack/commit/b366f3fae0605af75b2eb86839c5a94804a52ffb)) - -### Bug Fixes - -- add missing include path `../../**/*` in generated tsconfig.json ([#205](https://github.com/nitrojs/nitropack/issues/205)) ([8978404](https://github.com/nitrojs/nitropack/commit/89784044de3c5d7b518225488684f0b391a372be)) -- respect baseURL in prerendering ([#219](https://github.com/nitrojs/nitropack/issues/219)) ([3e8eddb](https://github.com/nitrojs/nitropack/commit/3e8eddb20a609c1405d1e531dba2fba3a39384db)) -- set built-in storage mounts before nitro init ([d1c6c64](https://github.com/nitrojs/nitropack/commit/d1c6c64384afdee7424eebc51a4c42978f4dc1c5)) - -### [0.4.2](https://github.com/nitrojs/nitropack/compare/v0.4.1...v0.4.2) (2022-05-07) - -### Bug Fixes - -- **node, preereender:** add handler for `unhandledRejection` ([3319912](https://github.com/nitrojs/nitropack/commit/3319912635320a8da1022045042b2c041fa6f6c2)) -- **prerender:** only crawl known extensions (non or `.json`) ([2dbc8b9](https://github.com/nitrojs/nitropack/commit/2dbc8b9b0d9122a797009e31b1303b3fc625d0ac)) - -### [0.4.1](https://github.com/nitrojs/nitropack/compare/v0.4.0...v0.4.1) (2022-05-06) - -### Bug Fixes - -- support fallback for `import.meta` per chunk ([5a83ec6](https://github.com/nitrojs/nitropack/commit/5a83ec62c4db52b11c88a18baa5c16bca3f71b4f)) -- use distinct prefix for lazy handler imports ([0cc7be1](https://github.com/nitrojs/nitropack/commit/0cc7be13a1ec125d888bc40f00be280bdc81c8fe)) - -## [0.4.0](https://github.com/nitrojs/nitropack/compare/v0.3.12...v0.4.0) (2022-05-05) - -### ⚠ BREAKING CHANGES - -- **cache:** only accept event handler for `defineCachedEventHandler` -- **prerender:** write html files to subfolder (resolves #166) - -### Features - -- `nitro.storage` ([e1c234e](https://github.com/nitrojs/nitropack/commit/e1c234eaa59db02bbc76d5b0272b153bb2a238ae)) -- add `X-Nitro-Prerender` header to detect prerendering ([11e732b](https://github.com/nitrojs/nitropack/commit/11e732b6d3c53ca2d8b7e09be9f0da4550eb5d0c)) -- allow explicit middleware handlers ([23d8cde](https://github.com/nitrojs/nitropack/commit/23d8cde6942c051872aa4286b49ee7ee88ee9254)) -- **cache:** only accept event handler for `defineCachedEventHandler` ([7e72b8f](https://github.com/nitrojs/nitropack/commit/7e72b8f327fb0141bce32d2b0b50e357ec6a7a07)) -- expose all assets to `nitro.vfs` and `/_vfs` endpoint (resolves [#173](https://github.com/nitrojs/nitropack/issues/173)) ([9bf2d71](https://github.com/nitrojs/nitropack/commit/9bf2d710583d5b6297a1afed1c3d33b8c8826e50)) -- extend prerender links from `X-Nitro-Prerender` (resolves [#115](https://github.com/nitrojs/nitropack/issues/115)) ([9423524](https://github.com/nitrojs/nitropack/commit/94235246d155c13f886a26a24162d6fd6e9c67d5)) -- named wildcard params ([233e024](https://github.com/nitrojs/nitropack/commit/233e024c75940c26c9113b374bbd7e35a8e0a31f)) -- **prerender:** write html files to subfolder (resolves [#166](https://github.com/nitrojs/nitropack/issues/166)) ([cdcd35a](https://github.com/nitrojs/nitropack/commit/cdcd35adf3e4f1d3902605f97559c0dcf6d0febf)) -- **rollup:** allow edit of commonJs plugin options ([#187](https://github.com/nitrojs/nitropack/issues/187)) ([c7759e9](https://github.com/nitrojs/nitropack/commit/c7759e90a67987ef20e5fadacc354f9934ef9cc3)) -- **rollup:** fail build when externals are not allowed and cannot resolve id ([ff2dd44](https://github.com/nitrojs/nitropack/commit/ff2dd443641ad2b72b1e22c2075a20099222e2c6)) -- universal `import.meta` (resolves [#181](https://github.com/nitrojs/nitropack/issues/181)) ([929322b](https://github.com/nitrojs/nitropack/commit/929322b5c6e3afd9f631613f07dcdd4e81a88dab)) -- update unenv ([04e2f26](https://github.com/nitrojs/nitropack/commit/04e2f2605b899e20a151efb62a6f81ccf1cfbc4e)) - -### Bug Fixes - -- **cache:** preserve event context (resolves [#189](https://github.com/nitrojs/nitropack/issues/189)) ([6cdbc4a](https://github.com/nitrojs/nitropack/commit/6cdbc4ac72dbec999d19eb3750ce392a462610a6)) -- enable lazy only when explicitly set (enable for api and rotues by default) ([247cfca](https://github.com/nitrojs/nitropack/commit/247cfca88e2f9aea529d23fc42af4e833f7c7cc2)) -- **handlers:** respect default value for lazy ([89da30a](https://github.com/nitrojs/nitropack/commit/89da30a7740398fe5531f223f15357dcc9ddb807)) -- improve bundled storage ([#179](https://github.com/nitrojs/nitropack/issues/179)) ([d4cb863](https://github.com/nitrojs/nitropack/commit/d4cb863c46047564d170bb183444e5bcdcb619c9)) -- **prerender:** allow all extensions (resolves [#190](https://github.com/nitrojs/nitropack/issues/190)) ([4b15520](https://github.com/nitrojs/nitropack/commit/4b15520f18f62108e9260fbc9a2881f838710fda)) -- **prerender:** support relative urls ([970286d](https://github.com/nitrojs/nitropack/commit/970286dacfcf8336f9c4d46c3f774d32bd0dfbca)) -- **rollup:** enable `preferBuiltins` only for node targets ([32f598a](https://github.com/nitrojs/nitropack/commit/32f598afaec65014e499980baa18cd7bb331b6ce)) -- **rollup:** respect `rollupConfig` options to override default config ([43b1d02](https://github.com/nitrojs/nitropack/commit/43b1d023117060a216c290888c71297c3b3376f3)) -- **rollup:** set `NODE_ENV` to `prerender` when prerendering ([2b7209a](https://github.com/nitrojs/nitropack/commit/2b7209aab8667d0470949b636ff383d85057a08d)) -- **worker:** use `iife` format by default ([6c8cae7](https://github.com/nitrojs/nitropack/commit/6c8cae7e25c4a24e5d85e8e322248e2beebedef3)) - -### [0.3.12](https://github.com/nitrojs/nitropack/compare/v0.3.11...v0.3.12) (2022-05-02) - -### Bug Fixes - -- add missing `prefixStorage` import for bundled storage ([defa4de](https://github.com/nitrojs/nitropack/commit/defa4defeae038a01464821969986240b9288088)) -- **storage:** skip bundled storage for dev and prerender ([31a3957](https://github.com/nitrojs/nitropack/commit/31a3957757614c4db61c271ecdb7c9c8f4e22d4a)) - -### [0.3.11](https://github.com/nitrojs/nitropack/compare/v0.3.10...v0.3.11) (2022-05-02) - -### Bug Fixes - -- **storage:** remove unused `prefixStorage` import ([7376c6d](https://github.com/nitrojs/nitropack/commit/7376c6dbc31cf277828160c7e22b4213fe142780)) -- **storage:** use `devStorage` for dev and prerender ([93c4d85](https://github.com/nitrojs/nitropack/commit/93c4d851fd08b6b2fe9952f1ea833ed36899273a)) - -### [0.3.10](https://github.com/nitrojs/nitropack/compare/v0.3.9...v0.3.10) (2022-05-02) - -### Features - -- experimental bundled storage ([#160](https://github.com/nitrojs/nitropack/issues/160)) ([308e7c7](https://github.com/nitrojs/nitropack/commit/308e7c7d869345565747f9d986a6e77e9789cc1d)) - -### Bug Fixes - -- **deps:** pin `@rollup/plugin-node-resolve` due to cloudflare issue ([3ecb813](https://github.com/nitrojs/nitropack/commit/3ecb813e72007ad4a8bb14f1b0892cee9761c66f)) - -### [0.3.9](https://github.com/nitrojs/nitropack/compare/v0.3.8...v0.3.9) (2022-05-02) - -### Bug Fixes - -- add cached shortcuts to the imports ([#162](https://github.com/nitrojs/nitropack/issues/162)) ([bf6d208](https://github.com/nitrojs/nitropack/commit/bf6d208866946b4251f7b5922128c03e6117bacd)) -- **cloudflare:** normalize incoming & outgoing headers ([#171](https://github.com/nitrojs/nitropack/issues/171)) ([abda66b](https://github.com/nitrojs/nitropack/commit/abda66b65bca708aee731cc4b9f1ba493fc356f2)) - -### [0.3.8](https://github.com/nitrojs/nitropack/compare/v0.3.7...v0.3.8) (2022-04-27) - -### Features - -- improve raw asset handling ([#158](https://github.com/nitrojs/nitropack/issues/158)) ([a68d3d2](https://github.com/nitrojs/nitropack/commit/a68d3d25da90c1a131ff4de85b9d3160067baa90)) - -### Bug Fixes - -- **cache:** replace magage typo by maxage ([#150](https://github.com/nitrojs/nitropack/issues/150)) ([07d8ced](https://github.com/nitrojs/nitropack/commit/07d8cedbf9d9d2105929f753d12e76254b31b204)) -- replace `global.` in fewer instances ([#155](https://github.com/nitrojs/nitropack/issues/155)) ([73db5c9](https://github.com/nitrojs/nitropack/commit/73db5c9e0de1baffec93a47bee85c88a33c8d609)) -- support patch method auto-scanning ([#153](https://github.com/nitrojs/nitropack/issues/153)) ([01801c2](https://github.com/nitrojs/nitropack/commit/01801c2e7a17effce8ff84d2cc6c5a488cce61a6)) - -### [0.3.7](https://github.com/nitrojs/nitropack/compare/v0.3.6...v0.3.7) (2022-04-25) - -### Bug Fixes - -- **rollup:** prepend `node_modules` to `moduleDirectories` ([458ff57](https://github.com/nitrojs/nitropack/commit/458ff5793a6d088c5813a05173a35675f453267d)), closes [#136](https://github.com/nitrojs/nitropack/issues/136) - -### [0.3.6](https://github.com/nitrojs/nitropack/compare/v0.3.5...v0.3.6) (2022-04-22) - -### Bug Fixes - -- manually merge runtime config with env ([#143](https://github.com/nitrojs/nitropack/issues/143)) ([1be5ac2](https://github.com/nitrojs/nitropack/commit/1be5ac2e89035ce98f50edaa8e7c79ba4e974adf)) -- respect `sourceMap` option ([#141](https://github.com/nitrojs/nitropack/issues/141)) ([e5ab741](https://github.com/nitrojs/nitropack/commit/e5ab741a1b96f91b62da4341ab3ceffd304e0f90)) -- wrap dynamic import in prerender to fix windows build failure ([#134](https://github.com/nitrojs/nitropack/issues/134)) ([2be8aaf](https://github.com/nitrojs/nitropack/commit/2be8aafd04c180de861010b263d551cdb049e7b6)) - -### [0.3.5](https://github.com/nitrojs/nitropack/compare/v0.3.4...v0.3.5) (2022-04-20) - -### Bug Fixes - -- **node-server:** default production host to `0.0.0.0` ([b7c7193](https://github.com/nitrojs/nitropack/commit/b7c719349a0ee399a525937abb5905e50b0351f2)) - -### [0.3.4](https://github.com/nitrojs/nitropack/compare/v0.3.3...v0.3.4) (2022-04-19) - -### Bug Fixes - -- **prerender:** disallow routes longer than 250 chars ([c736de0](https://github.com/nitrojs/nitropack/commit/c736de038f186589237b413eb6ed9bd4e163189c)) -- **prerender:** only use pathnames ([7cc02c9](https://github.com/nitrojs/nitropack/commit/7cc02c972c928537c2a19e75cfc53f7ea2e33ac6)) - -### [0.3.3](https://github.com/nitrojs/nitropack/compare/v0.3.2...v0.3.3) (2022-04-19) - -### Bug Fixes - -- provide compatibility `#nitro` as a virtual module ([6a798c6](https://github.com/nitrojs/nitropack/commit/6a798c6a1ac77c5c53f33838047f3ab5c7560787)) - -### [0.3.2](https://github.com/nitrojs/nitropack/compare/v0.3.1...v0.3.2) (2022-04-19) - -### Features - -- provide `#imports` alias and `#nitro` for backward compatibility ([ef2f216](https://github.com/nitrojs/nitropack/commit/ef2f216e48c54404c335c7995efcec85f7759c66)) - -### [0.3.1](https://github.com/nitrojs/nitropack/compare/v0.3.0...v0.3.1) (2022-04-19) - -### Bug Fixes - -- **node-server:** fix typo in import ([b5bd30b](https://github.com/nitrojs/nitropack/commit/b5bd30b4c0484f862dc9f78403248c686a6fb445)) -- **prerenderer:** switch back to simple queue ([b7a65eb](https://github.com/nitrojs/nitropack/commit/b7a65eb0765e5b5a5e0644f61cf654f46565b410)) - -## [0.3.0](https://github.com/nitrojs/nitropack/compare/v0.2.11...v0.3.0) (2022-04-19) - -### ⚠ BREAKING CHANGES - -- rename `#nitro` to `#internal/nitro` -- remove `nitro:` prefix from hook names - -### Features - -- add layer0 preset ([b748da3](https://github.com/nitrojs/nitropack/commit/b748da36a1deb4b4550c865d64a1f97a4fb50211)) -- **cache:** add `staleMaxAge` option for caching header ([#116](https://github.com/nitrojs/nitropack/issues/116)) ([8ff6836](https://github.com/nitrojs/nitropack/commit/8ff6836805842a7649d12f4a450d142cf329fa08)) -- netlify edge function preset ([feebf8f](https://github.com/nitrojs/nitropack/commit/feebf8f6fda08873452c826e89327db380a495c7)) -- stormkit preset ([#103](https://github.com/nitrojs/nitropack/issues/103)) ([7316385](https://github.com/nitrojs/nitropack/commit/7316385ea921fd33f89e4743cf3058898537f454)) - -### Bug Fixes - -- default fetch baseURL to runtime nitro base ([#122](https://github.com/nitrojs/nitropack/issues/122)) ([00a15c1](https://github.com/nitrojs/nitropack/commit/00a15c159b2f3601d7fc3c53cc7ee423f910cf8c)) -- **externals:** normalize output paths to flat structure ([a7f451f](https://github.com/nitrojs/nitropack/commit/a7f451fddf6bf7031b24eed14e707430271deda9)), closes [#106](https://github.com/nitrojs/nitropack/issues/106) -- force preset to `nitro-dev` when `dev` flag used ([94fc531](https://github.com/nitrojs/nitropack/commit/94fc53118e411bc538d61dacac70d1d1183b5004)), closes [#121](https://github.com/nitrojs/nitropack/issues/121) - -- remove `nitro:` prefix from hook names ([ac2f0aa](https://github.com/nitrojs/nitropack/commit/ac2f0aa30ff1a584a2144f879d0d8caacece0add)) -- rename `#nitro` to `#internal/nitro` ([944a348](https://github.com/nitrojs/nitropack/commit/944a34822c8eb4a4f6e31f285f8a64694372d657)) - -### [0.2.11](https://github.com/nitrojs/nitropack/compare/v0.2.10...v0.2.11) (2022-04-15) - -### Bug Fixes - -- **prerender:** add `.html` for implicit html routes ([1b7bc8c](https://github.com/nitrojs/nitropack/commit/1b7bc8c999004b64d2c063c8944928d9c6337e07)) - -### [0.2.10](https://github.com/nitrojs/nitropack/compare/v0.2.9...v0.2.10) (2022-04-14) - -### Features - -- **cache:** rewrite `defineCachedEventHandler` ([d7512be](https://github.com/nitrojs/nitropack/commit/d7512befd26880232c767d5fc135b4db86091853)) -- improve prerenderer ([5457a01](https://github.com/nitrojs/nitropack/commit/5457a010c188f412bed0914c44db27cbe02a664b)) - -### [0.2.9](https://github.com/nitrojs/nitropack/compare/v0.2.8...v0.2.9) (2022-04-14) - -### Bug Fixes - -- **prerender:** only extract relative links ([#112](https://github.com/nitrojs/nitropack/issues/112)) ([b61caf7](https://github.com/nitrojs/nitropack/commit/b61caf78f14e772edd229d8bbf49d695bf4d8f88)) - -### [0.2.8](https://github.com/nitrojs/nitropack/compare/v0.2.7...v0.2.8) (2022-04-13) - -### Features - -- add render, digital-ocean and heroku presets ([#55](https://github.com/nitrojs/nitropack/issues/55)) ([b77ef27](https://github.com/nitrojs/nitropack/commit/b77ef277679e50565c1f9c47d0fd849cf0e1940c)) - -### Bug Fixes - -- **dev:** remove global serve-placeholder ([7b4f340](https://github.com/nitrojs/nitropack/commit/7b4f340492ba452c9c2f9261e86925acf00dbd21)), closes [#94](https://github.com/nitrojs/nitropack/issues/94) -- **dev:** watch routes changes to full reload ([9d1ff93](https://github.com/nitrojs/nitropack/commit/9d1ff9307b32062fff786a80d0e6545f890cdc8e)) -- escape regex for wild-card route matcher ([41e27b4](https://github.com/nitrojs/nitropack/commit/41e27b466ec29bdba0ecda4961be146c4a630333)), closes [nuxt/framework#4313](https://github.com/nuxt/framework/issues/4313) -- remove `/index` from generated routes at last ([09cad09](https://github.com/nitrojs/nitropack/commit/09cad098cbed3591f3cede0ac65b38a5397ff9c4)), closes [nuxt/framework#4314](https://github.com/nuxt/framework/issues/4314) -- **server-assets:** assets behavior ([#105](https://github.com/nitrojs/nitropack/issues/105)) ([e21134c](https://github.com/nitrojs/nitropack/commit/e21134c172961026e62b4840fd9005bbe03c5077)) - -### [0.2.7](https://github.com/nitrojs/nitropack/compare/v0.2.6...v0.2.7) (2022-04-12) - -### Bug Fixes - -- **rollup:** also match moduleSideEffects with full path ([ce2e898](https://github.com/nitrojs/nitropack/commit/ce2e898beaaa32776d1dabe1d96a3debea2bbabf)) - -### [0.2.6](https://github.com/nitrojs/nitropack/compare/v0.2.5...v0.2.6) (2022-04-12) - -### Bug Fixes - -- resolve to tested version of `defu` and `h3` ([ba2e237](https://github.com/nitrojs/nitropack/commit/ba2e237b5dc95ba9681dc33afd2e1898638e16f8)) - -### [0.2.5](https://github.com/nitrojs/nitropack/compare/v0.2.4...v0.2.5) (2022-04-12) - -### Features - -- allow overriding nested runtime config ([#65](https://github.com/nitrojs/nitropack/issues/65)) ([27fb68b](https://github.com/nitrojs/nitropack/commit/27fb68b0411b967069e3eb60a762b12a7b979ea2)) -- support custom error and dev error handler ([#76](https://github.com/nitrojs/nitropack/issues/76)) ([cb6a84c](https://github.com/nitrojs/nitropack/commit/cb6a84c37fc1e4686b1e98a7320e44b1d7ed90d9)) - -### Bug Fixes - -- allow overriding nested variables ([#75](https://github.com/nitrojs/nitropack/issues/75)) ([d7bfc96](https://github.com/nitrojs/nitropack/commit/d7bfc9660c8a9662b13cfb24342d3ccc9289d46a)) -- allow users to override nitro error ([#58](https://github.com/nitrojs/nitropack/issues/58)) ([aa660c7](https://github.com/nitrojs/nitropack/commit/aa660c7faf92ddceee7b003c89adf1df7068bf93)) - -### [0.2.4](https://github.com/nitrojs/nitropack/compare/v0.2.3...v0.2.4) (2022-04-11) - -### Bug Fixes - -- **prerender:** use pathname from extracted links only ([#74](https://github.com/nitrojs/nitropack/issues/74)) ([b9271d7](https://github.com/nitrojs/nitropack/commit/b9271d72a182839eadc49e0c32d2beb64f1da37b)) - -### [0.2.3](https://github.com/nitrojs/nitropack/compare/v0.2.2...v0.2.3) (2022-04-11) - -### Features - -- use `std-env` to detect provider ([#72](https://github.com/nitrojs/nitropack/issues/72)) ([e78f598](https://github.com/nitrojs/nitropack/commit/e78f5984dd9b308d86adba8410b6b30336d07945)) - -### Bug Fixes - -- always apply `#build` windows fix when `externals.trace` is disabled ([1ec2ee4](https://github.com/nitrojs/nitropack/commit/1ec2ee4cf3dfd355a2b7d8d6d7aa5de6dcb51b7c)) - -### [0.2.2](https://github.com/nitrojs/nitropack/compare/v0.2.1...v0.2.2) (2022-04-11) - -### Bug Fixes - -- disable externals with explicit flag ([2e5de6c](https://github.com/nitrojs/nitropack/commit/2e5de6cf37f4954cbd1492212f4537c44ab681e4)), closes [nuxt/framework#226](https://github.com/nuxt/framework/issues/226) -- normalize `#build` windows path for dev and prerender presets ([#70](https://github.com/nitrojs/nitropack/issues/70)) ([ec5db11](https://github.com/nitrojs/nitropack/commit/ec5db11f7eef215d0337401b91c71e1946a30664)) - -### [0.2.1](https://github.com/nitrojs/nitropack/compare/v0.2.0...v0.2.1) (2022-04-07) - -### Bug Fixes - -- use file:// for windows #build alias on dev ([077b511](https://github.com/nitrojs/nitropack/commit/077b5118742c822223fa110e0fd19f36b8616b02)) - -## [0.2.0](https://github.com/nitrojs/nitropack/compare/v0.1.4...v0.2.0) (2022-04-07) - -### ⚠ BREAKING CHANGES - -- remove `nitro:document` hook -- remove `views/app.template.html` from `build` logic - -- remove `nitro:document` hook ([1feb644](https://github.com/nitrojs/nitropack/commit/1feb6444ccc9e90668a1adc13a48198891f98f2a)) -- remove `views/app.template.html` from `build` logic ([0939233](https://github.com/nitrojs/nitropack/commit/09392330a8f13a51e245c0346e7a4aa66dae1b85)) - -### [0.1.4](https://github.com/nitrojs/nitropack/compare/v0.1.3...v0.1.4) (2022-04-07) - -### Bug Fixes - -- issues with firebase dependencies ([#48](https://github.com/nitrojs/nitropack/issues/48)) ([3498d7d](https://github.com/nitrojs/nitropack/commit/3498d7d369df206f04e946335e4798ad60bcf2e6)) - -### [0.1.3](https://github.com/nitrojs/nitropack/compare/v0.1.2...v0.1.3) (2022-04-07) - -### Features - -- allow user configured dynamic virtual imports ([046d090](https://github.com/nitrojs/nitropack/commit/046d0901903bb09e2e1e3812eb433e7cfa9c6141)) -- improve error pages ([209688f](https://github.com/nitrojs/nitropack/commit/209688f90c72948073fe5165f03b2ef81acf865e)) - -### Bug Fixes - -- avoid replaceAll for node 14 compatibility ([#42](https://github.com/nitrojs/nitropack/issues/42)) ([e229115](https://github.com/nitrojs/nitropack/commit/e229115454ad29826f4e27f85edbc62d22574309)) -- **externals:** check for explicit externals ([b4ced48](https://github.com/nitrojs/nitropack/commit/b4ced481f3579141106f90c1f6c03bcad9a6f117)) -- **externals:** improve fallback error handling ([6b355ca](https://github.com/nitrojs/nitropack/commit/6b355ca6f767e9bce95ea018a84959cb2760db63)) -- update azure SWA preset and update node versions detection ([#43](https://github.com/nitrojs/nitropack/issues/43)) ([19c784b](https://github.com/nitrojs/nitropack/commit/19c784b297ef7b1a618ca2bac1656462802df144)) -- update firebase output for package.json ([#45](https://github.com/nitrojs/nitropack/issues/45)) ([7700500](https://github.com/nitrojs/nitropack/commit/7700500d04c333858b94be796b6385e08a4dce70)) - -### [0.1.2](https://github.com/nitrojs/nitropack/compare/v0.1.1...v0.1.2) (2022-04-07) - -### Bug Fixes - -- update azure functions preset ([#41](https://github.com/nitrojs/nitropack/issues/41)) ([c552906](https://github.com/nitrojs/nitropack/commit/c552906b847bf1698ee6b9cb9d424aef7fc33832)) - -### [0.1.1](https://github.com/nitrojs/nitropack/compare/v0.1.0...v0.1.1) (2022-04-07) - -### Features - -- `routes/` directory ([2f96340](https://github.com/nitrojs/nitropack/commit/2f963403b2bd39493c1dc918ec1ef0a534185c06)) -- method support for rotue handlers ([da35ab1](https://github.com/nitrojs/nitropack/commit/da35ab19aeaa33ea7f4ef52f9ee08bdec931fba5)) -- register `[...].ext` as catch-all ([2e2e283](https://github.com/nitrojs/nitropack/commit/2e2e28342375dd03c84020085b488af67406553d)) - -### Bug Fixes - -- also check for assets paths for `isPublicAssetURL` ([4170f65](https://github.com/nitrojs/nitropack/commit/4170f65056590075424f4d5cd5e14f9d1ad3ceed)) -- always enable publicAssets plugin ([a78e1be](https://github.com/nitrojs/nitropack/commit/a78e1beb07009b59df437b80e9883db04d9d24f4)) -- **cli:** prerender before main build ([9388b7d](https://github.com/nitrojs/nitropack/commit/9388b7dea3af8c0ac34e1ed5315d63f7e191a4ba)) -- mock readAsset when serveStatic is disabled ([e95b9d9](https://github.com/nitrojs/nitropack/commit/e95b9d9e84b6e589a2db4a91b523eaad60654994)) -- **service-worker:** remove `_server` prefix ([60ae8ba](https://github.com/nitrojs/nitropack/commit/60ae8ba5383dcceae52bf4094e4a3cc6a541d634)) -- update unenv to fix proxy mock issues ([fefd2e9](https://github.com/nitrojs/nitropack/commit/fefd2e9216da0b0287ed082578c34045bb62c309)) - -## 0.1.0 (2022-04-07) - -### ⚠ BREAKING CHANGES - -- use `app.baseURL` runtime config for framework agnostic usage -- expose `nitroApp` to entries -- simplify storage options -- drop paths and support top level `baseURL` option -- migrate to h3 0.5x with events API (#23) -- add `engines.node` field and node.js version check (#1197) - -### Features - -- `@nuxt/meta` module for head rendering ([#179](https://github.com/nitrojs/nitropack/issues/179)) ([1a76f60](https://github.com/nitrojs/nitropack/commit/1a76f6057d893d26e41960c0b12d9cf1e9496764)) -- `h3` auto imports preset ([0661fa9](https://github.com/nitrojs/nitropack/commit/0661fa988e0dafff8a700ee0c1cb10137914ccb5)) -- `nitro.close()` ([c1560d0](https://github.com/nitrojs/nitropack/commit/c1560d0a7bc063a487e924e340d50202ef9c6fa0)) -- add `engines.node` field and node.js version check ([#1197](https://github.com/nitrojs/nitropack/issues/1197)) ([a0ff933](https://github.com/nitrojs/nitropack/commit/a0ff933f75e4c07ac62bf1962ab3a1520fe2f094)) -- add `process.dev` ([#16](https://github.com/nitrojs/nitropack/issues/16)) ([68fc5b3](https://github.com/nitrojs/nitropack/commit/68fc5b32524964a5d899e39d3a5a090eb0d1e465)) -- add `runtime/client` for $fetch polyfill ([#11](https://github.com/nitrojs/nitropack/issues/11)) ([e241e3d](https://github.com/nitrojs/nitropack/commit/e241e3d770127d325ba6bfbeb74bb1adb0552e1a)) -- add $fetch to client ([48cf97c](https://github.com/nitrojs/nitropack/commit/48cf97c4244680c60af99ffee7e834e5cf604070)) -- add azure functions preset ([#45](https://github.com/nitrojs/nitropack/issues/45)) ([15b20a5](https://github.com/nitrojs/nitropack/commit/15b20a5c22684f49bf18931427a0ab45d4744ab3)) -- add basic html error ([d090aac](https://github.com/nitrojs/nitropack/commit/d090aac99d741bbf5b965988084111aedc594d2f)) -- add firebase preset ([#100](https://github.com/nitrojs/nitropack/issues/100)) ([750fa76](https://github.com/nitrojs/nitropack/commit/750fa76a33a5a2bc344bb1d0a01441f83da80f25)) -- add hint to dynamic require for netlify ([5fade11](https://github.com/nitrojs/nitropack/commit/5fade11011fe4878f61f7d4ac986926540fc19fb)) -- add serve-placeholder ([689aad0](https://github.com/nitrojs/nitropack/commit/689aad00155e5c153e5ee015493c81f3fb039b83)) -- add support for Azure static web apps ([#92](https://github.com/nitrojs/nitropack/issues/92)) ([9a5ae67](https://github.com/nitrojs/nitropack/commit/9a5ae67e9b07ec3948703286eb207e80197a93a5)) -- add support for vite build (with vite-format manifest) ([#450](https://github.com/nitrojs/nitropack/issues/450)) ([002469a](https://github.com/nitrojs/nitropack/commit/002469aae22aa965955bf9424597c4aca09b2352)) -- allow custom error handling ([#30](https://github.com/nitrojs/nitropack/issues/30)) ([ac1b093](https://github.com/nitrojs/nitropack/commit/ac1b0936f712d6138f4add5e2dcbca63d3ad68e2)) -- allow disabling tsconfig generation ([f30a026](https://github.com/nitrojs/nitropack/commit/f30a02667ca94415045a7071ed44c5f2196809b4)) -- allow overriding runtime config with `NITRO_` or an alternative specified with `NITRO_ENV_PREFIX_ALT` ([a27d529](https://github.com/nitrojs/nitropack/commit/a27d52908848edb80f003c448daf366c98ceffd1)) -- auto imports for `useConfig` and `useStorage` ([5b2c950](https://github.com/nitrojs/nitropack/commit/5b2c950209821c4d74bb68be6892ca4ec9ff3d40)) -- automatically mock unresolved externals ([dac74e1](https://github.com/nitrojs/nitropack/commit/dac74e1b5c848bb13fcdf37c15c6e3f4b6c7fa00)) -- aws APIGatewayProxyEventV2 support ([d135f01](https://github.com/nitrojs/nitropack/commit/d135f01be8303089a0f010d69e57cc44ad08b792)) -- basic multi dir support ([376d349](https://github.com/nitrojs/nitropack/commit/376d3496ec08633aed7ad8fb8488cd3551168b4d)) -- basic support for netlify_builder target ([#18](https://github.com/nitrojs/nitropack/issues/18)) ([4f90f95](https://github.com/nitrojs/nitropack/commit/4f90f959386e5a659401650be7a0f61934333afb)) -- better error handler ([d8cf235](https://github.com/nitrojs/nitropack/commit/d8cf2355b0e13c121df4084fbd5d2be7c9d7ad2a)) -- better process polyfill ([f06a437](https://github.com/nitrojs/nitropack/commit/f06a4376c35e1afec372fd6bd4ad9c79be76e732)) -- **browser:** inject script to js template ([51712ad](https://github.com/nitrojs/nitropack/commit/51712ad0d2e18294a03a941c67611a2df1c3f06b)) -- cache api ([e9a44f5](https://github.com/nitrojs/nitropack/commit/e9a44f57f6c7cbacad35e7be25f278a5fbb2c67e)) -- create `nitro.logger` to control verbosity ([a91fd52](https://github.com/nitrojs/nitropack/commit/a91fd5218253c8a9e3a2c62d9810462b1428f171)) -- define nitro `#storage` and `#assets` types ([#1377](https://github.com/nitrojs/nitropack/issues/1377)) ([cf78609](https://github.com/nitrojs/nitropack/commit/cf78609d4c56ea996cb002f144f391c6ee93f829)) -- **deps:** update all non-major dependencies ([#2252](https://github.com/nitrojs/nitropack/issues/2252)) ([1b2e92e](https://github.com/nitrojs/nitropack/commit/1b2e92e671adb5fc84fd673bdfa15b4f08a563d3)) -- detect target ([ea250b3](https://github.com/nitrojs/nitropack/commit/ea250b36a4d86914bef58c88d47c2fce1b424b3d)) -- dev server watch ([3eb6c20](https://github.com/nitrojs/nitropack/commit/3eb6c20a1a1d3eb23ae0d1a775829363da0d4b8b)) -- drop paths and support top level `baseURL` option ([913f3d8](https://github.com/nitrojs/nitropack/commit/913f3d8904f26d68ce7786a0f728371777faca76)) -- dynamic chunk importer ([0f179ab](https://github.com/nitrojs/nitropack/commit/0f179ab120d4d4a99b755dc5eebc84d49eac30e7)) -- dynamic-require rollup plugin ([b00cfb9](https://github.com/nitrojs/nitropack/commit/b00cfb93a5170af04676de5257ee62b312c423f1)) -- enable externals.trace by default ([303debd](https://github.com/nitrojs/nitropack/commit/303debdf24f5666882cb7f4481840476c0c91950)) -- export `defineNuxtConfig` from `nuxt3` and `@nuxt/bridge` ([#669](https://github.com/nitrojs/nitropack/issues/669)) ([8a02ab8](https://github.com/nitrojs/nitropack/commit/8a02ab812b043aa15da20d80be44572714cb083e)) -- expose `useNitroApp` to access nitroApp ([3d82df1](https://github.com/nitrojs/nitropack/commit/3d82df1a654b5099102ec2dc9e9bedd50a90800c)) -- expose process.env.SIGMA_PRESET ([8bdcc43](https://github.com/nitrojs/nitropack/commit/8bdcc4356714b0908b603e59aad0615f0cb2058b)) -- **external:** improved subpath detection for externals ([d13b842](https://github.com/nitrojs/nitropack/commit/d13b842e42b9c3304e333957d4bc4f7317f95205)) -- **externals:** smartly pick latest version and warn only on two different major ([cb03c96](https://github.com/nitrojs/nitropack/commit/cb03c96ce6abbd76714e381c9252e667d7486e9f)) -- **externals:** write bundledDependencies and detect duplicate versions ([a898c8d](https://github.com/nitrojs/nitropack/commit/a898c8dc20d6748de83b2edec87ec88f868ff3f3)) -- generate `.nitro/types/tsconfig.json` ([9494520](https://github.com/nitrojs/nitropack/commit/9494520769f52a8c3fc652a42ad08236a0018d29)) -- generate meaningful chunkNames ([9e22f68](https://github.com/nitrojs/nitropack/commit/9e22f68aa1c5ec621339d4f9544d259983a11698)) -- generate public (dist/) ([5f92307](https://github.com/nitrojs/nitropack/commit/5f92307ab8206d079d185618e258d012dca8ffa9)) -- generic devHandler support ([9175a34](https://github.com/nitrojs/nitropack/commit/9175a34df6d02ecbcb1c7e5079025a1050e97cc4)) -- handle api routes with router ([38b6631](https://github.com/nitrojs/nitropack/commit/38b66317dddb1ecb9d2a815268c29fa7f3a78ffb)) -- handle caching headers for cachfied handlers ([ace355b](https://github.com/nitrojs/nitropack/commit/ace355b9e25235e24c21557e1a44e38a80d2a769)) -- improve base url options ([#2655](https://github.com/nitrojs/nitropack/issues/2655)) ([9d8cf91](https://github.com/nitrojs/nitropack/commit/9d8cf9199e478b4eb99bc1dda3aea32bc6753e8f)) -- improve cache support for event handlers ([9b4b01a](https://github.com/nitrojs/nitropack/commit/9b4b01af91aa99028140d19e6889a8570e83d835)) -- improve dev error handling ([298a36b](https://github.com/nitrojs/nitropack/commit/298a36b99bc6d3104d1022e5ce443a32aadc6470)) -- improve mocking ([e76cb19](https://github.com/nitrojs/nitropack/commit/e76cb19dc21462a375857676009b5fad174a629c)) -- improve mocks ([6f411b2](https://github.com/nitrojs/nitropack/commit/6f411b2aa46d9de7605c8fea1938b57c44e957ac)) -- improve types ([#6](https://github.com/nitrojs/nitropack/issues/6)) ([b982ae2](https://github.com/nitrojs/nitropack/commit/b982ae22bb6419df1f01260f250fcd052876858d)) -- improved env support ([0c22cbe](https://github.com/nitrojs/nitropack/commit/0c22cbed3ce1a20e6b4533c72cd46b4c1b0275b0)) -- improved externals and experimental trace with vercel/nft ([bc649ba](https://github.com/nitrojs/nitropack/commit/bc649ba948d9a1cccf23edd1a5169efdfb67e178)) -- improved sever timing ([95e4538](https://github.com/nitrojs/nitropack/commit/95e45389cba4ee1ac63b36deb55ccb43df59d6fb)) -- initial version of nu cli ([#54](https://github.com/nitrojs/nitropack/issues/54)) ([47f4198](https://github.com/nitrojs/nitropack/commit/47f4198206eb90f0dab3797e773fbfff98963285)) -- inject sw script to pages ([b215c38](https://github.com/nitrojs/nitropack/commit/b215c38dddd4f319ffb3936df96dae7ecbf3df75)) -- integrate $fetch with ohmyfetch ([c0fc176](https://github.com/nitrojs/nitropack/commit/c0fc17635f68b0473b00879eda3211b8802789cb)) -- link crawling support ([462398f](https://github.com/nitrojs/nitropack/commit/462398f57c9bcd4886d614e060085a7264b1e525)) -- load and extend config/preset with c12 ([e18211a](https://github.com/nitrojs/nitropack/commit/e18211a7cac4895af148bfd70e0856ca80bdb6ca)) -- make browser target working again ([7c35713](https://github.com/nitrojs/nitropack/commit/7c357136e2591361e0706f6d7cd9efdc03daf808)) -- make cloudflare working ([2ed7b35](https://github.com/nitrojs/nitropack/commit/2ed7b35fd813e7c7cb602581337eac4b74a5e62d)) -- migrate to h3 0.5x with events API ([#23](https://github.com/nitrojs/nitropack/issues/23)) ([c705dd4](https://github.com/nitrojs/nitropack/commit/c705dd4893b9a127eb6c46797fb8039c1037f2cf)) -- mock debug ([#118](https://github.com/nitrojs/nitropack/issues/118)) ([54bb024](https://github.com/nitrojs/nitropack/commit/54bb024b57a24382bd9863ef177e649250f857d4)), closes [#97](https://github.com/nitrojs/nitropack/issues/97) -- mock mime packages and fix v1 compat ([c960a22](https://github.com/nitrojs/nitropack/commit/c960a22d64069cfb2394f46856b9b273f239c012)) -- mock stream ([435ce77](https://github.com/nitrojs/nitropack/commit/435ce7776683ba4d97a2362fe8dde949ddf0f01e)) -- module utils and improvements ([#38](https://github.com/nitrojs/nitropack/issues/38)) ([58605e2](https://github.com/nitrojs/nitropack/commit/58605e2faddb6447e3b1f7f67bd5f383c4c40d38)) -- natively parse and import async webpack chunks ([14b9db4](https://github.com/nitrojs/nitropack/commit/14b9db424f53e657e3d36b208e5e6fc11076f5c9)) -- new public asset handling ([305c498](https://github.com/nitrojs/nitropack/commit/305c49853d514ceb00342107a7affdbd9500f5f2)) -- nitro app plugins ([613a559](https://github.com/nitrojs/nitropack/commit/613a559cfd7f8ab445b947f4e18b517b4d86cda9)) -- nitro endpoint for viewing `_vfs` ([#362](https://github.com/nitrojs/nitropack/issues/362)) ([edd67c5](https://github.com/nitrojs/nitropack/commit/edd67c5dbbda2c07019148ff7d16f351def93438)) -- **nitro, vite:** use native module ([#252](https://github.com/nitrojs/nitropack/issues/252)) ([ad7044a](https://github.com/nitrojs/nitropack/commit/ad7044a2c50b7606ed00004e10e2b42d29d836dd)) -- **nitro:** #config ([d169f11](https://github.com/nitrojs/nitropack/commit/d169f116200a188d0eff3e1c7170b0cab6910421)) -- **nitro:** allow extending nitro context ([4a3a253](https://github.com/nitrojs/nitropack/commit/4a3a2539bdbee9162ab28e8440b30b45a7ff965a)) -- **nitro:** assets driver ([#511](https://github.com/nitrojs/nitropack/issues/511)) ([9a8d992](https://github.com/nitrojs/nitropack/commit/9a8d992dbb710f3103d5a5ce83f52c2272e1fd8e)) -- **nitro:** automatically type middleware/api routes ([#708](https://github.com/nitrojs/nitropack/issues/708)) ([3163fa2](https://github.com/nitrojs/nitropack/commit/3163fa217ed16e672c12d4dde3304a683fddb7cb)) -- **nitro:** handle request body in workers ([#537](https://github.com/nitrojs/nitropack/issues/537)) ([c3249cb](https://github.com/nitrojs/nitropack/commit/c3249cb6e2f7c870e4a0e78f48401c60e08a798c)) -- **nitro:** improve dev worker stability ([#1303](https://github.com/nitrojs/nitropack/issues/1303)) ([f71714d](https://github.com/nitrojs/nitropack/commit/f71714d3dde83a496de404d83c651c5774ae25bb)) -- **nitro:** raw loader ([#75](https://github.com/nitrojs/nitropack/issues/75)) ([5acb394](https://github.com/nitrojs/nitropack/commit/5acb394a75cbc28f2fe3c094af4452f22c493190)) -- **nitro:** server assets ([#83](https://github.com/nitrojs/nitropack/issues/83)) ([f71574c](https://github.com/nitrojs/nitropack/commit/f71574cd46829836d59e334fea1cf1fe529e003c)) -- **nitro:** specify packages to copy to `.output/server/node_modules` ([#2382](https://github.com/nitrojs/nitropack/issues/2382)) ([acb0033](https://github.com/nitrojs/nitropack/commit/acb00338c3798128c4d6ca533d2903fde914dbeb)) -- **nitro:** ssl nitro support in production ([#2742](https://github.com/nitrojs/nitropack/issues/2742)) ([9c48d73](https://github.com/nitrojs/nitropack/commit/9c48d73e59c9e68d0f471b2902847938a3d1d954)) -- **nitro:** storage support ([#76](https://github.com/nitrojs/nitropack/issues/76)) ([958563c](https://github.com/nitrojs/nitropack/commit/958563c0e9da1b86419776686471fd1a51759078)) -- **nitro:** support adding `node_modules` as middleware ([#2826](https://github.com/nitrojs/nitropack/issues/2826)) ([75d2674](https://github.com/nitrojs/nitropack/commit/75d2674ca1f24e7fc5c5e94b4ba0969d4bf65e16)) -- **nitro:** support esbuild options config ([#550](https://github.com/nitrojs/nitropack/issues/550)) ([bff7db3](https://github.com/nitrojs/nitropack/commit/bff7db3a61a52c009c037006a42537e20a5b5db2)) -- **nitro:** support importing/inlining wasm binaries ([#693](https://github.com/nitrojs/nitropack/issues/693)) ([a0ddbd2](https://github.com/nitrojs/nitropack/commit/a0ddbd2e16b0a0028541e74c4e727190352b16be)) -- **nitro:** support netlify zero-config deployments ([#175](https://github.com/nitrojs/nitropack/issues/175)) ([ced37c2](https://github.com/nitrojs/nitropack/commit/ced37c20839dab4df9c7b0ae9358a34fc90dd593)) -- **nitro:** update dependencies for node-fetch 3.x support ([#1373](https://github.com/nitrojs/nitropack/issues/1373)) ([9d12b7e](https://github.com/nitrojs/nitropack/commit/9d12b7e7ddf28d5f6322b7ae5047117d10d411c0)) -- **nuxi:** add `nuxi preview` command for local testing ([#2162](https://github.com/nitrojs/nitropack/issues/2162)) ([b60a23a](https://github.com/nitrojs/nitropack/commit/b60a23ae61f3050ad3b467dc09bd5b189458ca9b)) -- **nuxi:** bundle analyzer ([#701](https://github.com/nitrojs/nitropack/issues/701)) ([5364d04](https://github.com/nitrojs/nitropack/commit/5364d0444ccc5353c8152623b6590d6bbc8efb1e)) -- nuxt bridge ([#459](https://github.com/nitrojs/nitropack/issues/459)) ([3de9574](https://github.com/nitrojs/nitropack/commit/3de9574cf827c11d3a4d3e6805b3eba388d76cf8)) -- **nuxt3, bridge:** useRuntimeConfig ([#625](https://github.com/nitrojs/nitropack/issues/625)) ([832a9a4](https://github.com/nitrojs/nitropack/commit/832a9a44a246f5f9e50f57270561ae5d53fbcd1f)) -- **nuxt3:** `useFetch` ([#721](https://github.com/nitrojs/nitropack/issues/721)) ([9b76832](https://github.com/nitrojs/nitropack/commit/9b768326aae4eaa7fb329f13071a110c50720d1e)) -- optional pages and refactor nuxt3 ([#142](https://github.com/nitrojs/nitropack/issues/142)) ([39a0c4a](https://github.com/nitrojs/nitropack/commit/39a0c4a48617350bc03290b3b5dcd86afcae1338)) -- prerender support ([24fb151](https://github.com/nitrojs/nitropack/commit/24fb1516bd14c19cb4e17e60de55f48dcd633efc)) -- reexport common utils from `#nitro` index ([3dc2ee6](https://github.com/nitrojs/nitropack/commit/3dc2ee6d92bec9f4ece00f457887303053379298)) -- resolve aliases with reference to themselves ([#26](https://github.com/nitrojs/nitropack/issues/26)) ([adb6c5d](https://github.com/nitrojs/nitropack/commit/adb6c5d1c7820feef63ed0851d7850f04d98ebb1)) -- resolve externals with full path ([1c9b627](https://github.com/nitrojs/nitropack/commit/1c9b627f450eba8015f61e6224020e18a168812d)) -- rewrite as nuxt module ([6881079](https://github.com/nitrojs/nitropack/commit/68810798975e49c041352741c08bdde09f9be6aa)) -- **rollup:** allow custom replace entries ([18ee71b](https://github.com/nitrojs/nitropack/commit/18ee71b982d9ac8c15bdc2c374b860268fd2893c)) -- serve-placeholder ([7a59183](https://github.com/nitrojs/nitropack/commit/7a591834193b85ef96d5dfa3a4bf3d8259883247)) -- serveStatic ([#47](https://github.com/nitrojs/nitropack/issues/47)) ([af42712](https://github.com/nitrojs/nitropack/commit/af427122cd0733f5a2c115bdaef3557bb2478cd2)) -- show fs tree for output ([a230bc7](https://github.com/nitrojs/nitropack/commit/a230bc7bbd25b7335b7104e70461e9bf61db95ae)) -- sigma.client ([1656155](https://github.com/nitrojs/nitropack/commit/16561554610d56ad2a2fa25e3e9d6bb407a9b527)) -- sourcemap support ([e47b266](https://github.com/nitrojs/nitropack/commit/e47b266c69c576b54795108e986faece6ed3e8b6)) -- ssr with service worker ([971315c](https://github.com/nitrojs/nitropack/commit/971315c797c9c210b3966e3539da3d3c77415049)) -- support `NITRO_APP_BASE_URL` for build-time ([42ff5a3](https://github.com/nitrojs/nitropack/commit/42ff5a383a6d27eb6d66585171eac4cd7c6c4a0f)) -- support `ssr: false` ([#351](https://github.com/nitrojs/nitropack/issues/351)) ([ddc045e](https://github.com/nitrojs/nitropack/commit/ddc045e0a6586c689a87c9a7d5aa4061600b098d)) -- support dynamic chunks, lazy middleware and cjs target ([0caa11e](https://github.com/nitrojs/nitropack/commit/0caa11ee2113bcddf662224ba4aaf26362a3e51d)) -- support overriding nested runtime config ([#2](https://github.com/nitrojs/nitropack/issues/2)) ([b9cdcbd](https://github.com/nitrojs/nitropack/commit/b9cdcbd1357c7dd3c554320a561b79a16597ba7e)) -- support runtimeConfig (closes [#43](https://github.com/nitrojs/nitropack/issues/43)) ([5677d86](https://github.com/nitrojs/nitropack/commit/5677d86d8ee06290511abbc6f6600d6d2a5cfb98)) -- support server directory ([#132](https://github.com/nitrojs/nitropack/issues/132)) ([cda0aa4](https://github.com/nitrojs/nitropack/commit/cda0aa47891aec8becec2620ae2faec7a803a723)) -- support serverMiddleware ([e5cd009](https://github.com/nitrojs/nitropack/commit/e5cd009e537b00cb16a032d72abfe21db1605bdd)) -- support serverMiddleware ([#26](https://github.com/nitrojs/nitropack/issues/26)) ([c99316f](https://github.com/nitrojs/nitropack/commit/c99316f8c98045f1cd2cacda4622d4d122aaf7a0)) -- support serverMiddleware ([#26](https://github.com/nitrojs/nitropack/issues/26)) ([92e5015](https://github.com/nitrojs/nitropack/commit/92e5015aff81ad1e785985fdb0058f718bbb2555)) -- support ssrContext.head ([8bcf6fb](https://github.com/nitrojs/nitropack/commit/8bcf6fb74b935c673a5f88a1c35b6327cb48a78b)) -- support staticAssetsBase ([aca8be7](https://github.com/nitrojs/nitropack/commit/aca8be7d1eb3eb0866dc29dd681d5b807fe1382c)) -- support target functions to consume nuxtOptions ([725caec](https://github.com/nitrojs/nitropack/commit/725caecb1518b4195dd2024757c7272d2e8c5c03)) -- support typescript via esbuild (closes [#42](https://github.com/nitrojs/nitropack/issues/42)) ([3dd5276](https://github.com/nitrojs/nitropack/commit/3dd5276d008506c2843b951a3120b4f47012f81c)) -- support universalFetch during generate ([f656d3f](https://github.com/nitrojs/nitropack/commit/f656d3f72760b8d31fa21f9f8f4b6ea353ab55c2)) -- swr support with route rules ([4e37f23](https://github.com/nitrojs/nitropack/commit/4e37f2319932bc2c4067d01f4bf95cba11a9c9fd)) -- switch to h2 stack for dev server ([4dfca5a](https://github.com/nitrojs/nitropack/commit/4dfca5ac874e8d74761c270286a3f0e83fd165be)) -- timing plugin and Server-Timing ([424ce0a](https://github.com/nitrojs/nitropack/commit/424ce0af0edb88970650ab31984fc49fd2d1ad50)) -- unimport support for server api ([#15](https://github.com/nitrojs/nitropack/issues/15)) ([9fc9e03](https://github.com/nitrojs/nitropack/commit/9fc9e032caca71843bbfb8eabf612fbc1d2068e9)) -- update preset options ([12e1291](https://github.com/nitrojs/nitropack/commit/12e1291df6e3f9741449f7ae0aa888e437d0e186)) -- update vercel and improve internals ([9b5ac28](https://github.com/nitrojs/nitropack/commit/9b5ac280f3ab5923e90fad7df3684488cf4a506f)) -- use `@nuxt/design` ([#322](https://github.com/nitrojs/nitropack/issues/322)) ([b9a7033](https://github.com/nitrojs/nitropack/commit/b9a7033e4968fe9526bb93f50926aed265148a2e)) -- use dynamic require for node targets ([a67944f](https://github.com/nitrojs/nitropack/commit/a67944fd83a139384f98829363d1f3055d3e1e3e)) -- use h2@10 ([8ce644a](https://github.com/nitrojs/nitropack/commit/8ce644acc36ef02e855c5cb1bf361c75693e0e64)) -- use native esm for all packages ([#539](https://github.com/nitrojs/nitropack/issues/539)) ([cf4d593](https://github.com/nitrojs/nitropack/commit/cf4d59378355e0633cd942ed9737fe52ecd7a0cf)) -- use virtual filesystem for templates ([#292](https://github.com/nitrojs/nitropack/issues/292)) ([b0a9bd2](https://github.com/nitrojs/nitropack/commit/b0a9bd27516e5d5f37aead42b5ccd218064b479d)) -- use webpack esm server build ([#474](https://github.com/nitrojs/nitropack/issues/474)) ([009579a](https://github.com/nitrojs/nitropack/commit/009579a8bb60de0767e2a9d65977f52c527a9909)) -- **vite:** vite dev server bundler ([#604](https://github.com/nitrojs/nitropack/issues/604)) ([fb91ed2](https://github.com/nitrojs/nitropack/commit/fb91ed2d1847d9759036f0c99c13a67a0c16c814)) -- whitelist static routes ([377a965](https://github.com/nitrojs/nitropack/commit/377a9659fc230a9153801e5da7b07ec887e9726c)) -- **worker:** support process.hrtime ([a5904f5](https://github.com/nitrojs/nitropack/commit/a5904f5276c653be49c65da2b42ee881db6c0cf3)) -- working cloudflare with vue2 and async chunks ([0255442](https://github.com/nitrojs/nitropack/commit/02554424c4623aaa08427346954f7a2b7b026bb0)) -- working poc ([6f5c475](https://github.com/nitrojs/nitropack/commit/6f5c4752c7cc8e67736914bb15e2d7eca18dc3e5)) - -### Bug Fixes - -- \_interopDefault potential cjs files ([d873169](https://github.com/nitrojs/nitropack/commit/d873169363201fcff68a42346b40655ecd51aa05)) -- 404 handling for static assets ([c0cb35d](https://github.com/nitrojs/nitropack/commit/c0cb35df099c57ccf25d92eb28d9e65fb91f0425)) -- add `node_modules` from cwd to nodeResolve ([035a6e6](https://github.com/nitrojs/nitropack/commit/035a6e6ebb3c75b44cc6fc14bb03fa02bf3da38d)) -- add critical css ([37f6d79](https://github.com/nitrojs/nitropack/commit/37f6d797ec83370db0540d19ded954194775f24e)) -- add default route when generating code ([df694ea](https://github.com/nitrojs/nitropack/commit/df694ea391cea425aaba13fe9103bf08a86ea4fb)) -- add default value for assets.dirs ([4d7c6ac](https://github.com/nitrojs/nitropack/commit/4d7c6ac1f61ecc91908644d64984bbec7a3c417f)) -- add default value for buildDir and generateDir ([565a27c](https://github.com/nitrojs/nitropack/commit/565a27cc1200df4c72c499174915383b1ff554f8)) -- add generate.routes and disable crawler ([ec89296](https://github.com/nitrojs/nitropack/commit/ec8929643b57b4416ba688275ea0ac3253041775)) -- add hack for encoding ([20b8f22](https://github.com/nitrojs/nitropack/commit/20b8f228c468cfae1ef8ddb0a62cd715f9bca156)) -- add main entrypoints for packages ([#629](https://github.com/nitrojs/nitropack/issues/629)) ([e4e69f7](https://github.com/nitrojs/nitropack/commit/e4e69f75da77094a2e9afbb64e5c4a76f544b0f6)) -- add missing `#_config` ([#24](https://github.com/nitrojs/nitropack/issues/24)) ([e06573c](https://github.com/nitrojs/nitropack/commit/e06573cbe0671e3e02de8d00cccdb5690e6d9771)) -- add missing default for `devHandlers` ([43b2f41](https://github.com/nitrojs/nitropack/commit/43b2f415780be257c93503c1a3fbc88e709acbd0)) -- add more types ([#16](https://github.com/nitrojs/nitropack/issues/16)) ([da7bbb2](https://github.com/nitrojs/nitropack/commit/da7bbb2c2a228d201cf9452b02a47d4d373372fd)) -- add nitro client plugin ($fetch support) ([#223](https://github.com/nitrojs/nitropack/issues/223)) ([93213f4](https://github.com/nitrojs/nitropack/commit/93213f4f46bd5f6dcc05c2ff1a80321bc89c7779)), closes [#213](https://github.com/nitrojs/nitropack/issues/213) -- add prefix to dynamic imports name ([#5](https://github.com/nitrojs/nitropack/issues/5)) ([eecd766](https://github.com/nitrojs/nitropack/commit/eecd7660a1842bd0be87d6d640d4c15c8c1cc229)) -- add temp fix for browser ([d197716](https://github.com/nitrojs/nitropack/commit/d19771663b8312379b99b1d9b7fee245292f3134)) -- addresses static assets/azure issues ([#49](https://github.com/nitrojs/nitropack/issues/49)) ([88e8bd9](https://github.com/nitrojs/nitropack/commit/88e8bd92205592d9c3335f036ee8091aa4aef9c2)) -- allow matching dynamic page routes ([88d0676](https://github.com/nitrojs/nitropack/commit/88d0676358cdbfab33f4fc467b8ea0ab464c5b26)) -- allow not overriding env, and allow disabling prefix ([#40](https://github.com/nitrojs/nitropack/issues/40)) ([1d6a802](https://github.com/nitrojs/nitropack/commit/1d6a80246ff9b26c59f98a0740485f1f7a38e47c)) -- allow numbers in dynamic webpack chunk names ([#125](https://github.com/nitrojs/nitropack/issues/125)) ([3bfa916](https://github.com/nitrojs/nitropack/commit/3bfa916f9500dd3b166f7d687a4ff1b8ad556911)) -- allow use of nuxt3 in non-wsl windows environment ([#308](https://github.com/nitrojs/nitropack/issues/308)) ([da6da9c](https://github.com/nitrojs/nitropack/commit/da6da9c2b0bd6b2a096f0e151297c7ac04121c0d)) -- always mock generic dependencies ([f210304](https://github.com/nitrojs/nitropack/commit/f2103046d492d3ce9957bb9a362b847cd84e1586)) -- **app, nitro:** fix `app:rendered` hook ([#53](https://github.com/nitrojs/nitropack/issues/53)) ([ecc85f0](https://github.com/nitrojs/nitropack/commit/ecc85f048368cf2f822bcc5c461c3e475d11170c)) -- **app:** make `renderMeta` optional ([#340](https://github.com/nitrojs/nitropack/issues/340)) ([844cbea](https://github.com/nitrojs/nitropack/commit/844cbeaec2e093e8cea77dd691cc82d627ed831d)) -- **automock:** don't externalize .ts imports ([077bf13](https://github.com/nitrojs/nitropack/commit/077bf13b64c2b48f1d95a0998cf08c24a49ecdb9)) -- avoid `replaceAll` for platform compatibility ([3cde549](https://github.com/nitrojs/nitropack/commit/3cde54924170193ff527c17eac43c1a20c4bfc27)) -- avoid closing on dev command ([b6cca1a](https://github.com/nitrojs/nitropack/commit/b6cca1aab5c1743d9c3b6eed0767f5c609e0516a)) -- avoid overriding hooks ([d722e9f](https://github.com/nitrojs/nitropack/commit/d722e9f7892313345c000205757c62b6996261ab)) -- avoid reloading worker when entry not exists ([5d3ca2f](https://github.com/nitrojs/nitropack/commit/5d3ca2fcb5811a8c057cde47c5106a9b06fdef69)) -- await for reload process before responding ([f441b30](https://github.com/nitrojs/nitropack/commit/f441b30095d5a1ab8f5e7df5ecf550d593ed09fa)) -- **bridge:** plugin default detection ([#1847](https://github.com/nitrojs/nitropack/issues/1847)) ([f7748e2](https://github.com/nitrojs/nitropack/commit/f7748e22e4163211f416d47a000d087d3bf4f2f1)) -- **bridge:** set `app.basePath` ([#2808](https://github.com/nitrojs/nitropack/issues/2808)) ([8df7624](https://github.com/nitrojs/nitropack/commit/8df762429e24485548a38b915bd5ba9fbaba0b54)) -- bring back nuxt3 support ([a87c2a5](https://github.com/nitrojs/nitropack/commit/a87c2a58913b7d8405d7a471dd1f6cacacebb0f1)) -- **browser:** 400.html ~> 404.html ([7c68add](https://github.com/nitrojs/nitropack/commit/7c68add9e686b0fe234a439d8863db908902e34b)) -- check for server webpack config ([#91](https://github.com/nitrojs/nitropack/issues/91)) ([03bb235](https://github.com/nitrojs/nitropack/commit/03bb23569f30b338eb0cf0650999f66430cd39a3)) -- clone config and preserve overrides for prerender instance ([08c65b8](https://github.com/nitrojs/nitropack/commit/08c65b8945b3d44ea99b72ca566d8906efa00ce3)) -- cloudflare and polyfill ([dc967bc](https://github.com/nitrojs/nitropack/commit/dc967bcb77a733491475ffaac4dcc1327e83ceab)) -- **cloudflare, lambda:** preserve query parameters in url ([#155](https://github.com/nitrojs/nitropack/issues/155)) ([b59986d](https://github.com/nitrojs/nitropack/commit/b59986d1b89e035be3b9011041d54bb362aff040)) -- **compat:** add template variables for compat module ([#162](https://github.com/nitrojs/nitropack/issues/162)) ([126920a](https://github.com/nitrojs/nitropack/commit/126920aa7c54b99453a1ef0e772ea30f10e33723)) -- **compat:** cannot read property setLegacyMiddleware of undefined ([#82](https://github.com/nitrojs/nitropack/issues/82)) ([29b368e](https://github.com/nitrojs/nitropack/commit/29b368effaa6562242d007371ca4e3a2448e7138)) -- **compat:** disable webpack sourcemap ([#84](https://github.com/nitrojs/nitropack/issues/84)) ([961f18d](https://github.com/nitrojs/nitropack/commit/961f18de53f8c85933e9463a4638e5ad62be036d)) -- **compat:** enforce nuxt generate for static target ([#148](https://github.com/nitrojs/nitropack/issues/148)) ([8e0b095](https://github.com/nitrojs/nitropack/commit/8e0b095bb0368c77df130942189f0cca424bcbfa)) -- **components:** augment 'vue' module rather than overwriting ([#305](https://github.com/nitrojs/nitropack/issues/305)) ([c631f11](https://github.com/nitrojs/nitropack/commit/c631f115dd70d9d7da31daadf85e3bc04daeae72)) -- **config:** always disasble server sourceMap ([#88](https://github.com/nitrojs/nitropack/issues/88)) ([a5eb76e](https://github.com/nitrojs/nitropack/commit/a5eb76e311d5a74239b7e57333759d367e562745)) -- configurable publicPath (closes [#21](https://github.com/nitrojs/nitropack/issues/21)) ([9262d64](https://github.com/nitrojs/nitropack/commit/9262d64c5598c6fdf6e87730f622435047ff98dd)) -- default value for template path ([b334942](https://github.com/nitrojs/nitropack/commit/b3349428bf5d2891e24e87542b68568185c9e80a)) -- **dep:** pin esbuild to 0.10.x due to module breaking changes ([879a5bc](https://github.com/nitrojs/nitropack/commit/879a5bc02d680b61ab40d697c84d466cc39e03c3)) -- **deps:** update `h3` to `0.5.2` ([ce14f33](https://github.com/nitrojs/nitropack/commit/ce14f334ebe5260437acf059ce7fae6d8bdb063a)) -- **deps:** update dependency ohmyfetch to ^0.4.4 ([#1705](https://github.com/nitrojs/nitropack/issues/1705)) ([27f238f](https://github.com/nitrojs/nitropack/commit/27f238fe63ff8e0a9c2b73f0ead6afcbb10bd311)) -- **deps:** upgrade jiti to 2.12.9 ([#1171](https://github.com/nitrojs/nitropack/issues/1171)) ([e939b36](https://github.com/nitrojs/nitropack/commit/e939b36e31afb334e4b4d216148cead201421559)) -- **dev:** add conditional check for `removeAllListeners` call ([6529f60](https://github.com/nitrojs/nitropack/commit/6529f604d4783b1922ec339c0091026ef60364b7)) -- **dev:** handle unhandledRejection and uncaughtException to avoid failing worker state ([4e8a661](https://github.com/nitrojs/nitropack/commit/4e8a6610742bc2b27e5feb4bdfa1d121776e3de0)) -- **dev:** use localhost for emitted host in port mode ([eb6ebdb](https://github.com/nitrojs/nitropack/commit/eb6ebdb4c475c8bffd4bf4608d93ee91be9d9378)) -- disable cleanTargetDir for vercel ([9d8a95b](https://github.com/nitrojs/nitropack/commit/9d8a95b05424018bb1a76eedf9db2c732af7b751)) -- disable external tracing for local preset ([0d7d102](https://github.com/nitrojs/nitropack/commit/0d7d102089dd4fb7e89313e4461d6d4c29bb0569)) -- disable static manifest generation (resolves [#53](https://github.com/nitrojs/nitropack/issues/53)) ([df69cfa](https://github.com/nitrojs/nitropack/commit/df69cfa4808da3b8f867c97bc7a74a851c0eaae3)) -- do not inline whole `rootDir` ([0929bcd](https://github.com/nitrojs/nitropack/commit/0929bcd651e6ab139554e0af946985765f826c56)) -- don't set \_registeredComponents ([89b1958](https://github.com/nitrojs/nitropack/commit/89b1958f41f4fd5b9ec718f1f70074dc12abaf40)) -- enable vue-resolution workaround ([17c3c60](https://github.com/nitrojs/nitropack/commit/17c3c60732df8b0ef70a6884fbdd53cc781e206e)) -- ensure builds are relative to buildDir ([ba687f8](https://github.com/nitrojs/nitropack/commit/ba687f8c96c65cb51c1d7ecf4b561412d06969a0)) -- exec require before return ([a3fb537](https://github.com/nitrojs/nitropack/commit/a3fb5372b21450833cc267bc551f2a589a2b52f8)) -- expose types ([66b4973](https://github.com/nitrojs/nitropack/commit/66b4973f83b95b82a19f350c5eeb9a9e148fbce5)) -- extend routes from serverless.static ([75ae176](https://github.com/nitrojs/nitropack/commit/75ae17631eed148349ecea9aebe314f2ccc5c1cd)) -- **externals:** handle non pkg paths ([0831bac](https://github.com/nitrojs/nitropack/commit/0831bac1b511aaa9d8b4bf342996e76c7cdc8a78)) -- **externals:** use normalizeid for external files ([b9db0e9](https://github.com/nitrojs/nitropack/commit/b9db0e932a7e6d8d2af35921d2b4355e2b0768c2)) -- **externals:** windows compatibility with parseNodeModulePath ([935f39a](https://github.com/nitrojs/nitropack/commit/935f39a623406c826734e2771738113a8597136a)) -- fix \_interopDefault implementation ([faa7245](https://github.com/nitrojs/nitropack/commit/faa72459271f46831e087f2b5b36601c404a57ae)) -- fix error template formatting ([545ccf6](https://github.com/nitrojs/nitropack/commit/545ccf6c7e79e0832641f04b73b04e3a66c80bef)) -- fix issues with router.base support ([5a7e0fa](https://github.com/nitrojs/nitropack/commit/5a7e0faf3d5ef9db11ca907df404babc0c1fdf30)) -- fix mocks and disable buffer since is unnecessary ([ecdf2cd](https://github.com/nitrojs/nitropack/commit/ecdf2cd613771945acac6bf555171d2d58fff87a)) -- fix preview and deploy command info ([1c1bf04](https://github.com/nitrojs/nitropack/commit/1c1bf0450a9d3ef49e5b5cc677b8bbee93d43b62)) -- fix worker polyfill by adding performance ([a30fed4](https://github.com/nitrojs/nitropack/commit/a30fed4e46d4649e48ef9574e95258e4413a08c9)) -- force rebuild on new files being added ([#136](https://github.com/nitrojs/nitropack/issues/136)) ([2ca8a87](https://github.com/nitrojs/nitropack/commit/2ca8a873504947d16f0f6226cbdb8ca411fcc439)) -- handle decoding static file names ([#13](https://github.com/nitrojs/nitropack/issues/13)) ([5504ce9](https://github.com/nitrojs/nitropack/commit/5504ce9f3df5f54e9a70d66b2ff917b6cd26f686)) -- handle if serverless is not set in config ([f055ddd](https://github.com/nitrojs/nitropack/commit/f055ddd12d780756d0ab87af0edd81e7c1f245b1)) -- handle undefined error stack in production ([39ef2b3](https://github.com/nitrojs/nitropack/commit/39ef2b3854a749fecc62403e5b195d703342d231)) -- hide rollup circular and eval ([e5f9900](https://github.com/nitrojs/nitropack/commit/e5f9900bc73456ddcb8a4c25649ed2d4f797c099)) -- host ~> hostname ([7c663c2](https://github.com/nitrojs/nitropack/commit/7c663c20a67c8b30c434be36eefda2b3da4d61b7)) -- ignore close listeners ([ae22387](https://github.com/nitrojs/nitropack/commit/ae22387c3fe6235428ad8e7000b6c92dfba2fd07)) -- ignore resolving vue alias when not found ([5f12eaa](https://github.com/nitrojs/nitropack/commit/5f12eaa706a84ec1caf28a988b12ffbea40767a5)) -- improve externals handling ([a5262e4](https://github.com/nitrojs/nitropack/commit/a5262e4fa998d4fe4a733ac656c23fe198b72589)) -- improve prerender logs ([32ff5e4](https://github.com/nitrojs/nitropack/commit/32ff5e49b11058ffc9b91c3c55b4787ffa6693f7)) -- improve type declarations ([#1178](https://github.com/nitrojs/nitropack/issues/1178)) ([a2526f7](https://github.com/nitrojs/nitropack/commit/a2526f7c10f73336c889598eac676060eab58d87)) -- issues with externals outside of rootDir ([a7cbfbe](https://github.com/nitrojs/nitropack/commit/a7cbfbe1d6fe94dfc20e36370dd074a248555d9d)) -- lazy is true by default ([04d28b9](https://github.com/nitrojs/nitropack/commit/04d28b9f609d5456546a2ecc112df6ec532f2354)) -- less verbose logs when testing ([00177d0](https://github.com/nitrojs/nitropack/commit/00177d02b7181e990983a3527f2d2d4106bf83bb)) -- load webpack modules synchronously with `require` ([#104](https://github.com/nitrojs/nitropack/issues/104)) ([c20e813](https://github.com/nitrojs/nitropack/commit/c20e81387baf2eee54718ce94ab2b4865a2d82b4)) -- move hrtime polyfill to timing plugin ([fe9d073](https://github.com/nitrojs/nitropack/commit/fe9d0737b88a8219f4fa278d87df6ae800663869)) -- **netlify:** update output templates ([4f46310](https://github.com/nitrojs/nitropack/commit/4f46310633d5a78b0ef618aa7e500134c20a1344)) -- **nitro, nuxi:** add runtimeConfig types (for `#config` and `useRuntimeConfig()`) ([#1783](https://github.com/nitrojs/nitropack/issues/1783)) ([486be51](https://github.com/nitrojs/nitropack/commit/486be51e10871a81b83d4f80374055220abf715f)) -- **nitro:** `dot-prop` esm compatibility ([#829](https://github.com/nitrojs/nitropack/issues/829)) ([f157f56](https://github.com/nitrojs/nitropack/commit/f157f5680fbac314f470c9b83629d09ce7630f0a)) -- **nitro:** `table` esm compatibility (resolves [#877](https://github.com/nitrojs/nitropack/issues/877)) ([4c05a90](https://github.com/nitrojs/nitropack/commit/4c05a905b18c7a929996e432796015bd188e6457)) -- **nitro:** absolute external resolution ([#80](https://github.com/nitrojs/nitropack/issues/80)) ([b03c813](https://github.com/nitrojs/nitropack/commit/b03c813e45a1bfc7684f1ab727a3aeeca3780c1c)) -- **nitro:** add back compat entry ([70bf183](https://github.com/nitrojs/nitropack/commit/70bf1834e14ebe0825d7846a23cf6e6304af6345)) -- **nitro:** add body + body prepended scripts to template ([#154](https://github.com/nitrojs/nitropack/issues/154)) ([f348588](https://github.com/nitrojs/nitropack/commit/f348588f7b76885431ab154be3d93fa563537787)) -- **nitro:** add error logging to `initWorker`([#2090](https://github.com/nitrojs/nitropack/issues/2090)) ([9e004e1](https://github.com/nitrojs/nitropack/commit/9e004e10195d4e9a5f31ef0d35f949a044ae2693)) -- **nitro:** add missing kit dependency ([dfa3d8d](https://github.com/nitrojs/nitropack/commit/dfa3d8da8a6710da31c619a6e77bad2c8fc02bfe)) -- **nitro:** add temporary workarouind for ufo resolution in nuxt2 ([e5ecf6b](https://github.com/nitrojs/nitropack/commit/e5ecf6b029e657f7f097f1a8e4b19a9cb8821cc8)) -- **nitro:** allow inlining subpath of externals ([#2759](https://github.com/nitrojs/nitropack/issues/2759)) ([30023f7](https://github.com/nitrojs/nitropack/commit/30023f79f745bedbe47200b07e4e913bd1ea76da)) -- **nitro:** always inline `.wasm` ([#698](https://github.com/nitrojs/nitropack/issues/698)) ([e7bb03c](https://github.com/nitrojs/nitropack/commit/e7bb03ce731d1411368472915539889be68e5f87)) -- **nitro:** avoid using fs/promises ([bd25e87](https://github.com/nitrojs/nitropack/commit/bd25e873b9ebf1869538265b923f7ae5a9741a2b)) -- **nitro:** bundle json files ([#1245](https://github.com/nitrojs/nitropack/issues/1245)) ([adf2235](https://github.com/nitrojs/nitropack/commit/adf223590f00899d06e9b40ddaf83d037c5bfe58)) -- **nitro:** correct `#assets` type declaration ([#2403](https://github.com/nitrojs/nitropack/issues/2403)) ([bc9817c](https://github.com/nitrojs/nitropack/commit/bc9817ce02c565c62885f4c9f7328f3c1bb00b11)) -- **nitro:** correct issues rendering `payload.js` ([#466](https://github.com/nitrojs/nitropack/issues/466)) ([584a14d](https://github.com/nitrojs/nitropack/commit/584a14db5156a8e99261037d2c6f069fa082f69c)) -- **nitro:** correct vercel fs api static directory ([#488](https://github.com/nitrojs/nitropack/issues/488)) ([cd0616e](https://github.com/nitrojs/nitropack/commit/cd0616e111cce78057f5fda7b13f793754c086db)) -- **nitro:** detect `NETLIFY_LOCAL` ([#400](https://github.com/nitrojs/nitropack/issues/400)) ([f78d185](https://github.com/nitrojs/nitropack/commit/f78d1858d2e7b82467c8982716f2864f450f2ddd)) -- **nitro:** detect routes and middleware starting with dots ([#2771](https://github.com/nitrojs/nitropack/issues/2771)) ([9b3d6c2](https://github.com/nitrojs/nitropack/commit/9b3d6c2dbd5300f0daa983fc6f749f6fe41f628f)) -- **nitro:** disable `moduleSideEffects` by default ([#377](https://github.com/nitrojs/nitropack/issues/377)) ([ec207e9](https://github.com/nitrojs/nitropack/commit/ec207e9c9ff7e57733f9bb97df9dcfcf4511be79)) -- **nitro:** disable automatic spa fallback ([#1071](https://github.com/nitrojs/nitropack/issues/1071)) ([4427b89](https://github.com/nitrojs/nitropack/commit/4427b89a69ddd469812b6324a2e45dd4bc13f904)) -- **nitro:** disable externals in worker preset ([#535](https://github.com/nitrojs/nitropack/issues/535)) ([2298276](https://github.com/nitrojs/nitropack/commit/22982761af47b0e7693957d04c46a69fed5df275)) -- **nitro:** do not modify `event.request` for worker entries ([#1279](https://github.com/nitrojs/nitropack/issues/1279)) ([cc9a4cd](https://github.com/nitrojs/nitropack/commit/cc9a4cd24f6acad4ae7e4183a34cd5da8e04ba06)) -- **nitro:** do not overwrite output files for browser-preset ([#516](https://github.com/nitrojs/nitropack/issues/516)) ([69fd546](https://github.com/nitrojs/nitropack/commit/69fd546b63f10becd706d24b917e01e1b60aaa00)) -- **nitro:** don't externalize [@nuxt](https://github.com/nuxt), virtual: and # ([e53e297](https://github.com/nitrojs/nitropack/commit/e53e297cee7dc4e3fc62c6fb1f88a28d81505e36)) -- **nitro:** emit chunk names without `#` ([#477](https://github.com/nitrojs/nitropack/issues/477)) ([ce9a38e](https://github.com/nitrojs/nitropack/commit/ce9a38e23903802b7c29bec9215c899a3e44b379)) -- **nitro:** ensure that nitro runtime is not externalized ([#121](https://github.com/nitrojs/nitropack/issues/121)) ([d78237d](https://github.com/nitrojs/nitropack/commit/d78237db1bd7b662a687884eb1cc8c0c934cfb6a)) -- **nitro:** exclude `rootDir` from externals and reinstate automock warning ([#66](https://github.com/nitrojs/nitropack/issues/66)) ([5d9344f](https://github.com/nitrojs/nitropack/commit/5d9344fc529995d5de0a4b9f24d2f12f2cab6c79)) -- **nitro:** export named function rather than default export ([#490](https://github.com/nitrojs/nitropack/issues/490)) ([3ade210](https://github.com/nitrojs/nitropack/commit/3ade21091684a1306800f19871854b7e78932f77)) -- **nitro:** filter alias in `/_vfs` listing ([#1296](https://github.com/nitrojs/nitropack/issues/1296)) ([39b6db8](https://github.com/nitrojs/nitropack/commit/39b6db8ee1692ac2a163a144d0c9c523974c42d4)) -- **nitro:** filter out duplicate imports ([#378](https://github.com/nitrojs/nitropack/issues/378)) ([6ce6f68](https://github.com/nitrojs/nitropack/commit/6ce6f6875f70e37143e36100501cb71b70fceb1a)) -- **nitro:** firebase package.json is not exported ([#809](https://github.com/nitrojs/nitropack/issues/809)) ([31454ea](https://github.com/nitrojs/nitropack/commit/31454eaac26bf081b206ee23756ff9d070a0d194)) -- **nitro:** fix EBUSY error on windows ([#425](https://github.com/nitrojs/nitropack/issues/425)) ([5d79b2f](https://github.com/nitrojs/nitropack/commit/5d79b2f4a7af22a9be48f92357a4406bf9ed5006)) -- **nitro:** fix externals regex for scoped packages ([349c1d0](https://github.com/nitrojs/nitropack/commit/349c1d09b057781fccf5d4c67475c1632248500c)), closes [#238](https://github.com/nitrojs/nitropack/issues/238) -- **nitro:** fix regex for tracedFiles scanning ([#1509](https://github.com/nitrojs/nitropack/issues/1509)) ([6054d5b](https://github.com/nitrojs/nitropack/commit/6054d5b1c9663c72d2c7c73375691f0226773783)) -- **nitro:** fix rendering with `ssr` disabled ([#2191](https://github.com/nitrojs/nitropack/issues/2191)) ([d32d40d](https://github.com/nitrojs/nitropack/commit/d32d40df11e699f0503ba8dfa3c9fcf04a8ded49)) -- **nitro:** fix type inference for `$fetch` ([#938](https://github.com/nitrojs/nitropack/issues/938)) ([d9fdf29](https://github.com/nitrojs/nitropack/commit/d9fdf29ff913a2d2489b157cb1696c4638d6d4f9)) -- **nitro:** generate correct netlify entrypoint ([#372](https://github.com/nitrojs/nitropack/issues/372)) ([49a5ebd](https://github.com/nitrojs/nitropack/commit/49a5ebd872c7477b91db3b9d2ae30841e90a790c)) -- **nitro:** generate netlify `_redirects` in public ([#298](https://github.com/nitrojs/nitropack/issues/298)) ([2534dc6](https://github.com/nitrojs/nitropack/commit/2534dc6911253581446597a87710108a5672f39f)) -- **nitro:** handle esm imports from cjs files ([8decd90](https://github.com/nitrojs/nitropack/commit/8decd9008cad16bba135d72f3fdd96d3244f4b03)) -- **nitro:** handle ssr redirects ([#392](https://github.com/nitrojs/nitropack/issues/392)) ([42405c2](https://github.com/nitrojs/nitropack/commit/42405c252d9a50124566d0f15b5f7c40be463f3d)) -- **nitro:** handle static assets and api routes for `service-worker` preset ([#518](https://github.com/nitrojs/nitropack/issues/518)) ([9808f05](https://github.com/nitrojs/nitropack/commit/9808f05b510c2613e189d3c82726fa0d8e303eac)) -- **nitro:** handle terminating uninitialized worker ([9132a67](https://github.com/nitrojs/nitropack/commit/9132a67131bb8511b0ea8be3ac7a2dd2b134696f)) -- **nitro:** import externals as esm namespace ([#394](https://github.com/nitrojs/nitropack/issues/394)) ([1b7f9af](https://github.com/nitrojs/nitropack/commit/1b7f9af123f6fdb0fe773984fd92181bf1de6971)) -- **nitro:** import rollup as cjs ([1d9602c](https://github.com/nitrojs/nitropack/commit/1d9602cf00d6b444df0a79774ec5cef05d1f0e6a)) -- **nitro:** improve externals error handling ([#1188](https://github.com/nitrojs/nitropack/issues/1188)) ([59ea572](https://github.com/nitrojs/nitropack/commit/59ea5722b5ff57a14fd737b7ef032a512848a496)) -- **nitro:** inject entryURL at beginning of entrypoint ([#468](https://github.com/nitrojs/nitropack/issues/468)) ([cb3affa](https://github.com/nitrojs/nitropack/commit/cb3affa4eb96242c6a995632dba72da5f393c8c3)) -- **nitro:** inject payload for spa renderer ([#1434](https://github.com/nitrojs/nitropack/issues/1434)) ([09061ca](https://github.com/nitrojs/nitropack/commit/09061ca194935c9effe147d9bf55394a4733dbc2)) -- **nitro:** mock consola ([#106](https://github.com/nitrojs/nitropack/issues/106)) ([1679d18](https://github.com/nitrojs/nitropack/commit/1679d18133676e41941854762207cc9814defccb)) -- **nitro:** modify contents rather than compiled , remove template `compiled` ([#1154](https://github.com/nitrojs/nitropack/issues/1154)) ([5d7740c](https://github.com/nitrojs/nitropack/commit/5d7740c229ae4e6e3be83971a44d738b165e2f6a)) -- **nitro:** narrow replace call for template name ([#1626](https://github.com/nitrojs/nitropack/issues/1626)) ([4e0f597](https://github.com/nitrojs/nitropack/commit/4e0f597aa429b60b5d1a7cbf846637a0ef11907c)) -- **nitro:** omit `/index` from generated api urls ([#1371](https://github.com/nitrojs/nitropack/issues/1371)) ([f1a17f2](https://github.com/nitrojs/nitropack/commit/f1a17f28366887761c0909f8c3380c304774d247)) -- **nitro:** only serve placeholders for `publicPath` ([1cf0844](https://github.com/nitrojs/nitropack/commit/1cf0844b1d5770a17a84b20bd7fff6e8fe82770e)) -- **nitro:** ovrride by user input ([306b96f](https://github.com/nitrojs/nitropack/commit/306b96f82e97d42f0fcf082147a523714d9b478d)) -- **nitro:** pass `Headers` to `createFetch` ([#2615](https://github.com/nitrojs/nitropack/issues/2615)) ([87da9c7](https://github.com/nitrojs/nitropack/commit/87da9c7a8d80673e3ff4f879c9212db4dea7225f)) -- **nitro:** pass query params to localCall in service worker ([#530](https://github.com/nitrojs/nitropack/issues/530)) ([2af7359](https://github.com/nitrojs/nitropack/commit/2af7359f0bf95c6f6405325a47c99d8914dfa580)) -- **nitro:** pass req, res to ssr context (resolves [#39](https://github.com/nitrojs/nitropack/issues/39)) ([0e651d8](https://github.com/nitrojs/nitropack/commit/0e651d8e2c7b471a54b33e0d4f42930f2b263fcf)) -- **nitro:** pass sourcemap option through to rollup plugins ([#2387](https://github.com/nitrojs/nitropack/issues/2387)) ([2122f5c](https://github.com/nitrojs/nitropack/commit/2122f5cc7a8ec901a832474db79d0d4848829ab1)) -- **nitro:** promisify proxy handler ([#398](https://github.com/nitrojs/nitropack/issues/398)) ([0765495](https://github.com/nitrojs/nitropack/commit/0765495207d48c7d0dea8e5fd98136beef7390d0)) -- **nitro:** read body stream on post requests for `service-worker` ([#527](https://github.com/nitrojs/nitropack/issues/527)) ([cf19a6a](https://github.com/nitrojs/nitropack/commit/cf19a6a6bcb0e496493c5cc2643fc559ba1d3319)) -- **nitro:** read firebase package.json ([#1108](https://github.com/nitrojs/nitropack/issues/1108)) ([cc66a40](https://github.com/nitrojs/nitropack/commit/cc66a404debfd4dd3176783c438629b5df1bdb5e)) -- **nitro:** remove depd unenv alias ([#120](https://github.com/nitrojs/nitropack/issues/120)) ([10083b6](https://github.com/nitrojs/nitropack/commit/10083b6e106dd4952a2780f43d1015063750974c)) -- **nitro:** resolve alias for serverMiddleware ([79ef2fb](https://github.com/nitrojs/nitropack/commit/79ef2fb055e6f5f5d4810645b4b968e9cbe14d70)) -- **nitro:** resolve default export for assets ([60c1b6b](https://github.com/nitrojs/nitropack/commit/60c1b6ba0a0c759eac917aac56e968639d054c05)) -- **nitro:** resolve firebase package versions with `pkg-types` ([#1490](https://github.com/nitrojs/nitropack/issues/1490)) ([971a9dd](https://github.com/nitrojs/nitropack/commit/971a9ddc5584d85a0af346135279d1fe9ca5725e)) -- **nitro:** respect fs structure for traced files ([#2107](https://github.com/nitrojs/nitropack/issues/2107)) ([e3faaed](https://github.com/nitrojs/nitropack/commit/e3faaed1e8584b337bd1da43f856aa2e90fc8999)) -- **nitro:** revert to main rollup import (closes [#1445](https://github.com/nitrojs/nitropack/issues/1445)) ([5056059](https://github.com/nitrojs/nitropack/commit/505605922756026b95b04d7d4b7e787ee3a2b57d)) -- **nitro:** set `makeAbsoluteExternalsRelative` to false (resolves [#160](https://github.com/nitrojs/nitropack/issues/160)) ([df28558](https://github.com/nitrojs/nitropack/commit/df285585a145733fc8a7a67e14691b91b993de95)) -- **nitro:** set content-type header before html 404 ([#2301](https://github.com/nitrojs/nitropack/issues/2301)) ([68ab584](https://github.com/nitrojs/nitropack/commit/68ab584b7a089e425014fd692b7156e42622f11b)) -- **nitro:** set esbuild `target: '2019'` ([#189](https://github.com/nitrojs/nitropack/issues/189)) ([7d8505c](https://github.com/nitrojs/nitropack/commit/7d8505c59dde1a4a8dbea40bd3d8bdfedaa7de36)) -- **nitro:** show all ERR_MODULE_NOT_FOUND errors ([#561](https://github.com/nitrojs/nitropack/issues/561)) ([1a98e26](https://github.com/nitrojs/nitropack/commit/1a98e262f6732b3361615f7639cad370ecae76da)) -- **nitro:** skip copying symlinks and directories ([#1510](https://github.com/nitrojs/nitropack/issues/1510)) ([5a0d1a1](https://github.com/nitrojs/nitropack/commit/5a0d1a1f0ff140313b94134b85a7a32da198ae9d)) -- **nitro:** skip non existing externals ([#1876](https://github.com/nitrojs/nitropack/issues/1876)) ([bae42e9](https://github.com/nitrojs/nitropack/commit/bae42e9f691ca6560de5a3a588b3101fb99394eb)) -- **nitro:** sort middleware from long to short ([340bc61](https://github.com/nitrojs/nitropack/commit/340bc61fda9cec163e269901170b89b86a2d55b5)) -- **nitro:** support ~/@ aliases and explicitly externalize buildDir ([242207a](https://github.com/nitrojs/nitropack/commit/242207ab7e32bd3bcad4566f816fc40f01349d02)) -- **nitro:** support built `publicPath` ([#1479](https://github.com/nitrojs/nitropack/issues/1479)) ([8934c04](https://github.com/nitrojs/nitropack/commit/8934c0477299ea7c098c78b3babd8c05027f2b89)) -- **nitro:** support vue-meta (compat) ([f0cd329](https://github.com/nitrojs/nitropack/commit/f0cd32997ecf5acbb95dbeefdc41e922ada080f7)) -- **nitro:** terminate active worker before replacing ([#1302](https://github.com/nitrojs/nitropack/issues/1302)) ([1b93a42](https://github.com/nitrojs/nitropack/commit/1b93a42c81ec05497244aa9b6fa9b00a989612b0)) -- **nitro:** type inference for api routes returning promise ([#1483](https://github.com/nitrojs/nitropack/issues/1483)) ([3f5bba1](https://github.com/nitrojs/nitropack/commit/3f5bba15f6d7430493b98f1fb3a0faaa18254a9e)) -- **nitro:** update azure swa implementation ([#1069](https://github.com/nitrojs/nitropack/issues/1069)) ([5194af6](https://github.com/nitrojs/nitropack/commit/5194af646b53dbff93b360f60c9b3cbf0ff305e5)) -- **nitro:** update dot-prop import ([81f51d5](https://github.com/nitrojs/nitropack/commit/81f51d5fc2df92504fbe0d4f0a8a85720efdae5c)) -- **nitro:** update firebase preset to handle mjs output ([#1360](https://github.com/nitrojs/nitropack/issues/1360)) ([7797383](https://github.com/nitrojs/nitropack/commit/77973834388c87809f1075000373ad9c5571e775)) -- **nitro:** update nitro internal hook name ([#218](https://github.com/nitrojs/nitropack/issues/218)) ([f99d5a2](https://github.com/nitrojs/nitropack/commit/f99d5a25b9b48365ff1928bc184394c267bc5f48)) -- **nitro:** upgrade table dependency ([3e43fd7](https://github.com/nitrojs/nitropack/commit/3e43fd78e75bc5e103231606df18c44a649e6bb0)), closes [#2250](https://github.com/nitrojs/nitropack/issues/2250) -- **nitro:** use `app.assetsPath` for `publicPath` ([#1978](https://github.com/nitrojs/nitropack/issues/1978)) ([699e763](https://github.com/nitrojs/nitropack/commit/699e7638842fb8bf451bba06327ce8364eb130bd)) -- **nitro:** use `generate:page` hook for browser to inject sw ([134431b](https://github.com/nitrojs/nitropack/commit/134431b3db9b9c7577a33a9c023275caae53c7ba)), closes [#522](https://github.com/nitrojs/nitropack/issues/522) -- **nitro:** use file url for `#build` alias in windows dev ([#469](https://github.com/nitrojs/nitropack/issues/469)) ([d4a9f23](https://github.com/nitrojs/nitropack/commit/d4a9f233a888808bed3a582261b90a2c0f45a985)) -- **nitro:** use globalThis ([5a0d9e7](https://github.com/nitrojs/nitropack/commit/5a0d9e7303cfea8e3ffa6fd7abd05bde3f809b00)) -- **nitro:** use nuxt2 compatible template ([#268](https://github.com/nitrojs/nitropack/issues/268)) ([48e2dfa](https://github.com/nitrojs/nitropack/commit/48e2dfa346f5fd790c4f31f6ec27d80d39a4067a)), closes [#265](https://github.com/nitrojs/nitropack/issues/265) -- **nitro:** use random port for stackblitz ([#1666](https://github.com/nitrojs/nitropack/issues/1666)) ([d5bb79c](https://github.com/nitrojs/nitropack/commit/d5bb79c48c7a23d8061fc4279eb02f4c6e47f718)) -- **nitro:** use unenv 0.3.x (closes [#266](https://github.com/nitrojs/nitropack/issues/266)) ([6ac6aeb](https://github.com/nitrojs/nitropack/commit/6ac6aeb94a66427ddc958832793cb0c4d039a4f7)) -- **nitro:** used named export for azure entry ([#491](https://github.com/nitrojs/nitropack/issues/491)) ([903ab87](https://github.com/nitrojs/nitropack/commit/903ab872bfc509d90d518c8aa1ba59ad19dc7f85)) -- **nitro:** watch .mjs and .cjs extensions (closes [#352](https://github.com/nitrojs/nitropack/issues/352)) ([cab8faa](https://github.com/nitrojs/nitropack/commit/cab8faa866b14b5d1b8f8a65a6306ecf654750b8)) -- **nitro:** workaround for vue2 global style injection ([f1b74d0](https://github.com/nitrojs/nitropack/commit/f1b74d093421e42322195cd5a6e58ba544c59794)) -- **nuxi:** update version and vite detection ([#1169](https://github.com/nitrojs/nitropack/issues/1169)) ([db69571](https://github.com/nitrojs/nitropack/commit/db695717b49ac8c3d481ad9e22b7bd01cd440760)) -- **nuxt3:** provide `NuxtWelcome` component from design ([#745](https://github.com/nitrojs/nitropack/issues/745)) ([2d13716](https://github.com/nitrojs/nitropack/commit/2d137168b6a621ea403af116996dfd553b007882)) -- only generate .sls directory when needed ([de51381](https://github.com/nitrojs/nitropack/commit/de513815b597c08009a7a22e064046e1a4195567)) -- pass Headers to createFetch ([#7](https://github.com/nitrojs/nitropack/issues/7)) ([0b55f3c](https://github.com/nitrojs/nitropack/commit/0b55f3cdc22d3e8fa3996d1d6f5f15dddadb9e54)) -- **pkg:** downgrade node version to 14.16.x due to stackblitz issue ([18d2a90](https://github.com/nitrojs/nitropack/commit/18d2a907aa9b21135767841e39ac83e096058720)) -- **pkg:** downgrade node version to 14.17.x due to codesandbox issue ([f00f9d4](https://github.com/nitrojs/nitropack/commit/f00f9d4d5d22c93529ca721b9093e35ea04bcc69)) -- **pkg:** expose `defineNitroPreset` ([4846247](https://github.com/nitrojs/nitropack/commit/48462472ea27b00f66528946dcffbec60b0851bc)) -- **pkg:** remove vue3 from peerDependencies ([#1382](https://github.com/nitrojs/nitropack/issues/1382)) ([814ac73](https://github.com/nitrojs/nitropack/commit/814ac7377a2321aa039bb714b4cf3ce0e8f0f253)) -- **pkg:** support node 17.x in the engines field ([#1443](https://github.com/nitrojs/nitropack/issues/1443)) ([3416d8c](https://github.com/nitrojs/nitropack/commit/3416d8c7be8eb6f70e94fce319f2309a3dcbc90a)) -- preset types ([5574f7e](https://github.com/nitrojs/nitropack/commit/5574f7e2216ef16c0ffa7f91821d2e7f5f6891f1)) -- promisify: false support ([768081b](https://github.com/nitrojs/nitropack/commit/768081bca2443530fa890ad91724649d3452f07d)) -- properly resolve runtimeDir from chunks ([9adfacd](https://github.com/nitrojs/nitropack/commit/9adfacd860cbecfd4eb0d101b9f5072a9f01e50c)) -- remove extra `console.log` ([82c2767](https://github.com/nitrojs/nitropack/commit/82c27673951248c7e1527b8c7f683357c3a8d8f4)) -- remove runtime/ prefix ([0be4ba1](https://github.com/nitrojs/nitropack/commit/0be4ba18acd1359775ae1c741812c336766759c1)) -- remove windows workaround for now ([4af4f32](https://github.com/nitrojs/nitropack/commit/4af4f32e386ea5d55bb84306bfd7f5393dce48d2)) -- rename cold start -> nitro start ([#12](https://github.com/nitrojs/nitropack/issues/12)) ([bba998b](https://github.com/nitrojs/nitropack/commit/bba998b4364a2d04527c7ccfc364143d7b09d115)) -- **render:** don't override statusCode ([f166cfa](https://github.com/nitrojs/nitropack/commit/f166cfa612ec13eccd19a9f044781e77ef1ddc9f)) -- resolve chunksDirName based on outNames dirname (vercel) ([e82cfcc](https://github.com/nitrojs/nitropack/commit/e82cfcc5004f542ebf29897ea245262994b53e29)) -- resolve runtime provided dependencies ([3e9e27e](https://github.com/nitrojs/nitropack/commit/3e9e27efb67e4c13d27b4ff1fc5dcffa399959db)) -- **resolveMiddleware:** remove legacy handler and path props ([1de3717](https://github.com/nitrojs/nitropack/commit/1de3717b2c778ea7ff2a5e1a3945b0584dc9165f)) -- **rollup:** dirnames not generate a sourcemap for the transformation ([#83](https://github.com/nitrojs/nitropack/issues/83)) ([a8c02df](https://github.com/nitrojs/nitropack/commit/a8c02df9ced9e7f4a86742113728d5b8700d8d9b)) -- sanitize rollup-generated filenames ([#1648](https://github.com/nitrojs/nitropack/issues/1648)) ([5c49e2a](https://github.com/nitrojs/nitropack/commit/5c49e2aac3a0e325ceb13a7ca21e74574a4cf662)) -- **schema:** extend `NuxtOptions` for nitro & bridge types ([#2131](https://github.com/nitrojs/nitropack/issues/2131)) ([4d8e184](https://github.com/nitrojs/nitropack/commit/4d8e184d73cc3b8f31b66bc5be8fb5b3f7ea7b47)) -- **schema:** handle null/undefined values in `runtimeConfig` ([#2456](https://github.com/nitrojs/nitropack/issues/2456)) ([7ad2764](https://github.com/nitrojs/nitropack/commit/7ad276479a917fac2e1eeaa08a42d7d727bd66c9)) -- serve public assets in production ([2dfad65](https://github.com/nitrojs/nitropack/commit/2dfad65497ea211294a1bcadb10d80eb29ef64e0)) -- **service-worker:** check for asset urls ([aab6fbf](https://github.com/nitrojs/nitropack/commit/aab6fbf753da00d06eee1c7d2bfaef881572fd4c)) -- silent proxy errors ([63a083c](https://github.com/nitrojs/nitropack/commit/63a083c02bf9b45b5df0ccf838833a6c435790c8)) -- skip static dir if not exists ([3b87c28](https://github.com/nitrojs/nitropack/commit/3b87c28d72be042ef9f247daaba678654610b4ff)) -- small bug fixes ([26046ee](https://github.com/nitrojs/nitropack/commit/26046ee84ae787bee45a4d3ed4e40557fa074448)) -- static asset handling with leading slash ([2303c7d](https://github.com/nitrojs/nitropack/commit/2303c7d6a2dfffa193be2b6e45cc09e488be8b36)) -- static dir is in `srcDir` ([#37](https://github.com/nitrojs/nitropack/issues/37)) ([20fe1dc](https://github.com/nitrojs/nitropack/commit/20fe1dcee1cb42a0aac26b5191f5681bc6548814)) -- **storage:** replace non-word characters with underscore ([#542](https://github.com/nitrojs/nitropack/issues/542)) ([01628ae](https://github.com/nitrojs/nitropack/commit/01628ae48bfaa75380b44c433f6ce5846a4df8c6)) -- support both targets by adding prepare step ([36bfc43](https://github.com/nitrojs/nitropack/commit/36bfc43db294dfa4985aa89c6211d89184e78861)) -- temporary disable auto mock plugin ([414dfb6](https://github.com/nitrojs/nitropack/commit/414dfb6acf6f4abb09d4ad22d57dd7776455ee15)) -- temporary remove dev warning for pwa module ([#40](https://github.com/nitrojs/nitropack/issues/40)) ([e1cf8a0](https://github.com/nitrojs/nitropack/commit/e1cf8a06c3fe01036f2e70386932eb0651704936)) -- timing plugin helper import ([d9b28da](https://github.com/nitrojs/nitropack/commit/d9b28da5291def39419b044cb956b804c9ba53b6)), closes [nuxt/framework#3399](https://github.com/nuxt/framework/issues/3399) -- **timing:** include helpers only in entries ([fe5a33e](https://github.com/nitrojs/nitropack/commit/fe5a33e1605464da63edf5d45d944cbe795aec71)) -- update `service-worker` preset ([ce3aaf6](https://github.com/nitrojs/nitropack/commit/ce3aaf6d7caab4f8797a5e435372719ecbe82dc9)) -- update changed mw.path => route ([359a959](https://github.com/nitrojs/nitropack/commit/359a959725719f65f3e9978052be9ea4b9cdaa93)) -- update documentPath with updated buildDir ([#70](https://github.com/nitrojs/nitropack/issues/70)) ([25fa3eb](https://github.com/nitrojs/nitropack/commit/25fa3ebb3eb8b8a54b9a12cd621353949e749d54)) -- update h3 for static asset handling ([2861c61](https://github.com/nitrojs/nitropack/commit/2861c61f333d07fd5028425c9366f228089b2e66)) -- update node-resolve options ([e33b658](https://github.com/nitrojs/nitropack/commit/e33b6582b38e4d1adcd1be4e5fccccb09a5d9a0b)) -- update runtime/config ([b979f74](https://github.com/nitrojs/nitropack/commit/b979f748878d89b9452555561451d7d2bf701b5d)) -- update service-worker entry ([5874d01](https://github.com/nitrojs/nitropack/commit/5874d01c830086862ed557d43bebd0c10c3378d1)) -- use `globalThis` instead of `global` ([#59](https://github.com/nitrojs/nitropack/issues/59)) ([fb56216](https://github.com/nitrojs/nitropack/commit/fb56216d3e8c193f561ad4345ce436a5cb9f34c9)) -- use `perfect-debounce` ([#22](https://github.com/nitrojs/nitropack/issues/22)) ([5642e0d](https://github.com/nitrojs/nitropack/commit/5642e0d8660934c1665bc02b7acf89e9588f66a1)) -- use allowlist approach to chunk name ([#101](https://github.com/nitrojs/nitropack/issues/101)) ([42f2269](https://github.com/nitrojs/nitropack/commit/42f226966265473cce5452f6a79ed42d3479825b)), closes [#93](https://github.com/nitrojs/nitropack/issues/93) -- use connect for dev server due to loading-screen issue ([67d78c8](https://github.com/nitrojs/nitropack/commit/67d78c87a5acbba483aa034fee3e2d296b179e09)) -- use devalue to handle runtime config ([#28](https://github.com/nitrojs/nitropack/issues/28)) ([2522178](https://github.com/nitrojs/nitropack/commit/2522178f9ced253337fc8545212e666aa7f455ea)) -- use dist for netlify as default ([d4d5285](https://github.com/nitrojs/nitropack/commit/d4d52859792168dea2796d96e2638f7db44941f9)) -- use globalThis for client plugin ([34dbae8](https://github.com/nitrojs/nitropack/commit/34dbae8391071819117852356ffb7ee6388b60c9)) -- use html.contents ([97d0ebe](https://github.com/nitrojs/nitropack/commit/97d0ebe1e75b4a4864681c38f59c1f0cb0a6d840)) -- use native fetch when node is disabled ([4271c65](https://github.com/nitrojs/nitropack/commit/4271c6522cca80e9c067be26e025fec4f570113a)) -- use nitro plugin with explicit mjs extension ([78135ac](https://github.com/nitrojs/nitropack/commit/78135acc4336e38f3d07f66a33f62f5a06a702ba)) -- use output/public for prerenderer ([70c0866](https://github.com/nitrojs/nitropack/commit/70c086650b3f1e14562c6f0814f55e5001a96113)) -- use same global to inject process.hrtime ([0303912](https://github.com/nitrojs/nitropack/commit/030391290e1a9c9c6338a06883f14a1d3362d213)) -- use types dir for now ([#29](https://github.com/nitrojs/nitropack/issues/29)) ([2f27572](https://github.com/nitrojs/nitropack/commit/2f2757228e0a55bffb96fa22d00ffefe2dc1a60c)) -- **vercel:** add `/index` suffix to dst ([601b413](https://github.com/nitrojs/nitropack/commit/601b41312ce8fe2d82b53c8f0a9ba400aea3eea9)) -- **vercel:** add api prefix ([1fc0d9a](https://github.com/nitrojs/nitropack/commit/1fc0d9a55e95278a698305b99953050b0ceedc58)) -- **vercel:** add missing node segment ([b68b4c9](https://github.com/nitrojs/nitropack/commit/b68b4c931ba8fc73a5bc1e80debbe03a46a42586)) -- **vercel:** entry should export handle as default ([c8b1346](https://github.com/nitrojs/nitropack/commit/c8b13463b8ef7b8e41648b45b0fc28a05673e48a)) -- **vercel:** generate to config/routes.json ([f9e35f6](https://github.com/nitrojs/nitropack/commit/f9e35f686b7b37256bb2f41132f7ae6f27eba97d)) -- **vercel:** remove index.js from serverDir ([9ba1281](https://github.com/nitrojs/nitropack/commit/9ba1281d573f7965b4de48d9c86327dc3aa4325f)) -- **vite:** don't copy `publicDir` files to `_nuxt` ([#2135](https://github.com/nitrojs/nitropack/issues/2135)) ([98f86e3](https://github.com/nitrojs/nitropack/commit/98f86e344f90ea45bfe292c418641dc931930543)) -- **webpack:** use cjs for emitted webpack files ([#395](https://github.com/nitrojs/nitropack/issues/395)) ([aed8092](https://github.com/nitrojs/nitropack/commit/aed8092777feb85a406756b79f50407b4e6b21de)) -- windows path issues ([#408](https://github.com/nitrojs/nitropack/issues/408)) ([4f118b6](https://github.com/nitrojs/nitropack/commit/4f118b62511d16287893b14bd4fbc5fd4e3f8db7)) -- workaround for `vue` 3.2.18+ esm bundle issue and revert [#566](https://github.com/nitrojs/nitropack/issues/566) ([#578](https://github.com/nitrojs/nitropack/issues/578)) ([#578](https://github.com/nitrojs/nitropack/issues/578)) ([e60d22a](https://github.com/nitrojs/nitropack/commit/e60d22aa75a3dbde75a773fae6f037baa783f474)) -- **worker:** smaller and working hrtime polyfill ([2f60ea4](https://github.com/nitrojs/nitropack/commit/2f60ea4ec49b7acd5929eef4caf6e30ac4a6e1ad)) -- **worker:** wrap polyfill to iife ([3049212](https://github.com/nitrojs/nitropack/commit/3049212de55a296828b40d6670f6a512fe8c7271)) - -- expose `nitroApp` to entries ([4aa955f](https://github.com/nitrojs/nitropack/commit/4aa955f44d06d99c2790046f4b8f5d3ffc5ed6b6)) -- simplify storage options ([cffb900](https://github.com/nitrojs/nitropack/commit/cffb90089834b65acbe8b8957a3b6a7631318d62)) -- use `app.baseURL` runtime config for framework agnostic usage ([59196a6](https://github.com/nitrojs/nitropack/commit/59196a65266c227ce7a4cb6fa005eebe8cbfdaae)) diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000000..43c994c2d3 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..d6d79fbbaf --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +CODE_OF_CONDUCT.md. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..e6292d1237 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,65 @@ +# Contribution Guide + + + +> All contributors lead the growth of Nitro - including you! + +## Discussions + +You can involve in discussions using: + +- [GitHub Discussions](discussions) +- [Nitro Discord](https://discord.nitro.build) + +## Contribute to the Code + +> [!IMPORTANT] +> Please discuss your ideas with the maintainers before opening a pull request. + +### Local Development + +- Clone the [`nitrojs/nitro`](https://github.com/nitrojs/nitro) git repository. +- Install the latest LTS version of [Node.js](https://nodejs.org/en/) (v22+). +- Enable [corepack](https://github.com/nodejs/corepack) using `corepack enable` (run `npm i -g corepack` if it's not available). +- Install dependencies using `pnpm install`. +- Build the project in stub mode using `pnpm build --stub`. +- Run the playground with `pnpm nitro dev ./playground` to verify changes. +- Add, modify, and run tests using `pnpm test`. + - Tip: Run `pnpm vitest test/presets/node.test.ts` for quick testing. + +## Reporting Issues + +You might encounter a bug while using Nitro. + +Although we aim to resolve all known issues, new bugs can emerge over time. Your bug report helps us find and fix them faster — even if you're unable to fix the underlying code yourself. + +Here’s how to report a bug effectively: + +### Ensure It's a Bug + +Sometimes what seems like a bug may actually be expected behavior or a missing feature. Make sure you’re reporting an actual bug by creating a minimal nitro project and reducing scope. + +### Create a Minimal Reproduction + +Please create a minimal reproduction using the Nitro starter templates. + +Sometimes, bugs originate from another layer — not Nitro itself. A minimal reproduction helps identify the source and speeds up debugging. + +Use one of the following templates to reproduce the issue: + +- [Stackblitz Template](https://stackblitz.com/fork/github/nitrojs/starter) +- [Nitro Starter Repo](https://github.com/nitrojs/starter) + +If your bug involves a higher-level framework like [Nuxt](https://nuxt.com), please report it there. Maintainers will help narrow it down to a Nitro-level issue if needed. + +### Search Existing Issues and Discussions + +Before creating a new issue, search existing [issues](https://github.com/nitrojs/nitro/issues) and [discussions](https://github.com/nitrojs/nitro/discussions) to see if your bug has already been reported. + +If it has already been reported: +- Add a 👍 reaction to the original post (instead of commenting "me too" or "when will it be fixed"). +- If you can provide additional context or a better/smaller reproduction, please share it. + +> [!NOTE] +> If the issue seems related but different or old or already closed, it's **better to open a new issue**. Maintainers will merge similar issues if needed. + diff --git a/LICENSE b/LICENSE index 126076e30b..137e558965 100644 --- a/LICENSE +++ b/LICENSE @@ -19,3 +19,9 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +## Third-Party Licenses + +This software includes bundled third-party dependencies. The licenses and +copyright notices for these dependencies are available in +`dist/THIRD-PARTY-LICENSES.md` within the distributed package. diff --git a/README.md b/README.md index b933499140..0a039be656 100644 --- a/README.md +++ b/README.md @@ -1,49 +1,20 @@ -# Nitro - - - -[![npm version](https://flat.badgen.net/npm/v/nitropack)](https://npmjs.com/package/nitropack) -[![npm downloads](https://flat.badgen.net/npm/dm/nitropack)](https://npmjs.com/package/nitropack) +[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/nitrojs/nitro) - - -Create web servers that run anywhere! 📖 [**documentation**](https://nitro.build) +# Nitro > [!NOTE] -> You are on the v2 branch. Check [main branch](https://github.com/nitrojs/nitro/tree/main) for v3 development tree. - -## Contribution +> You’re viewing the **v3** branch. +> For the current stable release, see [Nitro v2](https://github.com/nitrojs/nitro/tree/v2). -
- Local development +**Nitro** extends your Vite app with a **production-ready server**, designed to run **anywhere**. +Add server routes, deploy across multiple platforms, and enjoy a **zero-config** experience. -- Clone this repository -- Install the latest LTS version of [Node.js](https://nodejs.org/en/) -- Enable [Corepack](https://github.com/nodejs/corepack) using `corepack enable` -- Install dependencies using `pnpm install` -- Run tests using `pnpm dev` or `pnpm test` +📘 **Docs:** [https://nitro.build](https://nitro.build) -
+## Contributing - +See Check out the [Contribution Guide](./CONTRIBUTING.md) to get started. ## License - - -Published under the [MIT](https://github.com/nitrojs/nitro/blob/main/LICENSE) license. -Made by [@pi0](https://github.com/pi0) and [community](https://github.com/nitrojs/nitro/graphs/contributors) 💛 -

- - - - - - - - ---- - -_🤖 auto updated with [automd](https://automd.unjs.io)_ - - +Released under the [MIT License](LICENSE). diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index a6039a2884..0000000000 --- a/SECURITY.md +++ /dev/null @@ -1,9 +0,0 @@ -# Security Policy - -## ⚠️ Reporting a Vulnerability - -To report a vulnerability, please send an email to [security+nitro@unjs.io](mailto:security+nitro@unjs.io) or submit it for a bounty via [Huntr](https://huntr.dev/bounties/disclose/?target=https://github.com/nitrojs/nitro). - -All security vulnerabilities will be promptly verified and addressed. - -We recommend to regularly upgrade and publish with the latest versions of used packages and sub-dependencies by maintaining lock files (`yarn.lock`, `package-lock.json` and `pnpm-lock.yaml`) in order to ensure your application remains as secure as possible. diff --git a/automd.config.ts b/automd.config.ts new file mode 100644 index 0000000000..348d03c44f --- /dev/null +++ b/automd.config.ts @@ -0,0 +1,258 @@ +import type { Config } from "automd"; +import { readdir, stat, readFile } from "node:fs/promises"; +import { join, extname, relative } from "pathe"; + +interface FileEntry { + path: string; + relativePath: string; + content: string; + language: string; +} + +const DEFAULT_IGNORE = [ + "node_modules", + ".git", + ".DS_Store", + ".nuxt", + ".output", + ".nitro", + "dist", + "coverage", + ".cache", + ".turbo", + "pnpm-lock.yaml", + "package-lock.json", + "yarn.lock", +]; + +const EXTENSION_LANGUAGE_MAP: Record = { + ".ts": "ts", + ".tsx": "tsx", + ".js": "js", + ".jsx": "jsx", + ".mjs": "js", + ".cjs": "js", + ".vue": "vue", + ".json": "json", + ".html": "html", + ".css": "css", + ".scss": "scss", + ".md": "md", + ".yaml": "yaml", + ".yml": "yaml", + ".toml": "toml", + ".sh": "bash", + ".bash": "bash", + ".zsh": "bash", +}; + +async function parseGitignore(dir: string): Promise { + try { + const gitignorePath = join(dir, ".gitignore"); + const content = await readFile(gitignorePath, "utf8"); + return content + .split("\n") + .map((line) => line.trim()) + .filter((line) => line && !line.startsWith("#")); + } catch { + return []; + } +} + +function shouldIgnore(name: string, ignorePatterns: string[], defaultIgnore: string[]): boolean { + const allPatterns = [...defaultIgnore, ...ignorePatterns]; + for (const pattern of allPatterns) { + const cleanPattern = pattern.replace(/^\//, "").replace(/\/$/, ""); + if (name === cleanPattern) { + return true; + } + if (pattern.startsWith("*") && name.endsWith(pattern.slice(1))) { + return true; + } + if (pattern.endsWith("*") && name.startsWith(pattern.slice(0, -1))) { + return true; + } + } + return false; +} + +function getLanguage(filePath: string): string { + const ext = extname(filePath).toLowerCase(); + return EXTENSION_LANGUAGE_MAP[ext] || "text"; +} + +async function collectFiles( + dir: string, + baseDir: string, + ignorePatterns: string[], + maxDepth: number, + currentDepth: number = 0 +): Promise { + if (maxDepth > 0 && currentDepth >= maxDepth) { + return []; + } + + const entries = await readdir(dir); + const files: FileEntry[] = []; + + for (const entry of entries) { + if (shouldIgnore(entry, ignorePatterns, DEFAULT_IGNORE)) { + continue; + } + + const fullPath = join(dir, entry); + const stats = await stat(fullPath); + + if (stats.isDirectory()) { + const nestedFiles = await collectFiles( + fullPath, + baseDir, + ignorePatterns, + maxDepth, + currentDepth + 1 + ); + files.push(...nestedFiles); + } else { + try { + const content = await readFile(fullPath, "utf8"); + const relativePath = relative(baseDir, fullPath); + files.push({ + path: fullPath, + relativePath, + content: content.trim(), + language: getLanguage(fullPath), + }); + } catch { + // Skip binary or unreadable files + } + } + } + + return files; +} + +function sortFiles(files: FileEntry[]): FileEntry[] { + return files.sort((a, b) => { + const aParts = a.relativePath.split("/"); + const bParts = b.relativePath.split("/"); + + // Sort by depth first (shallower files first) + if (aParts.length !== bParts.length) { + return aParts.length - bParts.length; + } + + // Then alphabetically + return a.relativePath.localeCompare(b.relativePath); + }); +} + +function generateCodeTree( + files: FileEntry[], + options: { defaultValue?: string; expandAll?: boolean } = {} +): string { + const sortedFiles = sortFiles(files); + const codeBlocks: string[] = []; + + for (const file of sortedFiles) { + const lang = file.language; + const filename = file.relativePath; + + // Use 4 backticks for markdown files to avoid conflicts + const fence = lang === "md" ? "````" : "```"; + codeBlocks.push(`${fence}${lang} [${filename}]`); + codeBlocks.push(file.content); + codeBlocks.push(fence); + codeBlocks.push(""); + } + + const attrs: string[] = []; + if (options.defaultValue) { + attrs.push(`defaultValue="${options.defaultValue}"`); + } + if (options.expandAll) { + attrs.push(`expandAll`); + } + const propsStr = attrs.length > 0 ? `{${attrs.join(" ")}}` : ""; + const contents = `::code-tree${propsStr}\n\n${codeBlocks.join("\n").trim()}\n\n::`; + + return contents; +} + +function resolvePath(srcPath: string, options: { url?: string; dir?: string }): string { + if (srcPath.startsWith("/")) { + return srcPath; + } + const base = options.url ? new URL(".", options.url).pathname : options.dir || process.cwd(); + return join(base, srcPath); +} + +export default { + input: ["README.md", "docs/**/*.md"], + generators: { + compatDate: { + name: "compatDate", + async generate(ctx) { + // const { compatibilityChanges } = await import("./lib/meta.mjs"); + + // const table = [ + // "| Compatibility date | Platform | Description |", + // "|------|----------|-------------|", + // ...compatibilityChanges.map( + // (change) => + // `| **≥ ${change.from}** | ${change.platform} | ${change.description} |` + // ), + // ]; + return { + // contents: table.join("\n"), + contents: "", + }; + }, + }, + "ui-code-tree": { + name: "ui-code-tree", + async generate({ + args, + config, + url, + }: { + args: Record; + config: { dir?: string }; + url?: string; + }) { + const srcPath = (args.src as string) || "."; + const fullPath = resolvePath(srcPath, { url, dir: config.dir }); + + const stats = await stat(fullPath); + if (!stats.isDirectory()) { + throw new Error(`Path "${srcPath}" is not a directory`); + } + + const userIgnore: string[] = args.ignore + ? String(args.ignore) + .split(",") + .map((s: string) => s.trim()) + : []; + + const gitignorePatterns = await parseGitignore(fullPath); + const ignorePatterns = [...gitignorePatterns, ...userIgnore, "README.md", ".*"]; + + const maxDepth = args.maxDepth ? Number(args.maxDepth) : 0; + const defaultValue = (args.defaultValue || args.default) as string | undefined; + const expandAll = args.expandAll !== undefined && args.expandAll !== "false"; + + const files = await collectFiles(fullPath, fullPath, ignorePatterns, maxDepth); + + if (files.length === 0) { + return { + contents: "", + issues: ["No files found in the specified directory"], + }; + } + + const contents = generateCodeTree(files, { defaultValue, expandAll }); + + return { contents }; + }, + }, + }, +} satisfies Config; diff --git a/build.config.ts b/build.config.ts index ab674c0759..77c45ed07e 100644 --- a/build.config.ts +++ b/build.config.ts @@ -1,88 +1,188 @@ -import { writeFile } from "node:fs/promises"; -import { fileURLToPath } from "node:url"; -import { resolve } from "pathe"; -import { normalize } from "pathe"; -import { defineBuildConfig } from "unbuild"; +import { defineBuildConfig } from "obuild/config"; -const srcDir = fileURLToPath(new URL("src", import.meta.url)); +import { resolveModulePath } from "exsolve"; +import { traceNodeModules } from "nf3"; +import { mkdir, readFile, rmdir, writeFile } from "node:fs/promises"; +import type { CodeSplittingOptions } from "rolldown"; -export const subpaths = [ - "cli", - "config", - "core", - "kit", - "presets", - "rollup", - "runtime", - "meta", - "types", +const isStub = process.argv.includes("--stub"); + +const pkg = await import("./package.json", { with: { type: "json" } }).then((r) => r.default || r); + +const tracePkgs = [ + "cookie-es", // used by azure runtime + "croner", // used by internal/task + "defu", // used by open-api runtime + "destr", // used by node-server and deno-server + "get-port-please", // used by dev server + "rendu", // used by HTML renderer template + "scule", // used by runtime config + "source-map", // used by dev error runtime + "ufo", // used by presets and runtime + "unctx", // used by internal/context + "youch", // used by error handler + "youch-core", // used by error handler ]; export default defineBuildConfig({ - declaration: true, - name: "nitro", entries: [ - // CLI - { input: "src/cli/index.ts" }, - // Config - { input: "src/config/index.ts" }, - // Core - { input: "src/core/index.ts" }, - // Runtime - { input: "src/runtime/", outDir: "dist/runtime", format: "esm" }, - // Kit - { input: "src/kit/index.ts" }, - // Meta - { input: "src/meta/index.ts" }, - // Presets - { input: "src/presets/", outDir: "dist/presets", format: "esm" }, - // Rollup - { input: "src/rollup/index.ts" }, - // Types - { input: "src/types/index.ts" }, + { + type: "bundle", + input: ["src/builder.ts", "src/cli/index.ts", "src/types/index.ts", "src/vite.ts"], + }, + { + type: "transform", + input: "src/runtime/", + outDir: "dist/runtime", + }, + { + type: "transform", + input: "src/presets/", + outDir: "dist/presets", + filter: (id) => id.includes("runtime/"), + dts: false, + }, ], hooks: { - async "build:prepare"(ctx) { - for (const subpath of subpaths) { - await writeFile( - `./${subpath}.d.ts`, - `export * from "./dist/${subpath}/index";` - ); - } + rolldownConfig(config) { + config.platform = "node"; + + config.resolve ??= {}; + config.resolve.alias ??= {}; + Object.assign(config.resolve.alias, { + "node-fetch-native/proxy": "node-fetch-native/native", + "node-fetch-native": "node-fetch-native/native", + }); + + config.external ??= []; + (config.external as string[]).push( + "nitro", + ...Object.keys(pkg.exports || {}).map((key) => key.replace(/^./, "nitro")), + ...Object.keys(pkg.dependencies), + ...Object.keys(pkg.peerDependencies), + ...tracePkgs, + "typescript", + "firebase-functions", + "@scalar/api-reference", + "get-port-please", + "cloudflare:workers", + "@cloudflare/workers-types", + // unplugin deps + "@rspack/core", + "@farmfe/core", + "webpack", + "unloader" + ); }, - }, - externals: [ - "nitro", - "nitropack", - "nitropack/runtime/meta", - ...subpaths.map((subpath) => `nitropack/${subpath}`), - "firebase-functions", - "@scalar/api-reference", - ], - stubOptions: { - jiti: { - alias: { - nitropack: "nitropack", - "nitropack/meta": resolve(srcDir, "../meta.ts"), - "nitropack/runtime/meta": resolve(srcDir, "../runtime-meta.mjs"), - ...Object.fromEntries( - subpaths.map((subpath) => [ - `nitropack/${subpath}`, - resolve(srcDir, `${subpath}/index.ts`), - ]) - ), - }, + rolldownOutput(config) { + (config.codeSplitting as CodeSplittingOptions).groups?.unshift( + { + test: /src[/\\]build[/\\](plugins|virtual|\w+\.ts)/, + name: "_build/common", + }, + { test: /src[/\\](utils)[/\\]/, name: "_chunks/utils" } + ); + config.chunkFileNames = (chunk) => { + if (chunk.name.startsWith("_")) { + return `[name].mjs`; + } + if (chunk.name === "rolldown-runtime") { + return `_common.mjs`; + } + if (chunk.moduleIds.every((id) => id.includes("node_modules"))) { + const pkgNames = [ + ...new Set( + chunk.moduleIds + .map( + (id) => + id.match(/.*[/\\]node_modules[/\\](?@[^/\\]+[/\\][^/\\]+|[^/\\]+)/) + ?.groups?.package + ) + .filter(Boolean) + .map((name) => name!.split(/[/\\]/).pop()!) + .filter(Boolean) + ), + ].sort((a, b) => a.length - b.length); + let chunkName = ""; + for (const name of pkgNames) { + const separator = chunkName ? "+" : ""; + if ((chunkName + separator + name).length > 30) { + break; + } + chunkName += separator + name; + } + return `_libs/${chunkName || "_"}.mjs`; + } + if (chunk.moduleIds.every((id) => /src[/\\]cli[/\\]/.test(id))) { + return `cli/_chunks/[name].mjs`; + } + if (chunk.moduleIds.every((id) => /build[/\\]vite[/\\]/.test(id))) { + return `_build/vite.[name].mjs`; + } + if (chunk.moduleIds.every((id) => /build[/\\]rolldown[/\\]/.test(id))) { + return `_build/rolldown.mjs`; + } + if (chunk.moduleIds.every((id) => /build[/\\]rollup[/\\]|build[/\\]plugins/.test(id))) { + return `_build/rollup.mjs`; + } + if (chunk.moduleIds.every((id) => /src[/\\]dev[/\\]|src[/\\]runtime/.test(id))) { + return `_dev.mjs`; + } + if (chunk.moduleIds.every((id) => /src[/\\]presets/.test(id))) { + return `_presets.mjs`; + } + if ( + chunk.moduleIds.every((id) => /src[/\\]build[/\\]|src[/\\]presets|src[/\\]utils/.test(id)) + ) { + return `_build/shared.mjs`; + } + if (chunk.moduleIds.every((id) => /src[/\\](runner|dev|runtime)/.test(id))) { + return `_chunks/dev.mjs`; + } + return "_chunks/nitro.mjs"; + }; }, - }, - rollup: { - output: { - chunkFileNames(chunk: any) { - const id = normalize(chunk.moduleIds.at(-1)); - if (id.includes("/src/cli/")) { - return "cli/[name].mjs"; + async end() { + if (isStub) { + return; + } + + // Bundle docs + const { DocsManager, DocsSourceFS, exportDocsToFS } = await import("mdzilla"); + const man = new DocsManager(new DocsSourceFS("./docs")); + await man.load(); + await rmdir("./skills/nitro/docs").catch(() => {}); + await mkdir("./skills/nitro/docs", { recursive: true }); + await exportDocsToFS(man, "./skills/nitro/docs", { + title: "Nitro Documentation", + tocFile: "TOC.md", + filter: (e: { entry: { path: string } }) => !e.entry.path.startsWith("/blog"), + }); + + // Trace included dependencies + await traceNodeModules( + tracePkgs.map((pkg) => resolveModulePath(pkg)), + { + hooks: { + tracedPackages(packages) { + // Avoid tracing direct dependencies + const deps = new Set([ + ...Object.keys(pkg.dependencies), + ...Object.keys(pkg.peerDependencies), + ]); + for (const dep of deps) { + delete packages[dep]; + } + }, + }, } - return "_chunks/[name].mjs"; - }, + ); + + // Vite types + await writeFile( + "dist/vite.d.mts", + `import "vite/client";\nimport "nitro/vite/types";\n${await readFile("dist/vite.d.mts", "utf8")}` + ); }, }, }); diff --git a/changelog.config.ts b/changelog.config.ts new file mode 100644 index 0000000000..a0f34194ba --- /dev/null +++ b/changelog.config.ts @@ -0,0 +1,8 @@ +import type { ChangelogConfig } from "changelogen"; + +export default { + output: false, + types: { + presets: { title: "Preset Changes", semver: "patch" }, + }, +} satisfies Partial; diff --git a/docs/.config/automd.config.ts b/docs/.config/automd.config.ts new file mode 100644 index 0000000000..c0d39c8b64 --- /dev/null +++ b/docs/.config/automd.config.ts @@ -0,0 +1 @@ +export { default } from "../../automd.config"; diff --git a/docs/.config/docs.yaml b/docs/.config/docs.yaml index 15e0bb909a..91cd8f9b16 100644 --- a/docs/.config/docs.yaml +++ b/docs/.config/docs.yaml @@ -1,55 +1,43 @@ # yaml-language-server: $schema=https://unpkg.com/undocs/schema/config.json name: Nitro -shortDescription: Next Generation Server Toolkit -description: Create web servers with everything you need and deploy them wherever you prefer. +shortDescription: Ship Full-stack Vite Apps +description: Add server API routes to any Vite apps and deploy with zero configuration on your favorite hosting platform. github: nitrojs/nitro url: https://nitro.build -themeColor: "red" -automd: true +socials: + x: "https://x.com/nitrojsdev" + bluesky: "https://bsky.app/profile/nitro.build" + discord: https://discord.nitro.build +sponsors: + api: https://sponsors.pi0.io/sponsors.json redirects: - /deploy/node: /deploy/runtimes/node -landing: - heroLinks: - playOnline: - label: "Play Online" - icon: "i-simple-icons-lightning" - to: "https://stackblitz.com/github/nitrojs/nitro/tree/main/examples/hello-world" - contributors: true - featuresTitle: "A Server for the Modern Web" - features: - - title: "Rapid Development" - description: "Zero config setup with hot module replacement for server code in development." - icon: "🐇" - - title: "Deploy Anywhere" - description: "Deploy the same codebase to any [deployment provider](/deploy) with no extra config." - icon: "😌" - - title: "Portable and Compact" - description: "Say goodbye to `node_modules`, output size is less than 1MB." - icon: "💼" - - title: "Filesystem Routing" - description: "[Automatically registers](/guide/routing) server and API routes." - icon: "📁" - - title: "Minimal Design" - description: "Minimal design to fit into any solution with minimum overhead" - icon: "🤏" - - title: "Code-Splitting" - description: "Async chunk loading for fast server startup time and answer." - icon: "🚀" - - title: "TypeScript" - description: "TypeScript support out of the box with few more goodies." - icon: "👕" - - title: "Storage Layer" - description: "Multi driver and platform-agnostic storage system." - icon: "💾" - - title: "Cache API" - description: "Powerful built-in caching API." - icon: "💰" - - title: "Hackable" - description: "Built to be customized with the [plugins](/guide/plugins) hooks system." - icon: "🐱" - - title: "Auto Imports" - description: "Automatically import utilities for a minimal and clean codebase. Only the used ones will be added to the final bundle." - icon: "✨" - - title: "Backward Compatible" - description: "So you can use legacy npm packages, CommonJS and mocking Node.js modules for workers." - icon: "🏛️" + # v2 guide → v3 docs + "/guide": "/docs" + "/guide/getting-started": "/docs" + "/guide/utils": "/docs/routing" + "/guide/routing": "/docs/routing" + "/guide/websocket": "/docs/routing" + "/guide/cache": "/docs/cache" + "/guide/storage": "/docs/storage" + "/guide/database": "/docs/database" + "/guide/fetch": "/docs/routing" + "/guide/assets": "/docs/assets" + "/guide/plugins": "/docs/plugins" + "/guide/configuration": "/docs/configuration" + "/guide/typescript": "/docs/configuration" + "/guide/tasks": "/docs/tasks" + "/guide/nightly": "/docs/nightly" + # v2 deploy + "/deploy/workers": "/deploy" + "/deploy/runtimes/winterjs": "/deploy" + "/deploy/custom-presets": "/deploy" + "/deploy/providers/edgio": "/deploy" + "/deploy/node": "/deploy/runtimes/node" +themeColor: "rose" +automd: true +branch: main +versions: + - label: "v3 (beta)" + active: true + - label: "v2 (legacy)" + to: "https://v2.nitro.build" diff --git a/docs/.docs/app.config.ts b/docs/.docs/app.config.ts new file mode 100644 index 0000000000..46663cea38 --- /dev/null +++ b/docs/.docs/app.config.ts @@ -0,0 +1,11 @@ +import { defineAppConfig } from "#imports" + +export default defineAppConfig({ + ui: { + button: { + slots: { + base: 'active:translate-y-px transition-transform duration-300', + }, + }, + }, +}) diff --git a/docs/.docs/assets/css/main.css b/docs/.docs/assets/css/main.css new file mode 100644 index 0000000000..652f92f4e9 --- /dev/null +++ b/docs/.docs/assets/css/main.css @@ -0,0 +1,23 @@ +:root { + --font-sans: "Geist", sans-serif !important; + --font-mono: "Geist Mono", monospace !important; +} + +h1[data-slot="title"] { + font-family: "Geist Pixels", sans-serif !important; +} + +.landing-code { + --ui-bg-muted: #0c0c0e; + --ui-border-muted: #27272a; + --ui-bg: #0c0c0e; +} + +.landing-code pre[style] { + background-color: #0c0c0e !important; +} + +.landing-code > div > div { + margin-top: 0; + margin-bottom: 0; +} diff --git a/docs/.docs/assets/fonts/GeistPixel-Square.woff2 b/docs/.docs/assets/fonts/GeistPixel-Square.woff2 new file mode 100644 index 0000000000..232cae2c11 Binary files /dev/null and b/docs/.docs/assets/fonts/GeistPixel-Square.woff2 differ diff --git a/docs/.docs/components/AppHero.vue b/docs/.docs/components/AppHero.vue new file mode 100644 index 0000000000..006c0329e8 --- /dev/null +++ b/docs/.docs/components/AppHero.vue @@ -0,0 +1,62 @@ + + + diff --git a/docs/.docs/components/AppHeroLinks.vue b/docs/.docs/components/AppHeroLinks.vue new file mode 100644 index 0000000000..e8f3d60f6b --- /dev/null +++ b/docs/.docs/components/AppHeroLinks.vue @@ -0,0 +1,49 @@ + + + diff --git a/docs/.docs/components/FeatureCard.vue b/docs/.docs/components/FeatureCard.vue new file mode 100644 index 0000000000..17838c7dcd --- /dev/null +++ b/docs/.docs/components/FeatureCard.vue @@ -0,0 +1,51 @@ + + + diff --git a/docs/.docs/components/HeroBackground.client.vue b/docs/.docs/components/HeroBackground.client.vue new file mode 100644 index 0000000000..dbd575e36d --- /dev/null +++ b/docs/.docs/components/HeroBackground.client.vue @@ -0,0 +1,31 @@ + + + diff --git a/docs/.docs/components/HeroFeatures.vue b/docs/.docs/components/HeroFeatures.vue new file mode 100644 index 0000000000..944a0528b7 --- /dev/null +++ b/docs/.docs/components/HeroFeatures.vue @@ -0,0 +1,75 @@ + + + diff --git a/docs/.docs/components/LandingFeatures.vue b/docs/.docs/components/LandingFeatures.vue new file mode 100644 index 0000000000..43f61ec45d --- /dev/null +++ b/docs/.docs/components/LandingFeatures.vue @@ -0,0 +1,21 @@ + + + diff --git a/docs/.docs/components/PerformanceShowcase.vue b/docs/.docs/components/PerformanceShowcase.vue new file mode 100644 index 0000000000..b0fb95bb10 --- /dev/null +++ b/docs/.docs/components/PerformanceShowcase.vue @@ -0,0 +1,84 @@ + + + diff --git a/docs/.docs/layouts/examples.vue b/docs/.docs/layouts/examples.vue new file mode 100644 index 0000000000..021ff828ad --- /dev/null +++ b/docs/.docs/layouts/examples.vue @@ -0,0 +1,86 @@ + + + diff --git a/docs/.docs/nuxt.config.ts b/docs/.docs/nuxt.config.ts new file mode 100644 index 0000000000..ff27429974 --- /dev/null +++ b/docs/.docs/nuxt.config.ts @@ -0,0 +1,13 @@ +import { defineNuxtConfig } from "nuxt/config" + +export default defineNuxtConfig({ + modules: ['motion-v/nuxt'], + css: ['~/assets/css/main.css'], + fonts: { + families: [ + { name: 'Geist', weights: [400, 600, 700], global: true }, + { name: 'Geist Mono', weights: [400, 600], global: true }, + { name: "Geist Pixels", src: "/assets/fonts/GeistPixel-Square.woff2", weight: 500, global: true }, + ], + }, +}) diff --git a/docs/.docs/pages/examples/[...slug].vue b/docs/.docs/pages/examples/[...slug].vue new file mode 100644 index 0000000000..9e4d74c34c --- /dev/null +++ b/docs/.docs/pages/examples/[...slug].vue @@ -0,0 +1,110 @@ + + + diff --git a/docs/.docs/pages/examples/index.vue b/docs/.docs/pages/examples/index.vue new file mode 100644 index 0000000000..2bb69ce728 --- /dev/null +++ b/docs/.docs/pages/examples/index.vue @@ -0,0 +1,88 @@ + + + diff --git a/docs/.docs/pages/index.vue b/docs/.docs/pages/index.vue new file mode 100644 index 0000000000..1429164062 --- /dev/null +++ b/docs/.docs/pages/index.vue @@ -0,0 +1,22 @@ + + + diff --git a/docs/.docs/public/icon.svg b/docs/.docs/public/icon.svg index e5564f27bf..d6450f9467 100644 --- a/docs/.docs/public/icon.svg +++ b/docs/.docs/public/icon.svg @@ -1,5 +1,5 @@ - + = { + vite: 'i-logos-vitejs', + 'backend frameworks': 'i-lucide-puzzle', + features: 'i-lucide-sparkles', + config: 'i-lucide-settings', + integrations: 'i-lucide-plug', + 'server side rendering': 'i-lucide-server', + other: 'i-lucide-folder', +} diff --git a/docs/.npmrc b/docs/.npmrc new file mode 100644 index 0000000000..bf2e7648b0 --- /dev/null +++ b/docs/.npmrc @@ -0,0 +1 @@ +shamefully-hoist=true diff --git a/docs/1.docs/.navigation.yml b/docs/1.docs/.navigation.yml new file mode 100644 index 0000000000..5c159a9592 --- /dev/null +++ b/docs/1.docs/.navigation.yml @@ -0,0 +1 @@ +icon: i-lucide-book-open diff --git a/docs/1.docs/1.index.md b/docs/1.docs/1.index.md new file mode 100644 index 0000000000..e7adf11ec0 --- /dev/null +++ b/docs/1.docs/1.index.md @@ -0,0 +1,60 @@ +--- +icon: i-lucide-compass +--- + +# Introduction + +> Nitro is a full-stack server framework, compatible with any runtime and any deployment target. + +Nitro gives you a production-ready server with filesystem routing, code-splitting, and built-in support for storage, caching, and databases — all runtime-agnostic and deployable anywhere. + +## What is Nitro? + +Create server and API routes inside the `routes/` directory. Each file maps directly to a URL path, and Nitro handles the rest — routing, code-splitting, and optimized builds. + +You can also take full control of the server entry by creating a `server.ts` file. Nitro’s high-level, runtime-agnostic approach lets you use any HTTP library, such as [Elysia](https://elysiajs.com/), [h3](https://h3.dev), or [Hono](https://hono.dev). + +### Performance + +Nitro compiles your routes at build time, removing the need for a runtime router. Only the code required to handle each incoming request is loaded and executed. This makes it ideal for serverless hosting, with near-0ms boot time regardless of project size. + +### Deploy Anywhere + +Build your server into an optimized `.output/` folder compatible with Node.js, Bun, Deno, and many hosting platforms without any configuration — Cloudflare Workers, Netlify, Vercel, and more. Take advantage of platform features like ESR, ISR, and SWR without changing a single line of code. + +### Server-Side Rendering + +Render HTML with your favorite templating engine, or use component libraries such as React, Vue, or Svelte directly on the server. Go full universal rendering with client-side hydration. Nitro provides the foundation and a progressive approach to reach your goals. + +### Storage + +Nitro includes a runtime-agnostic key-value storage layer out of the box. It uses in-memory storage by default, but you can connect more than 20 different drivers (FS, Redis, S3, etc.), attach them to different namespaces, and swap them without changing your code. + +### Caching + +Nitro supports caching for both server routes and server functions, backed directly by the server storage (via the `cache` namespace). + +### Database + +Nitro also includes a built-in SQL database. It defaults to SQLite, but you can connect to and query more than 10 databases (Postgres, MySQL, PGLite, etc.) using the same API. + +### Meta-Framework Foundation + +Nitro can be used as the foundation for building your own meta-framework. Popular frameworks such as Nuxt, SolidStart, and TanStack Start fully or partially leverage Nitro. + +## Vite Integration + +Nitro integrates seamlessly with [Vite](https://vite.dev) as a plugin. If you’re building a frontend application with Vite, adding Nitro gives you API routes, server-side rendering, and a full production server — all built together with `vite build`. + +```ts [vite.config.ts] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ + plugins: [nitro()], +}); +``` + +With Nitro, `vite build` produces an optimized `.output/` folder containing both your frontend and backend — ready to deploy anywhere. + +Ready to give it a try? Jump into the [quick start](/docs/quick-start). diff --git a/docs/1.docs/2.quick-start.md b/docs/1.docs/2.quick-start.md new file mode 100644 index 0000000000..808cf4c89b --- /dev/null +++ b/docs/1.docs/2.quick-start.md @@ -0,0 +1,123 @@ +--- +icon: i-lucide-zap +--- + +# Quick Start + +> Start with a fresh Nitro project or adopt it in your current Vite project. + +## Try Nitro online + +Get a taste of Nitro in your browser using our playground. + +[Play with Nitro in StackBlitz](https://stackblitz.com/github/nitrojs/starter/tree/v3-vite?file=index.html,server.ts){target="_blank"} + + +## Create a Nitro project + +The fastest way to create a Nitro application is using the `create-nitro-app`. + +> [!NOTE] +> Make sure to have installed the latest LTS version of either [Node.js](https://nodejs.org/en), [Bun](https://bun.sh/), or [Deno](https://deno.com/). + +:pm-x{command="create-nitro-app"} + +
+ Preview +
+ Preview +
+ + +Follow the instructions from the CLI and you will be ready to start your development server. + +## Add to a Vite project + +You can add Nitro to any existing Vite project to get API routes, server-side rendering, and more. + +::steps{level="3"} + +### Install `nitro` and `vite` + +:pm-install{name="nitro vite"} + +### Add Nitro plugin to Vite + +Add the Nitro plugin to your `vite.config.ts`: + +```ts [vite.config.ts] {2,6} +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ + plugins: [ + nitro() + ], +}); +``` + +### Configure Nitro + +Create a `nitro.config.ts` to configure the server directory: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + serverDir: "./server", +}); +``` + +The `serverDir` option tells Nitro where to look for your server routes. In this example, all routes will be inside the `server/` directory. + +### Create an API route + +Create your first API route at `server/api/test.ts`: + +::code-tree{defaultValue="server/api/test.ts"} +```ts [server/api/test.ts] +import { defineHandler } from "nitro"; + +export default defineHandler(() => { + return { message: "Hello Nitro!" }; +}); +``` +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + serverDir: "./server", +}); +``` +```ts [vite.config.ts] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ + plugins: [nitro()], +}); +``` +:: + +The file path maps directly to the route URL — `server/api/test.ts` becomes `/api/test`. + +::tip +As an alternative to filesystem routing, you can declare routes programmatically using the `routes` config option. See [Programmatic route handlers](/docs/routing#programmatic-route-handlers) for more details. +:: + +::tip +You can return strings, JSON objects, `Response` instances, or readable streams from your handlers. See [Routing](/docs/routing) for more about dynamic routes, methods, and middleware. +:: + + +### Start the development server + +:pm-run{script="dev -- --open"} + +Your API route is now accessible at `http://localhost:3000/api/test` :sparkles: + + + + + + diff --git a/docs/1.docs/4.renderer.md b/docs/1.docs/4.renderer.md new file mode 100644 index 0000000000..7ad54c3434 --- /dev/null +++ b/docs/1.docs/4.renderer.md @@ -0,0 +1,327 @@ +--- +icon: ri:layout-masonry-line +navigation: + title: Renderer +--- + +# Nitro Renderer + +> Use a renderer to handle all unmatched routes with custom HTML or a templating system. + +The renderer is a special handler in Nitro that catches all routes that don't match any specific API or route handler. It's commonly used for server-side rendering (SSR), serving single-page applications (SPAs), or creating custom HTML responses. + +## Configuration + +The renderer is configured using the `renderer` option in your Nitro config: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + renderer: { + template: './index.html', // Path to HTML template file + handler: './renderer.ts', // Path to custom renderer handler + static: false, // Treat template as static HTML (no rendu processing) + } +}) +``` + +| Option | Type | Description | +| --- | --- | --- | +| `template` | `string` | Path to an HTML file used as the renderer template. | +| `handler` | `string` | Path to a custom renderer handler module. | +| `static` | `boolean` | When `true`, skips rendu template processing and serves the HTML as-is. Auto-detected based on template syntax when not set. | + +Set `renderer: false` in the config to explicitly disable the renderer entirely (including auto-detection of `index.html`). + +## HTML template + +### Auto-detected `index.html` + +By default, Nitro automatically looks for an `index.html` file in your project src dir. + +If found, Nitro will use it as the renderer template and serve it for all unmatched routes. + +::code-group +```html [index.html] + + + + + + My Vite + Nitro App + + +
+ + + +``` +```ts [routes/api/hello.ts] +import { defineHandler } from "nitro"; + +export default defineHandler((event) => { + return { hello: "API" }; +}); +``` +:: + +::tip +When `index.html` is detected, Nitro will automatically log in the terminal: `Using index.html as renderer template.` +:: + +With this setup: +- `/api/hello` → Handled by your API routes +- `/about`, `/contact`, etc. → Served with `index.html` + +### Custom HTML file + +You can specify a custom HTML template file using the `renderer.template` option in your Nitro configuration. + +::code-group +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + renderer: { + template: './app.html' + } +}) +``` + +```html [app.html] + + + + + Custom Template + + +
Loading...
+ + + +``` +:: + +### Static templates + +By default, Nitro auto-detects whether your HTML template contains [rendu](#hypertext-preprocessor-experimental) syntax. If it does, the template is processed dynamically on each request. If it doesn't, it's served as static HTML. + +You can override this behavior with the `static` option: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + renderer: { + template: './index.html', + static: true // Force static serving, skip template processing + } +}) +``` + +In production, static templates are inlined into the server bundle and served directly for optimal performance. + +### Hypertext Preprocessor (experimental) + +Nitro uses [rendu](https://github.com/h3js/rendu) Hypertext Preprocessor, which provides a simple and powerful way to create dynamic HTML templates with JavaScript expressions. + +#### Output expressions + +- `{{ expression }}` — HTML-escaped output +- `{{{ expression }}}` or `` — raw (unescaped) output + +```html +

Hello {{ $URL.pathname }}

+
{{{ 'raw html' }}}
+``` + +#### Control flow + +Use `` for JavaScript control flow: + +```html + +

Form submitted!

+ +
+ +
+ + +
    + +
  • {{ item }}
  • + +
+``` + +#### Server scripts + +Use ` +
{{ JSON.stringify(data) }}
+``` + +#### Streaming content + +Use the `echo()` function for streaming content. It accepts strings, functions, Promises, Response objects, or ReadableStreams: + +```html + +``` + +#### Global variables + +Access request context within templates: + +| Variable | Description | +| --- | --- | +| `$REQUEST` | The incoming `Request` object | +| `$METHOD` | HTTP method (`GET`, `POST`, etc.) | +| `$URL` | Request `URL` object | +| `$HEADERS` | Request headers | +| `$RESPONSE` | Response configuration object | +| `$COOKIES` | Read-only object containing request cookies | + +#### Built-in functions + +| Function | Description | +| --- | --- | +| `htmlspecialchars(str)` | Escape HTML characters (automatically applied in `{{ }}` syntax) | +| `setCookie(name, value, options?)` | Set a cookie in the response | +| `redirect(url)` | Redirect the user to another URL | +| `echo(content)` | Stream content to the response | + +```html [index.html] + + + + + Dynamic template + + +

Hello {{ $REQUEST.url }}

+

Welcome, !

+ + + +``` + +:read-more{to="https://github.com/h3js/rendu" title="Rendu Documentation"} + +## Custom renderer handler + +For more complex scenarios, you can create a custom renderer handler that programmatically generates responses. + +The handler is a default export function that receives an H3 event object. You can access the incoming `Request` via `event.req`: + +```ts [renderer.ts] +export default function renderer({ req }: { req: Request }) { + const url = new URL(req.url); + return new Response( + /* html */ ` + + + Custom Renderer + + +

Hello from custom renderer!

+

Current path: ${url.pathname}

+ + `, + { headers: { "content-type": "text/html; charset=utf-8" } } + ); +} +``` + +Then, specify the renderer entry in the Nitro config: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + renderer: { + handler: './renderer.ts' + } +}) +``` + +::note +When `renderer.handler` is set, it takes full control of rendering. The `renderer.template` option is ignored. +:: + +## Renderer priority + +The renderer always acts as a catch-all route (`/**`) and has the **lowest priority**. This means: + +1. Specific API routes are matched first (e.g., `/api/users`) +2. Specific server routes are matched next (e.g., `/about`) +3. The renderer catches everything else + +```md +api/ + users.ts → /api/users (matched first) +routes/ + about.ts → /about (matched second) +renderer.ts → /** (catches all other routes) +``` + +::warning +If you define a catch-all route (`[...].ts`) in your routes, Nitro will warn you that the renderer will override it. Use more specific routes or different HTTP methods to avoid conflicts. +:: + +:read-more{to="/docs/lifecycle" title="Lifecycle"} + +## Vite integration + +When using Nitro with Vite, the renderer integrates with Vite's build pipeline and dev server. + +### Development mode + +In development, the renderer template is read from disk on each request, so changes to `index.html` are reflected immediately without restarting the server. Vite's `transformIndexHtml` hook is applied to inject HMR client scripts and other dev-time transforms. + +### SSR with `` + +When using Vite environments with an `ssr` service, you can add an `` comment to your `index.html`. Nitro will replace it with the output from your SSR entry during rendering: + +```html [index.html] + + + + + SSR App + + +
+ + + +``` + +### Production build + +During production builds, Vite processes the `index.html` through its build pipeline (resolving scripts, CSS, and other assets), then Nitro inlines the transformed HTML into the server bundle. + +## Use Cases + +### Single-Page Application (SPA) + +Serve your SPA's `index.html` for all routes to enable client-side routing: + +> [!TIP] +> This is the default behavior of Nitro when used with Vite. + + + + diff --git a/docs/1.docs/5.routing.md b/docs/1.docs/5.routing.md new file mode 100644 index 0000000000..ceba27cae8 --- /dev/null +++ b/docs/1.docs/5.routing.md @@ -0,0 +1,707 @@ +--- +icon: ri:direction-line +--- + +# Routing + +> Nitro supports filesystem routing to automatically map files to routes. By combining code-splitting with compiled routes, it removes the need for a runtime router, leaving only minimal compiled logic. + +## Request handler + +Nitro request handler is a function accepting an `event` object, which is a [H3Event](https://h3.dev/guide/api/h3event#h3event-properties) object. + +::code-group +```ts [Single function] +import type { H3Event } from "nitro"; + +export default (event: H3Event) => { + return "world"; +} +``` +```ts [defineHandler] +import { defineHandler } from "nitro"; + +// For better type inference +export default defineHandler((event) => { + return "world"; +}); +``` +:: + +## Filesystem routing + +Nitro supports file-based routing for your API routes (files are automatically mapped to [h3 routes](https://h3.dev/guide/basics/routing)). Defining a route is as simple as creating a file inside the `api/` or `routes/` directory. + +You can only define one handler per files and you can [append the HTTP method](#specific-request-method) to the filename to define a specific request method. + +``` +routes/ + api/ + test.ts <-- /api/test + hello.get.ts <-- /hello (GET only) + hello.post.ts <-- /hello (POST only) +vite.config.ts +``` + +You can nest routes by creating subdirectories. + +```txt +routes/ + api/ + [org]/ + [repo]/ + index.ts <-- /api/:org/:repo + issues.ts <-- /api/:org/:repo/issues + index.ts <-- /api/:org +package.json +``` + +#### Route Groups + +In some cases, you may want to group a set of routes together in a way which doesn't affect file-based routing. For this purpose, you can put files in a folder which is wrapped in parentheses `(` and `)`. + +For example: +```txt +routes/ + api/ + (admin)/ + users.ts <-- /api/users + reports.ts <-- /api/reports + (public)/ + index.ts <-- /api +package.json +``` +> [!NOTE] The route groups are not part of the route definition and are only used for organization purposes. + + +### Static routes + +First, create a file in `routes/` or `routes/api/` directory. The filename will be the route path. + +Then, export a fetch-compatible function: + +```ts [routes/api/test.ts] +import { defineHandler } from "nitro"; + +export default defineHandler(() => { + return { hello: "API" }; +}); +``` + +### Dynamic routes + +#### Single param + +To define a route with params, use the `[]` syntax where `` is the name of the param. The param will be available in the `event.context.params` object or using the [`getRouterParam`](https://h3.dev/utils/request#getrouterparamevent-name-opts-decode) utility. + +```ts [routes/hello/[name\\].ts] +import { defineHandler } from "nitro"; + +export default defineHandler((event) => { + const { name } = event.context.params; + + return `Hello ${name}!`; +}); +``` + +Call the route with the param `/hello/nitro`, you will get: + +```txt [Response] +Hello nitro! +``` + +> [!WARNING] +> You cannot define multiple dynamic routes with different parameter names in the same directory, even if they use different HTTP methods (e.g., `[id].post.ts` and `[slug].get.ts`). This is a known current limitation of the router. Please use the exact same parameter name (e.g., `[id].post.ts` and `[id].get.ts`) to avoid conflicts. + +#### Multiple params + +You can define multiple params in a route using `[]/[]` syntax where each param is a folder. You **cannot** define multiple params in a single filename of folder. + +```ts [routes/hello/[name\\]/[age\\].ts] +import { defineHandler } from "nitro"; + +export default defineHandler((event) => { + const { name, age } = event.context.params; + + return `Hello ${name}! You are ${age} years old.`; +}); +``` + +#### Catch-all params + +You can capture all the remaining parts of a URL using `[...]` syntax. This will include the `/` in the param. + +```ts [routes/hello/[...name\\].ts] +import { defineHandler } from "nitro"; + +export default defineHandler((event) => { + const { name } = event.context.params; + + return `Hello ${name}!`; +}); +``` + +Call the route with the param `/hello/nitro/is/hot`, you will get: + +```txt [Response] +Hello nitro/is/hot! +``` + +### Specific request method + +You can append the HTTP method to the filename to force the route to be matched only for a specific HTTP request method, for example `hello.get.ts` will only match for `GET` requests. You can use any HTTP method you want. + +Supported methods: `get`, `post`, `put`, `delete`, `patch`, `head`, `options`, `connect`, `trace`. + +::code-group +```js [GET] +// routes/users/[id].get.ts +import { defineHandler } from "nitro"; + +export default defineHandler(async (event) => { + const { id } = event.context.params; + + // Do something with id + + return `User profile!`; +}); +``` + +```js [POST] +// routes/users.post.ts +import { defineHandler } from "nitro"; + +export default defineHandler(async (event) => { + const body = await event.req.json(); + + // Do something with body like saving it to a database + + return { updated: true }; +}); +``` +:: + +### Catch-all route + +You can create a special route that will match all routes that are not matched by any other route. This is useful for creating a default route. + +To create a catch-all route, create a file named `[...].ts`. + +```ts [routes/[...\\].ts] +import { defineHandler } from "nitro"; + +export default defineHandler((event) => { + return `Hello ${event.url}!`; +}); +``` + +### Environment specific handlers + +You can specify for a route that will only be included in specific builds by adding a `.dev`, `.prod` or `.prerender` suffix to the file name, for example: `routes/test.get.dev.ts` or `routes/test.get.prod.ts`. + +The suffix is placed after the method suffix (if any): + +```txt +routes/ + env/ + index.dev.ts <-- /env (dev only) + index.get.prod.ts <-- /env (GET, prod only) +``` + +> [!TIP] +> You can specify multiple environments or specify a preset name as environment using programmatic registration of routes via [`routes`](#routes-config) config. + +### Ignoring files + +You can use the `ignore` config option to exclude files from route scanning. It accepts an array of glob patterns relative to the server directory. + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + ignore: [ + "routes/api/**/_*", // Ignore files starting with _ in api/ + "middleware/_*.ts", // Ignore middleware starting with _ + "routes/_*.ts", // Ignore root routes starting with _ + ], +}); +``` + +## Programmatic route handlers + +In addition to filesystem routing, you can register route handlers programmatically using the `routes` config option. + +### `routes` config + +The `routes` option allows you to map route patterns to handlers: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + routes: { + "/api/hello": "./server/routes/api/hello.ts", + "/api/custom": { + handler: "./server/routes/api/hello.ts", + method: "POST", + lazy: true, + }, + "/virtual": { + handler: "#virtual-route", + }, + }, +}); +``` + +Each route entry can be a simple string (handler path) or an object with the following options: + +| Option | Type | Description | +|--------|------|-------------| +| `handler` | `string` | Path to event handler file or virtual module ID | +| `method` | `string` | HTTP method to match (`get`, `post`, etc.) | +| `lazy` | `boolean` | Use lazy loading to import handler | +| `format` | `"web" \| "node"` | Handler type. `"node"` handlers are converted to web-compatible | +| `env` | `string \| string[]` | Environments to include this handler (`"dev"`, `"prod"`, `"prerender"`, or a preset name) | + +### `handlers` config + +The `handlers` array is useful for registering middleware with control over route matching: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + handlers: [ + { + route: "/api/**", + handler: "./server/middleware/api-auth.ts", + middleware: true, + }, + ], +}); +``` + +Each handler entry supports the following options: + +| Option | Type | Description | +|--------|------|-------------| +| `route` | `string` | HTTP pathname pattern (e.g., `/test`, `/api/:id`, `/blog/**`) | +| `handler` | `string` | Path to event handler file or virtual module ID | +| `method` | `string` | HTTP method to match (`get`, `post`, etc.) | +| `middleware` | `boolean` | Run handler as middleware before route handlers | +| `lazy` | `boolean` | Use lazy loading to import handler | +| `format` | `"web" \| "node"` | Handler type. `"node"` handlers are converted to web-compatible | +| `env` | `string \| string[]` | Environments to include this handler (`"dev"`, `"prod"`, `"prerender"`, or a preset name) | + +## Middleware + +Nitro route middleware can hook into the request lifecycle. + +::tip +A middleware can modify the request before it is processed, not after. +:: + +Middleware are auto-registered within the `middleware/` directory. + +```md +middleware/ + auth.ts + logger.ts + ... +routes/ + hello.ts +``` + +### Simple middleware + +Middleware are defined exactly like route handlers with the only exception that they should not return anything. +Returning from middleware behaves like returning from a request - the value will be returned as a response and further code will not be ran. + +```ts [middleware/auth.ts] +import { defineHandler } from "nitro"; + +export default defineHandler((event) => { + // Extends or modify the event + event.context.user = { name: "Nitro" }; +}); +``` + +Middleware in `middleware/` directory are automatically registered for all routes. If you want to register a middleware for a specific route, see [Object Syntax Event Handler](https://h3.dev/guide/basics/handler#object-syntax). + +::note +Returning anything from a middleware will close the request and should be avoided! Any returned value from middleware will be the response and further code will not be executed however **this is not recommended to do!** +:: + +### Route Meta + +You can define route handler meta at build-time using `defineRouteMeta` macro in the event handler files. + +> [!IMPORTANT] +> This feature is currently experimental. + +```ts [routes/api/test.ts] +import { defineRouteMeta } from "nitro"; +import { defineHandler } from "nitro"; + +defineRouteMeta({ + openAPI: { + tags: ["test"], + description: "Test route description", + parameters: [{ in: "query", name: "test", required: true }], + }, +}); + +export default defineHandler(() => "OK"); +``` + +::read-more{to="https://swagger.io/specification/v3/"} +This feature is currently usable to specify OpenAPI meta. See swagger specification for available OpenAPI options. +:: + +### Execution order + +Middleware are executed in directory listing order. + +```md +middleware/ + auth.ts <-- First + logger.ts <-- Second + ... <-- Third +``` + +Prefix middleware with a number to control their execution order. + +```md +middleware/ + 1.logger.ts <-- First + 2.auth.ts <-- Second + 3.... <-- Third +``` +::note +Remember that file names are sorted as strings, thus for example if you have 3 files `1.filename.ts`, `2.filename.ts` and `10.filename.ts`, the `10.filename.ts` will come after the `1.filename.ts`. To avoid this, prefix `1-9` with a `0` like `01`, if you have more than 10 middleware in the same directory. +:: + +### Request filtering + +Middleware are executed on every request. + +Apply custom logic to scope them to specific conditions. + +For example, you can use the URL to apply a middleware to a specific route: + +```ts [middleware/auth.ts] +import { defineHandler } from "nitro"; + +export default defineHandler((event) => { + // Will only execute for /auth route + if (event.url.pathname.startsWith('/auth')) { + event.context.user = { name: "Nitro" }; + } +}); +``` + +### Route-scoped middleware + +You can register middleware for specific route patterns using the [`handlers`](#handlers-config) config with the `middleware` option and a specific `route`: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + handlers: [ + { + route: "/api/**", + handler: "./server/middleware/api-auth.ts", + middleware: true, + }, + ], +}); +``` + +Unlike global middleware (registered in the `middleware/` directory which match `/**`), route-scoped middleware only run for requests matching the specified pattern. + +## Error handling + +You can use the [utilities available in H3](https://h3.dev/guide/basics/error) to handle errors in both routes and middlewares. + +The way errors are sent back to the client depends on the environment. In development, requests with an `Accept` header of `text/html` (such as browsers) will receive a HTML error page. In production, errors are always sent in JSON. + +This behaviour can be overridden by some request properties (e.g.: `Accept` or `User-Agent` headers). + +## Code splitting + +Nitro creates a separate chunk for each route handler. Chunks load on-demand when first requested, so `/api/users` doesn't load code for `/api/posts`. + +See [`inlineDynamicImports`](/config#inlinedynamicimports) to bundle everything into a single file. + +## Route rules + +Nitro allows you to add logic at the top-level for each route of your configuration. It can be used for redirecting, proxying, caching, authentication, and adding headers to routes. + +It is a map from route pattern (following [rou3](https://github.com/h3js/rou3)) to route options. + +When `cache` option is set, handlers matching pattern will be automatically wrapped with `defineCachedEventHandler`. See the [cache guide](/docs/cache) to learn more about this function. + +::note +`swr: true|number` is shortcut for `cache: { swr: true, maxAge: number }` +:: + +You can set route rules in the `nitro.routeRules` options. + +```ts [nitro.config.ts] +import { defineConfig } from "nitro"; + +export default defineNitroConfig({ + routeRules: { + '/blog/**': { swr: true }, + '/blog2/**': { swr: 600 }, + '/blog3/**': { static: true }, + '/blog4/**': { cache: { /* cache options*/ } }, + '/assets/**': { headers: { 'cache-control': 's-maxage=0' } }, + '/api/v1/**': { cors: true, headers: { 'access-control-allow-methods': 'GET' } }, + '/old-page': { redirect: '/new-page' }, + '/old-page/**': { redirect: '/new-page/**' }, + '/proxy/example': { proxy: 'https://example.com' }, + '/proxy/**': { proxy: '/api/**' }, + '/admin/**': { basicAuth: { username: 'admin', password: 'supersecret' } }, + } +}); +``` + +### Rule merging and overrides + +Route rules are matched from least specific to most specific. When multiple rules match a request, their options are merged, with more specific rules taking precedence. + +You can use `false` to disable a rule that was set by a more general pattern: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + routeRules: { + '/api/cached/**': { swr: true }, + '/api/cached/no-cache': { cache: false, swr: false }, + '/admin/**': { basicAuth: { username: 'admin', password: 'secret' } }, + '/admin/public/**': { basicAuth: false }, + } +}); +``` + +### Headers + +Set custom response headers for matching routes: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + routeRules: { + '/api/**': { headers: { 'cache-control': 's-maxage=60' } }, + '**': { headers: { 'x-powered-by': 'Nitro' } }, + } +}); +``` + +### CORS + +Enable CORS headers with the `cors: true` shortcut. This sets `access-control-allow-origin: *`, `access-control-allow-methods: *`, `access-control-allow-headers: *`, and `access-control-max-age: 0`. + +You can override individual CORS headers using `headers`: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + routeRules: { + '/api/v1/**': { + cors: true, + headers: { 'access-control-allow-methods': 'GET' }, + }, + } +}); +``` + +### Redirect + +Redirect matching routes to another URL. Use a string for a simple redirect (defaults to `307` status), or an object for more control: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + routeRules: { + // Simple redirect (307 status) + '/old-page': { redirect: '/new-page' }, + // Redirect with custom status + '/legacy': { redirect: { to: 'https://example.com/', status: 308 } }, + // Wildcard redirect — preserves the path after the pattern + '/old-blog/**': { redirect: 'https://blog.example.com/**' }, + } +}); +``` + +### Proxy + +Proxy requests to another URL. Supports both internal and external targets: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + routeRules: { + // Proxy to exact URL + '/api/proxy/example': { proxy: 'https://example.com' }, + // Proxy to internal route + '/api/proxy/**': { proxy: '/api/echo' }, + // Wildcard proxy — preserves the path after the pattern + '/cdn/**': { proxy: 'https://cdn.jsdelivr.net/**' }, + // Proxy with options + '/external/**': { + proxy: { + to: 'https://api.example.com/**', + // Additional H3 proxy options... + }, + }, + } +}); +``` + +### Basic auth + +Protect routes with HTTP Basic Authentication: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + routeRules: { + '/admin/**': { + basicAuth: { + username: 'admin', + password: 'supersecret', + realm: 'Admin Area', // Optional, shown in the browser prompt + }, + }, + // Disable basic auth for a sub-path + '/admin/public/**': { basicAuth: false }, + } +}); +``` + +### Caching (SWR / Static) + +Control caching behavior with `cache`, `swr`, or `static` options: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + routeRules: { + // Enable stale-while-revalidate caching + '/blog/**': { swr: true }, + // SWR with maxAge in seconds + '/blog/posts/**': { swr: 600 }, + // Full cache options + '/api/data/**': { + cache: { + maxAge: 60, + swr: true, + // ...other cache options + }, + }, + // Disable caching + '/api/realtime/**': { cache: false }, + } +}); +``` + +::tip +`swr: true` is a shortcut for `cache: { swr: true }` and `swr: ` is a shortcut for `cache: { swr: true, maxAge: }`. +:: + +### Prerender + +Mark routes for prerendering at build time: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + routeRules: { + '/about': { prerender: true }, + '/dynamic/**': { prerender: false }, + } +}); +``` + +### ISR (Vercel) + +Configure Incremental Static Regeneration for Vercel deployments: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + routeRules: { + '/isr/**': { isr: true }, + '/isr-ttl/**': { isr: 60 }, + '/isr-custom/**': { + isr: { + expiration: 60, + allowQuery: ['q'], + group: 1, + }, + }, + } +}); +``` + +### Route rules reference + +| Option | Type | Description | +|--------|------|-------------| +| `headers` | `Record` | Custom response headers | +| `redirect` | `string \| { to: string, status?: number }` | Redirect to another URL (default status: `307`) | +| `proxy` | `string \| { to: string, ...proxyOptions }` | Proxy requests to another URL | +| `cors` | `boolean` | Enable permissive CORS headers | +| `cache` | `object \| false` | Cache options (see [cache guide](/docs/cache)) | +| `swr` | `boolean \| number` | Shortcut for `cache: { swr: true, maxAge: number }` | +| `static` | `boolean \| number` | Shortcut for static caching | +| `basicAuth` | `{ username, password, realm? } \| false` | HTTP Basic Authentication | +| `prerender` | `boolean` | Enable/disable prerendering | +| `isr` | `boolean \| number \| object` | Incremental Static Regeneration (Vercel) | + +### Runtime route rules + +Route rules can be provided through `runtimeConfig`, allowing overrides via environment variables without rebuilding: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + runtimeConfig: { + nitro: { + routeRules: { + '/api/**': { headers: { 'x-env': 'production' } }, + }, + }, + }, +}); +``` + +## Config reference + +These config options control routing behavior: + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `baseURL` | `string` | `"/"` | Base URL for all routes | +| `apiBaseURL` | `string` | `"/api"` | Base URL for routes in the `api/` directory | +| `apiDir` | `string` | `"api"` | Directory name for API routes | +| `routesDir` | `string` | `"routes"` | Directory name for file-based routes | +| `serverDir` | `string \| false` | `false` | Server directory for scanning routes, middleware, plugins, etc. | +| `scanDirs` | `string[]` | `[]` | Additional directories to scan for routes | +| `routes` | `Record` | `{}` | Route-to-handler mapping | +| `handlers` | `NitroEventHandler[]` | `[]` | Programmatic handler registration (mainly for middleware) | +| `routeRules` | `Record` | `{}` | Route rules for matching patterns | +| `ignore` | `string[]` | `[]` | Glob patterns to ignore during file scanning | diff --git a/docs/1.docs/50.assets.md b/docs/1.docs/50.assets.md new file mode 100644 index 0000000000..5be2ca7da0 --- /dev/null +++ b/docs/1.docs/50.assets.md @@ -0,0 +1,172 @@ +--- +icon: ri:image-2-line +--- + +# Assets + +Nitro supports two types of assets: **public assets** served directly to clients and **server assets** bundled into the server for programmatic access. + +## Public Assets + +Nitro handles assets via the `public/` directory. + +All assets in `public/` directory will be automatically served. This means that you can access them directly from the browser without any special configuration. + +```md +public/ + image.png <-- /image.png + video.mp4 <-- /video.mp4 + robots.txt <-- /robots.txt +``` + +### Caching and Headers + +Public assets are served with automatic `ETag` and `Last-Modified` headers for conditional requests. When the client sends `If-None-Match` or `If-Modified-Since` headers, Nitro returns a `304 Not Modified` response. + +For assets served from a non-root `baseURL` (such as `/build/`), Nitro prevents fallthrough to application handlers. If a request matches a public asset base but the file is not found, a `404` is returned immediately. + +### Production Public Assets + +When building your Nitro app, the `public/` directory will be copied to `.output/public/` and a manifest with metadata will be created and embedded in the server bundle. + +```json +{ + "/image.png": { + "type": "image/png", + "etag": "\"4a0c-6utWq0Kbk5OqDmksYCa9XV8irnM\"", + "mtime": "2023-03-04T21:39:45.086Z", + "size": 18956 + }, + "/robots.txt": { + "type": "text/plain; charset=utf-8", + "etag": "\"8-hMqyDrA8fJ0R904zgEPs3L55Jls\"", + "mtime": "2023-03-04T21:39:45.086Z", + "size": 8 + }, + "/video.mp4": { + "type": "video/mp4", + "etag": "\"9b943-4UwfQXKUjPCesGPr6J5j7GzNYGU\"", + "mtime": "2023-03-04T21:39:45.085Z", + "size": 637251 + } +} +``` + +This allows Nitro to know the public assets without scanning the directory, giving high performance with caching headers. + +### Custom Public Asset Directories + +You can configure additional public asset directories using the `publicAssets` config option. Each entry supports the following properties: + +- `dir` -- Path to the directory (resolved relative to `rootDir`). +- `baseURL` -- URL prefix for serving assets (default: `"/"`). +- `maxAge` -- Cache `max-age` in seconds. When set, a `Cache-Control: public, max-age=, immutable` header is applied via route rules. +- `fallthrough` -- Whether requests should fall through to application handlers when the asset is not found. Top-level (`baseURL: "/"`) directories default to `true`; non-root directories default to `false`. +- `ignore` -- Pass `false` to disable ignore patterns, or an array of glob patterns to override the global `ignore` option. + +```js [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + publicAssets: [ + { + baseURL: "build", + dir: "public/build", + maxAge: 3600, + }, + ], +}); +``` + +In this example, files in `public/build/` are served under `/build/` with a one-hour cache and no fallthrough to application handlers. + +### Compressed Public Assets + +Nitro can generate pre-compressed versions of your public assets during the build. When a client sends an `Accept-Encoding` header, the server will serve the compressed version if available. Supported encodings are gzip (`.gz`), brotli (`.br`), and zstd (`.zst`). + +Set `compressPublicAssets: true` to enable all encodings: + +```js [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + compressPublicAssets: true, +}); +``` + +Or pick specific encodings: + +```js [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + compressPublicAssets: { + gzip: true, + brotli: true, + zstd: false, + }, +}); +``` + +> [!NOTE] +> Only compressible MIME types (text, JavaScript, JSON, XML, WASM, fonts, SVG, etc.) with a file size of at least 1 KB are compressed. Source map files (`.map`) are excluded. + +## Server Assets + +All assets in `assets/` directory will be added to the server bundle. After building your application, you can find them in the `.output/server/chunks/raw/` directory. Be careful with the size of your assets, as they will be bundled with the server bundle. + +> [!TIP] +> Unless using `useStorage()`, assets won't be included in the server bundle. + +They can be addressed by the `assets:server` mount point using the [storage layer](/docs/storage). + +For example, you could store a json file in `assets/data.json` and retrieve it in your handler: + +```js +import { defineHandler } from "nitro"; + +export default defineHandler(async () => { + const data = await useStorage("assets:server").get("data.json"); + + return data; +}); +``` + +### Custom Server Assets + +In order to add assets from a custom directory, you will need to define a path in your nitro config. This allows you to add assets from a directory outside of the `assets/` directory. + +Each entry in `serverAssets` supports the following properties: + +- `baseName` -- Name used as the storage mount point (accessed via `assets:`). +- `dir` -- Path to the directory (resolved relative to `rootDir`). +- `pattern` -- Glob pattern for file inclusion (default: `"**/*"`). +- `ignore` -- Array of glob patterns to exclude files. + +```js [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + serverAssets: [ + { + baseName: "templates", + dir: "./templates", + }, + ], +}); +``` + +Then you can use the `assets:templates` base to retrieve your assets. + +```ts [handlers/success.ts] +import { defineHandler } from "nitro"; + +export default defineHandler(async (event) => { + const html = await useStorage("assets:templates").get("success.html"); + + return html; +}); +``` + +> [!TIP] +> During development, server assets are read directly from the filesystem using the `fs` unstorage driver. In production, they are bundled into the server as lazy imports with pre-computed metadata (MIME type, ETag, modification time). diff --git a/docs/1.docs/50.configuration.md b/docs/1.docs/50.configuration.md new file mode 100644 index 0000000000..bc80db1e9f --- /dev/null +++ b/docs/1.docs/50.configuration.md @@ -0,0 +1,257 @@ +--- +icon: ri:settings-3-line +--- + +# Configuration + +> Customize and extend Nitro defaults. + +::read-more{to="/config"} +See [config reference](/config) for available options. +:: + +## Config file + +You can customize your Nitro builder with a configuration file. + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + // Nitro options +}) +``` +```ts [vite.config.ts] +import { defineConfig } from 'vite' +import { nitro } from 'nitro/vite' + +export default defineConfig({ + plugins: [ + nitro() + ], + nitro: { + // Nitro options + } +}) + +``` + +> [!TIP] +> Nitro loads the configuration using [c12](https://github.com/unjs/c12), giving more possibilities such as using `.nitrorc` file in current working directory or in the user's home directory. + +### Environment-specific config + +Using [c12](https://github.com/unjs/c12) conventions, you can provide environment-specific overrides using `$development` and `$production` keys: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + logLevel: 3, + $development: { + // Options applied only in development mode + debug: true, + }, + $production: { + // Options applied only in production builds + minify: true, + }, +}) +``` + +The environment name is `"development"` during `nitro dev` and `"production"` during `nitro build`. + +### Extending configs + +You can extend from other configs or presets using the `extends` key: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + extends: "./base.config", +}) +``` + +### Config from `package.json` + +You can also provide Nitro configuration under the `nitro` key in your `package.json` file. + +## Directory options + +Nitro provides several options for controlling directory structure: + +| Option | Default | Description | +| --- | --- | --- | +| `rootDir` | `.` (current directory) | The root directory of the project. | +| `serverDir` | `false` | Server source directory (set to `"server"` or `"./"` to enable). | +| `buildDir` | `node_modules/.nitro` | Directory for build artifacts. | +| `output.dir` | `.output` | Production output directory. | +| `output.serverDir` | `.output/server` | Server output directory. | +| `output.publicDir` | `.output/public` | Public assets output directory. | + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + serverDir: "server", + buildDir: "node_modules/.nitro", + output: { + dir: ".output", + }, +}) +``` + +> [!NOTE] +> The `srcDir` option is deprecated. Use `serverDir` instead. + +## Environment variables + +Certain Nitro behaviors can be configured using environment variables: + +| Variable | Description | +| --- | --- | +| `NITRO_PRESET` | Override the deployment preset. | +| `NITRO_COMPATIBILITY_DATE` | Set the compatibility date. | +| `NITRO_APP_BASE_URL` | Override the base URL (default: `/`). | + +## Runtime configuration + +Nitro provides a runtime config API to expose configuration within your application, with the ability to update it at runtime by setting environment variables. This is useful when you want to expose different configuration values for different environments (e.g. development, staging, production). For example, you can use this to expose different API endpoints for different environments or to expose different feature flags. + +First, you need to define the runtime config in your configuration file. + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + runtimeConfig: { + apiToken: "dev_token", // `dev_token` is the default value + } +}); +``` + +You can now access the runtime config using `useRuntimeConfig()`. + +```ts [api/example.get.ts] +import { defineHandler } from "nitro"; +import { useRuntimeConfig } from "nitro/runtime-config"; + +export default defineHandler((event) => { + return useRuntimeConfig().apiToken; // Returns `dev_token` +}); +``` + +### Nested objects + +Runtime config supports nested objects. Keys at any depth are mapped to environment variables using the `NITRO_` prefix and `UPPER_SNAKE_CASE` conversion: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + runtimeConfig: { + database: { + host: "localhost", + port: 5432, + }, + }, +}); +``` + +```bash [.env] +NITRO_DATABASE_HOST="db.example.com" +NITRO_DATABASE_PORT="5433" +``` + +> [!NOTE] +> Only keys defined in `runtimeConfig` in your config file will be considered. You cannot introduce new keys using environment variables alone. + +### Serialization + +Runtime config values must be serializable (strings, numbers, booleans, plain objects, and arrays). Non-serializable values (class instances, functions, etc.) will trigger a warning at build time. + +Values that are `undefined` or `null` in the config are replaced with empty strings (`""`) as a fallback. + +### Local development + +You can update the runtime config using environment variables. You can use a `.env` or `.env.local` file in development and use platform variables in production (see below). + +Create an `.env` file in your project root: + +```bash [.env] +NITRO_API_TOKEN="123" +``` + +Re-start the development server, fetch the `/api/example` endpoint and you should see `123` as the response instead of `dev_token`. + +> [!NOTE] +> The `.env` and `.env.local` files are only loaded during development (`nitro dev`). In production, use your platform's native environment variable mechanism. + +Do not forget that you can still universally access environment variables using `import.meta.env` or `process.env` but avoid using them in ambient global contexts to prevent unexpected behavior. + +### Production + +You can define variables in your production environment to update the runtime config. + +::warning +All variables must be prefixed with `NITRO_` to be applied to the runtime config. They will override the runtime config variables defined within your `nitro.config.ts` file. +:: + +```bash [.env] +NITRO_API_TOKEN="123" +``` + +In runtime config, define key using camelCase. In environment variables, define key using snake_case and uppercase. + +```ts +{ + helloWorld: "foo" +} +``` + +```bash +NITRO_HELLO_WORLD="foo" +``` + +### Custom env prefix + +You can configure a secondary environment variable prefix using the `nitro.envPrefix` runtime config key. This prefix is checked in addition to the default `NITRO_` prefix: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + runtimeConfig: { + nitro: { + envPrefix: "APP_", + }, + apiToken: "", + }, +}); +``` + +With this configuration, both `NITRO_API_TOKEN` and `APP_API_TOKEN` will be checked as overrides. + +### Env expansion + +When enabled, environment variable references using `{{VAR_NAME}}` syntax in runtime config string values are expanded at runtime: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + experimental: { + envExpansion: true, + }, + runtimeConfig: { + url: "https://{{APP_DOMAIN}}/api", + }, +}); +``` + +```bash +APP_DOMAIN="example.com" +``` + +At runtime, `useRuntimeConfig().url` will resolve to `"https://example.com/api"`. diff --git a/docs/1.docs/50.database.md b/docs/1.docs/50.database.md new file mode 100644 index 0000000000..979694901a --- /dev/null +++ b/docs/1.docs/50.database.md @@ -0,0 +1,195 @@ +--- +icon: ri:database-2-line +title: Database +--- + +> Nitro provides a built-in and lightweight SQL database layer. + +The default database connection is **preconfigured** with [SQLite](https://db0.unjs.io/connectors/sqlite) and works out of the box for development mode and any Node.js compatible production deployments. By default, data will be stored in `.data/db.sqlite`. + +:read-more{to="https://db0.unjs.io" title="DB0 Documentation"} + +> [!IMPORTANT] +> Database support is currently experimental. +> Refer to the [db0 issues](https://github.com/unjs/db0/issues) for status and bug report. + +In order to enable database layer you need to enable experimental feature flag. + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + experimental: { + database: true + } +}) +``` + +> [!TIP] +> You can change default connection or define more connections to any of the [supported databases](https://db0.unjs.io/connectors/sqlite). + +> [!TIP] +> You can integrate database instance to any of the [supported ORMs](https://db0.unjs.io/integrations). + + +## Usage + + + +```ts [server.ts] +import { defineHandler } from "nitro"; +import { useDatabase } from "nitro/database"; + +export default defineHandler(async () => { + const db = useDatabase(); + + // Create users table + await db.sql`DROP TABLE IF EXISTS users`; + await db.sql`CREATE TABLE IF NOT EXISTS users ("id" TEXT PRIMARY KEY, "firstName" TEXT, "lastName" TEXT, "email" TEXT)`; + + // Add a new user + const userId = String(Math.round(Math.random() * 10_000)); + await db.sql`INSERT INTO users VALUES (${userId}, 'John', 'Doe', '')`; + + // Query for users + const { rows } = await db.sql`SELECT * FROM users WHERE id = ${userId}`; + + return { + rows, + }; +}); +``` + + + +### `useDatabase` + +Use `useDatabase` to get a database instance. It accepts an optional connection name (defaults to `"default"`). + +```ts +import { useDatabase } from "nitro/database"; + +// Use the default connection +const db = useDatabase(); + +// Use a named connection +const usersDb = useDatabase("users"); +``` + +> [!NOTE] +> When `experimental.database` is enabled, `useDatabase` is auto-imported and available without an explicit import statement. + +Database instances are created lazily on first use and cached for subsequent calls with the same connection name. If a connection name is not configured, an error will be thrown. + +### `db.sql` + +Execute SQL queries using tagged template literals with automatic parameter binding: + +```ts +const db = useDatabase(); + +// Insert with parameterized values (safe from SQL injection) +const id = "1001"; +await db.sql`INSERT INTO users VALUES (${id}, 'John', 'Doe', 'john@example.com')`; + +// Query with parameters +const { rows } = await db.sql`SELECT * FROM users WHERE id = ${id}`; + +// The result includes rows, changes count, and last insert ID +const result = await db.sql`INSERT INTO posts (title) VALUES (${"Hello"})`; +// result.rows, result.changes, result.lastInsertRowid +``` + +### `db.exec` + +Execute a raw SQL string directly: + +```ts +const db = useDatabase(); + +await db.exec("CREATE TABLE IF NOT EXISTS users (id TEXT PRIMARY KEY, name TEXT)"); +``` + +### `db.prepare` + +Prepare an SQL statement for repeated execution: + +```ts +const db = useDatabase(); + +const stmt = db.prepare("SELECT * FROM users WHERE id = ?"); +const result = await stmt.bind("1001").all(); +``` + +## Configuration + +You can configure database connections using `database` config: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + database: { + default: { + connector: "sqlite", + options: { name: "db" } + }, + users: { + connector: "postgresql", + options: { + url: "postgresql://username:password@hostname:port/database_name" + }, + }, + }, +}); +``` + +### Development Database + +Use the `devDatabase` config to override the database configuration **only for development mode**. This is useful for using a local SQLite database during development while targeting a different database in production. + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + database: { + default: { + connector: "postgresql", + options: { + url: "postgresql://username:password@hostname:port/database_name" + } + } + }, + devDatabase: { + default: { + connector: "sqlite", + options: { name: "dev-db" } + } + } +}); +``` + +> [!TIP] +> When `experimental.database` is enabled and no `database` or `devDatabase` config is provided, Nitro automatically configures a default SQLite connection. In development mode, data is stored relative to the project root directory. In Node.js production, it uses the default SQLite path. + +## Connectors + +Nitro supports all [db0 connectors](https://db0.unjs.io/connectors). The `connector` field in the database config accepts any of the following values: + +| Connector | Description | +|---|---| +| `sqlite` | Node.js built-in SQLite (alias for `node-sqlite`) | +| `node-sqlite` | Node.js built-in SQLite | +| `better-sqlite3` | [better-sqlite3](https://github.com/WiseLibs/better-sqlite3) | +| `sqlite3` | [sqlite3](https://github.com/TryGhost/node-sqlite3) | +| `bun` / `bun-sqlite` | Bun built-in SQLite | +| `libsql` / `libsql-node` | [libSQL](https://github.com/tursodatabase/libsql) (Node.js) | +| `libsql-http` | libSQL over HTTP | +| `libsql-web` | libSQL for web environments | +| `postgresql` | [PostgreSQL](https://github.com/porsager/postgres) | +| `mysql2` | [MySQL](https://github.com/sidorares/node-mysql2) | +| `pglite` | [PGlite](https://github.com/electric-sql/pglite) (embedded PostgreSQL) | +| `planetscale` | [PlanetScale](https://github.com/planetscale/database-js) serverless | +| `cloudflare-d1` | [Cloudflare D1](https://developers.cloudflare.com/d1/) | +| `cloudflare-hyperdrive-mysql` | Cloudflare Hyperdrive with MySQL | +| `cloudflare-hyperdrive-postgresql` | Cloudflare Hyperdrive with PostgreSQL | diff --git a/docs/1.docs/50.lifecycle.md b/docs/1.docs/50.lifecycle.md new file mode 100644 index 0000000000..7120456280 --- /dev/null +++ b/docs/1.docs/50.lifecycle.md @@ -0,0 +1,201 @@ +--- +icon: i-lucide-layers +--- + +# Lifecycle + +> Understand how Nitro runs and serves incoming requests to your application. + +## Request lifecycle + +A request can be intercepted and terminated (with or without a response) from any of these layers, in this order: + +::steps + +### `request` hook + +The `request` hook is the first code that runs for every incoming request. It is registered via a [server plugin](/docs/plugins): + +```ts [plugins/request-hook.ts] +import { definePlugin } from "nitro"; + +export default definePlugin((nitroApp) => { + nitroApp.hooks.hook("request", (event) => { + console.log(`Incoming request on ${event.path}`); + }); +}); +``` + +::note +Errors thrown inside the `request` hook are captured by the [`error` hook](#error-handling) and do not terminate the request pipeline. +:: + +### Static assets + +When static asset serving is enabled (the default for most presets), Nitro checks if the request matches a file in the `public/` directory **before** any other middleware or route handler runs. + +If a match is found, the static file is served immediately with appropriate `Content-Type`, `ETag`, `Last-Modified`, and `Cache-Control` headers. The request is terminated and no further middleware or routes are executed. + +Static assets also support content negotiation for pre-compressed files (gzip, brotli, zstd) via the `Accept-Encoding` header. + +### Route rules + +The matching route rules defined in the Nitro config will execute. Route rules run as middleware so most of them alter the response without terminating it (for instance, adding a header or setting a cache policy). + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + routeRules: { + '/**': { headers: { 'x-nitro': 'first' } } + } +}) +``` + +:read-more{to="/docs/routing#route-rules" title="Routing > Route rules"} + +### Global middleware + +Any global middleware defined in the `middleware/` directory will be run: + +```ts [middleware/info.ts] +import { defineHandler } from "nitro"; + +export default defineHandler((event) => { + event.context.info = { name: "Nitro" }; +}); +``` + +::warning +Returning from a middleware will close the request and should be avoided when possible. +:: + +::read-more{to="/docs/routing#middleware"} +Learn more about Nitro middleware. +:: + +### Routed middleware + +Middleware that targets a specific route pattern (defined with a `route` in `middleware/`) runs after global middleware but before the matched route handler. + +### Routes + +Nitro will look at defined routes in the `routes/` folder to match the incoming request. + +```ts [routes/api/hello.ts] +export default (event) => ({ world: true }) +``` + +::read-more{to="/docs/routing#filesystem-routing"} +Learn more about Nitro file-system routing. +:: + +If serverEntry is defined it will catch all requests not matching any other route acting as `/**` route handler. + +```ts [server.ts] +import { defineHandler } from "nitro"; + +export default defineHandler((event) => { + if (event.path === "/") { + return "Home page"; + } +}); +``` + +::read-more{to="/docs/server-entry"} +Learn more about Nitro server entry. +:: + +### Renderer + +If no route is matched, Nitro will look for a renderer handler (defined or auto-detected) to handle the request. + +::read-more{to="/docs/renderer"} +Learn more about Nitro renderer. +:: + +### `response` hook + +After the response is created (from any of the layers above), the `response` hook runs. This hook receives the final `Response` object and the event, and can be used to inspect or modify response headers: + +```ts [plugins/response-hook.ts] +import { definePlugin } from "nitro"; + +export default definePlugin((nitroApp) => { + nitroApp.hooks.hook("response", (res, event) => { + console.log(`Response ${res.status} for ${event.path}`); + }); +}); +``` + +::note +The `response` hook runs for every response, including static assets, middleware-terminated requests, and error responses. +:: + +:: + +## Error handling + +When an error occurs at any point in the request lifecycle, Nitro: + +1. Calls the `error` hook with the error and context (including the event and source tags). +2. Passes the error to the **error handler** which converts it into an HTTP response. + +```ts [plugins/errors.ts] +import { definePlugin } from "nitro"; + +export default definePlugin((nitroApp) => { + nitroApp.hooks.hook("error", (error, context) => { + console.error("Captured error:", error); + // context.event - the H3 event (if available) + // context.tags - error source tags like "request", "response", "plugin" + }); +}); +``` + +Errors are also tracked per-request in `event.req.context.nitro.errors` for inspection in later hooks. + +You can provide a custom error handler in the Nitro config to control error response formatting: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + errorHandler: "~/error", +}) +``` + +Additionally, unhandled promise rejections and uncaught exceptions at the process level are automatically captured into the `error` hook with the tags `"unhandledRejection"` and `"uncaughtException"`. + +## Server shutdown + +When the Nitro server is shutting down, the `close` hook is called. Use this to clean up resources such as database connections, timers, or external service handles: + +```ts [plugins/cleanup.ts] +import { definePlugin } from "nitro"; + +export default definePlugin((nitroApp) => { + nitroApp.hooks.hook("close", async () => { + // Clean up resources + }); +}); +``` + +## Hooks reference + +All runtime hooks are registered through [server plugins](/docs/plugins) using `nitroApp.hooks.hook()`. + +| Hook | Signature | When it runs | +| --- | --- | --- | +| `request` | `(event: HTTPEvent) => void \| Promise` | Start of each request, before routing. | +| `response` | `(res: Response, event: HTTPEvent) => void \| Promise` | After the response is created, before it is sent. | +| `error` | `(error: Error, context: { event?, tags? }) => void` | When any error is captured during the lifecycle. | +| `close` | `() => void` | When the Nitro server is shutting down. | + +::note +The `NitroRuntimeHooks` interface is augmentable. Deployment presets (such as Cloudflare) can extend it with platform-specific hooks. +:: + +::read-more{to="/docs/plugins"} +Learn more about Nitro plugins and hook usage examples. +:: diff --git a/docs/1.docs/50.plugins.md b/docs/1.docs/50.plugins.md new file mode 100644 index 0000000000..1480d2816f --- /dev/null +++ b/docs/1.docs/50.plugins.md @@ -0,0 +1,168 @@ +--- +icon: ri:plug-line +--- + +# Plugins + +> Use plugins to extend Nitro's runtime behavior. + +Nitro plugins are **executed once** during server startup in order to allow extending Nitro's runtime behavior. +They receive `nitroApp` context, which can be used to hook into lifecycle events. + +Plugins are auto-registered from the `plugins/` directory and run synchronously by file name order on the first Nitro initialization. Plugin functions themselves must be synchronous (return `void`), but the hooks they register can be async. + +**Example:** + +```ts [plugins/test.ts] +import { definePlugin } from "nitro"; + +export default definePlugin((nitroApp) => { + console.log('Nitro plugin', nitroApp) +}) +``` + +If you have plugins in another directory, you can use the `plugins` option: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + plugins: ['my-plugins/hello.ts'] +}) +``` + +## The `nitroApp` context + +The plugin function receives a `nitroApp` object with the following properties: + +| Property | Type | Description | +| --- | --- | --- | +| `hooks` | [`HookableCore`](https://github.com/unjs/hookable) | Hook system for registering lifecycle callbacks. | +| `h3` | `H3Core` | The underlying [H3](https://github.com/h3js/h3) application instance. | +| `fetch` | `(req: Request) => Response \| Promise` | The app's internal fetch handler. | +| `captureError` | `(error: Error, context) => void` | Programmatically capture errors into the error hook pipeline. | + +## Nitro runtime hooks + +You can use Nitro [hooks](https://github.com/unjs/hookable) to extend the default runtime behaviour of Nitro by registering custom functions to the lifecycle events within plugins. + +**Example:** + +```ts +import { definePlugin } from "nitro"; + +export default definePlugin((nitroApp) => { + nitroApp.hooks.hook("close", async () => { + // Will run when nitro is being closed + }); +}) +``` + +### Available hooks + +| Hook | Signature | Description | +| --- | --- | --- | +| `request` | `(event: HTTPEvent) => void \| Promise` | Called at the start of each request. | +| `response` | `(res: Response, event: HTTPEvent) => void \| Promise` | Called after the response is created. | +| `error` | `(error: Error, context: { event?: HTTPEvent, tags?: string[] }) => void` | Called when an error is captured. | +| `close` | `() => void` | Called when the Nitro server is shutting down. | + +> [!NOTE] +> The `NitroRuntimeHooks` interface is augmentable. Deployment presets (such as Cloudflare) can extend it with platform-specific hooks like `cloudflare:scheduled` and `cloudflare:email`. + +### Unregistering hooks + +The `hook()` method returns an unregister function that can be called to remove the hook: + +```ts +import { definePlugin } from "nitro"; + +export default definePlugin((nitroApp) => { + const unregister = nitroApp.hooks.hook("request", (event) => { + // ... + }); + + // Later, remove the hook + unregister(); +}); +``` + +## Examples + +### Capturing errors + +You can use plugins to capture all application errors. + +```ts +import { definePlugin } from "nitro"; + +export default definePlugin((nitroApp) => { + nitroApp.hooks.hook("error", async (error, { event }) => { + console.error(`${event?.path} Application error:`, error) + }); +}) +``` + +The `context` object includes an optional `tags` array that identifies the error source (e.g., `"request"`, `"response"`, `"cache"`, `"plugin"`, `"unhandledRejection"`, `"uncaughtException"`). + +### Programmatic error capture + +You can use `captureError` to manually feed errors into the error hook pipeline: + +```ts +import { definePlugin } from "nitro"; + +export default definePlugin((nitroApp) => { + nitroApp.captureError(new Error("something went wrong"), { + tags: ["startup"], + }); +}); +``` + +### Graceful shutdown + +Server will gracefully shutdown and wait for any background pending tasks initiated by `event.waitUntil`. + +```ts +import { definePlugin } from "nitro"; + +export default definePlugin((nitroApp) => { + nitroApp.hooks.hook("close", async () => { + // Clean up resources, close connections, etc. + }); +}); +``` + +### Request and response lifecycle + +You can use plugins to register hooks that run on the request lifecycle: + +```ts +import { definePlugin } from "nitro"; + +export default definePlugin((nitroApp) => { + nitroApp.hooks.hook("request", (event) => { + console.log("on request", event.path); + }); + + nitroApp.hooks.hook("response", (res, event) => { + // Modify or inspect the response + console.log("on response", res.status); + }); +}); +``` + +### Modifying response headers + +```ts +import { definePlugin } from "nitro"; + +export default definePlugin((nitroApp) => { + nitroApp.hooks.hook("response", (res, event) => { + const { pathname } = new URL(event.req.url); + if (pathname.endsWith(".css") || pathname.endsWith(".js")) { + res.headers.append("Vary", "Origin"); + } + }); +}); +``` diff --git a/docs/1.docs/50.tasks.md b/docs/1.docs/50.tasks.md new file mode 100644 index 0000000000..0ca1191e35 --- /dev/null +++ b/docs/1.docs/50.tasks.md @@ -0,0 +1,282 @@ +--- +icon: codicon:run-all +--- + +# Tasks + +> Nitro tasks allow on-off operations in runtime. + +## Opt-in to the experimental feature + +> [!IMPORTANT] +> Tasks support is currently experimental. +> See [nitrojs/nitro#1974](https://github.com/nitrojs/nitro/issues/1974) for the relevant discussion. + +In order to use the tasks API you need to enable experimental feature flag. + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + experimental: { + tasks: true + } +}) +``` + +## Define tasks + +Tasks can be defined in `tasks/[name].ts` files. + +Nested directories are supported. The task name will be joined with `:`. (Example: `tasks/db/migrate.ts` task name will be `db:migrate`) + +**Example:** + +```ts [tasks/db/migrate.ts] +export default defineTask({ + meta: { + name: "db:migrate", + description: "Run database migrations", + }, + run({ payload, context }) { + console.log("Running DB migration task..."); + return { result: "Success" }; + }, +}); +``` + +### Task interface + +The `defineTask` helper accepts an object with the following properties: + +- **`meta`** (optional): An object with optional `name` and `description` string fields used for display in the dev server and CLI. +- **`run`** (required): A function that receives a [`TaskEvent`](#taskevent) and returns (or resolves to) an object with an optional `result` property. + +```ts +interface Task { + meta?: { name?: string; description?: string }; + run(event: TaskEvent): { result?: RT } | Promise<{ result?: RT }>; +} +``` + +### `TaskEvent` + +The `run` function receives a `TaskEvent` object with the following properties: + +- **`name`**: The name of the task being executed. +- **`payload`**: An object (`Record`) containing any data passed to the task. +- **`context`**: A `TaskContext` object (may include `waitUntil` depending on the runtime). + +```ts +interface TaskEvent { + name: string; + payload: TaskPayload; + context: TaskContext; +} +``` + +### Registering tasks via config + +In addition to file-based scanning, tasks can be registered directly in the Nitro config. This is useful for tasks provided by modules or pointing to custom handler paths. + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + experimental: { + tasks: true + }, + tasks: { + "db:migrate": { + handler: "./tasks/custom-migrate.ts", + description: "Run database migrations" + } + } +}) +``` + +If a task is both scanned from the `tasks/` directory and defined in the config, the config-defined `handler` takes precedence. + +## Scheduled tasks + +You can define scheduled tasks using Nitro configuration to automatically run after each period of time. + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + scheduledTasks: { + // Run `cms:update` task every minute + '* * * * *': ['cms:update'], + // Run a single task (string shorthand) + '0 * * * *': 'db:cleanup' + } +}) +``` + +The `scheduledTasks` config maps cron expressions to either a single task name (string) or an array of task names. When multiple tasks are assigned to the same cron expression, they run in parallel. + +> [!TIP] +> You can use [crontab.guru](https://crontab.guru/) to easily generate and understand cron tab patterns. + +When a scheduled task runs, it automatically receives a `payload` with `scheduledTime` set to the current timestamp (`Date.now()`). + +### Platform support + +- **`dev`**, **`node_server`**, **`node_cluster`**, **`node_middleware`**, **`bun`** and **`deno_server`** presets are supported with the [croner](https://croner.56k.guru/) engine. +- **`cloudflare_module`** and **`cloudflare_pages`** presets have native integration with [Cron Triggers](https://developers.cloudflare.com/workers/configuration/cron-triggers/). Nitro automatically generates the cron triggers in the wrangler config at build time - no manual wrangler setup required. +- **`vercel`** preset has native integration with [Vercel Cron Jobs](https://vercel.com/docs/cron-jobs). Nitro automatically generates the cron job configuration at build time - no manual `vercel.json` setup required. You can secure cron endpoints by setting the `CRON_SECRET` environment variable. +- More presets (with native primitives support) are planned to be supported! + +## `waitUntil` + +When running background tasks, you might want to make sure the server or worker waits until the task is done. + +An optional `context.waitUntil` function _might_ be available depending on the runtime. + +```ts +export default defineTask({ + run({ context }) { + const promise = fetch(...) + context.waitUntil?.(promise); + await promise; + return { result: "Success" }; + }, +}); +``` + +## Programmatically run tasks + +To manually run tasks, you can use `runTask(name, { payload?, context? })` utility from `nitro/task`. + +**Example:** + +```ts [api/migrate.ts] +import { defineHandler } from "nitro"; + +export default defineHandler(async (event) => { + // IMPORTANT: Authenticate user and validate payload! + const payload = Object.fromEntries(event.url.searchParams); + const { result } = await runTask("db:migrate", { payload }); + + return { result }; +}); +``` + +### Error handling + +`runTask` throws an HTTP error if: + +- The task does not exist (status `404`). +- The task has no handler implementation (status `501`). + +Any errors thrown inside the task's `run` function will propagate to the caller. + +## Run tasks with dev server + +Nitro's built-in dev server exposes tasks to be easily executed without programmatic usage. + +### Using API routes + +#### `/_nitro/tasks` + +This endpoint returns a list of available task names and their meta. + +```json +// [GET] /_nitro/tasks +{ + "tasks": { + "db:migrate": { + "description": "Run database migrations" + }, + "cms:update": { + "description": "Update CMS content" + } + }, + "scheduledTasks": [ + { + "cron": "* * * * *", + "tasks": [ + "cms:update" + ] + } + ] +} +``` + +#### `/_nitro/tasks/:name` + +This endpoint executes a task. You can provide a payload using both query parameters and body JSON payload. The payload sent in the JSON body payload must be under the `"payload"` property. + +::code-group +```ts [tasks/echo/payload.ts] +export default defineTask({ + meta: { + name: "echo:payload", + description: "Returns the provided payload", + }, + run({ payload, context }) { + console.log("Running echo task..."); + return { result: payload }; + }, +}); +``` +```json [GET] +// [GET] /_nitro/tasks/echo:payload?field=value&array=1&array=2 +{ + "field": "value", + "array": ["1", "2"] +} +``` +```json [POST] +/** + * [POST] /_nitro/tasks/echo:payload?field=value + * body: { + * "payload": { + * "answer": 42, + * "nested": { + * "value": true + * } + * } + * } + */ +{ + "field": "value", + "answer": 42, + "nested": { + "value": true + } +} +``` +:: + +> [!NOTE] +> The JSON payload included in the body will overwrite the keys present in the query params. + +### Using CLI + +> [!IMPORTANT] +> It is only possible to run these commands while the **dev server is running**. You should run them in a second terminal. + +#### List tasks + +```sh +nitro task list +``` + +#### Run a task + +```sh +nitro task run db:migrate --payload "{}" +``` + +The `--payload` flag accepts a JSON string that will be parsed and passed to the task. If the value is not a valid JSON object, the task runs without a payload. + +## Notes + +### Concurrency + +Each task can have **one running instance**. Calling a task of same name multiple times in parallel, results in calling it once and all callers will get the same return value. + +> [!NOTE] +> Nitro tasks can be running multiple times and in parallel. diff --git a/docs/1.docs/6.server-entry.md b/docs/1.docs/6.server-entry.md new file mode 100644 index 0000000000..4fba01467b --- /dev/null +++ b/docs/1.docs/6.server-entry.md @@ -0,0 +1,234 @@ +--- +icon: ri:server-line +navigation: + title: Server Entry +--- + +# Nitro Server Entry + +> Use a server entry to create a global middleware that runs for all routes before they are matched. + +The server entry is a special handler in Nitro that acts as a global middleware, running for every incoming request before routes are matched. It's commonly used for cross-cutting concerns like authentication, logging, request preprocessing, or creating custom routing logic. + +## Auto-detected `server.ts` + +By default, Nitro automatically looks for a `server.ts` (or `.js`, `.mjs`, `.mts`, `.tsx`, `.jsx`) file in your project root directory. + +If found, Nitro will use it as the server entry and run it for all incoming requests. + +::code-group +```ts [server.ts] +export default { + async fetch(req: Request) { + const url = new URL(req.url); + + // Handle specific routes + if (url.pathname === "/health") { + return new Response("OK", { + status: 200, + headers: { "content-type": "text/plain" } + }); + } + + // Add custom headers to all requests + // Return nothing to continue to the next handler + } +} +``` +```ts [routes/api/hello.ts] +import { defineHandler } from "nitro"; + +export default defineHandler((event) => { + return { hello: "API" }; +}); +``` +:: + +::tip +When `server.ts` is detected, Nitro will log in the terminal: `Detected \`server.ts\` as server entry.` +:: + +With this setup: +- `/health` → Handled by server entry (returns a response) +- `/api/hello` → Handled by the API route handler directly +- `/about`, etc. → Server entry runs first, then continues to the renderer if no response is returned + +## Framework compatibility + +The server entry is a great way to integrate with other frameworks. Any framework that exposes a standard Web `fetch(request: Request): Response` interface can be used as a server entry. + +### Web-compatible frameworks + +Frameworks that implement the Web `fetch` API work directly with `server.ts`: + +::tabs + ::tabs-item{label="H3" icon="i-undocs-h3"} + ```ts [server.ts] + import { H3 } from "h3"; + + const app = new H3() + + app.get("/", () => "⚡️ Hello from H3!"); + + export default app; + ``` + :: + ::tabs-item{label="Hono" icon="i-undocs-hono"} + ```ts [server.ts] + import { Hono } from "hono"; + + const app = new Hono(); + + app.get("/", (c) => c.text("🔥 Hello from Hono!")); + + export default app; + ``` + :: + ::tabs-item{label="Elysia" icon="i-undocs-elysia"} + ```ts [server.ts] + import { Elysia } from "elysia"; + + const app = new Elysia(); + + app.get("/", () => "🦊 Hello from Elysia!"); + + export default app.compile(); + ``` + :: +:: + +### Node.js frameworks + +For Node.js frameworks that use `(req, res)` style handlers (like [Express](https://expressjs.com/) or [Fastify](https://fastify.dev/)), name your server entry file `server.node.ts` instead of `server.ts`. Nitro will automatically detect the `.node.` suffix and convert the Node.js handler to a web-compatible fetch handler using [`srvx`](https://srvx.h3.dev/). + +::tabs + ::tabs-item{label="Express"} + ```ts [server.node.ts] + import Express from "express"; + + const app = Express(); + + app.use("/", (_req, res) => { + res.send("Hello from Express with Nitro!"); + }); + + export default app; + ``` + :: + ::tabs-item{label="Fastify"} + ```ts [server.node.ts] + import Fastify from "fastify"; + + const app = Fastify(); + + app.get("/", () => "Hello, Fastify with Nitro!"); + + await app.ready(); + + export default app.routing; + ``` + :: +:: + + +## Configuration + +### Custom server entry file + +You can specify a custom server entry file using the `serverEntry` option in your Nitro configuration: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + serverEntry: "./nitro.server.ts" +}) +``` + +You can also provide an object with `handler` and `format` options: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + serverEntry: { + handler: "./server.ts", + format: "node" // "web" (default) or "node" + } +}) +``` + +### Handler format + +The `format` option controls how Nitro treats the default export of your server entry: + +- **`"web"`** (default) — Expects a Web-compatible handler with a `fetch(request: Request): Response` method. +- **`"node"`** — Expects a Node.js-style `(req, res)` handler. Nitro automatically converts it to a web-compatible handler. + +When auto-detecting, the format is determined by the filename: `server.node.ts` uses `"node"` format, while `server.ts` uses `"web"` format. + +### Disabling server entry + +Set `serverEntry` to `false` to disable auto-detection and prevent Nitro from using any server entry: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + serverEntry: false +}) +``` + +## Using event handler + +You can also export an event handler using `defineHandler` for better type inference and access to the h3 event object: + +```ts [server.ts] +import { defineHandler } from "nitro"; + +export default defineHandler((event) => { + // Add custom context + event.context.requestId = crypto.randomUUID(); + event.context.timestamp = Date.now(); + + // Log the request + console.log(`[${event.context.requestId}] ${event.method} ${event.path}`); + + // Continue to the next handler (don't return anything) +}); +``` + +::important +If your server entry returns `undefined` or doesn't return anything, the request will continue to be processed by routes and the renderer. If it returns a response, the request lifecycle stops there. +:: + +## Request lifecycle + +The server entry is registered as a catch-all (`/**`) route handler. When a specific route (like `/api/hello`) matches a request, that route handler takes priority. For requests that don't match any specific route, the server entry runs before the renderer: + +```md +1. Server hook: `request` +2. Route rules (headers, redirects, etc.) +3. Global middleware (middleware/) +4. Route matching: + a. Specific routes (routes/) ← if matched, handles the request + b. Server entry ← runs for unmatched routes + c. Renderer (renderer.ts or index.html) +``` + +When both a server entry and a renderer exist, they are chained: the server entry runs first, and if it doesn't return a response, the renderer handles the request. + +## Development mode + +During development, Nitro watches for changes to your server entry file. When the file is created, modified, or deleted, the dev server automatically reloads to pick up the changes. + +## Best practices + +- Use server entry for cross-cutting concerns that affect **all routes** +- Return `undefined` to continue processing, return a response to terminate +- Keep server entry logic lightweight for better performance +- Use global middleware for modular concerns instead of one large server entry +- Consider using [Nitro plugins](/docs/plugins) for initialization logic +- Avoid heavy computation in server entry (it runs for every request) +- Don't use server entry for route-specific logic (use route handlers instead as they are more performant) + diff --git a/docs/1.docs/7.cache.md b/docs/1.docs/7.cache.md new file mode 100644 index 0000000000..deeb7bc98b --- /dev/null +++ b/docs/1.docs/7.cache.md @@ -0,0 +1,377 @@ +--- +icon: ri:speed-line +--- + +# Cache + +> Nitro provides a caching system built on top of the storage layer, powered by [ocache](https://github.com/unjs/ocache). + +## Cached handlers + +To cache an event handler, you simply need to use the `defineCachedHandler` method. + +It works like `defineHandler` but with an second parameter for the [cache options](#options). + +```ts [routes/cached.ts] +import { defineCachedHandler } from "nitro/cache"; + +export default defineCachedHandler((event) => { + return "I am cached for an hour"; +}, { maxAge: 60 * 60 }); +``` + +With this example, the response will be cached for 1 hour and a stale value will be sent to the client while the cache is being updated in the background. If you want to immediately return the updated response set `swr: false`. + +See the [options](#options) section for more details about the available options. + + +::important +**Request headers are dropped** when handling cached responses. Use the [`varies` option](#options) to consider specific headers when caching and serving the responses. +:: + +### Automatic HTTP headers + +When using `defineCachedHandler`, Nitro automatically manages HTTP cache headers on cached responses: + +- **`etag`** -- A weak ETag (`W/"..."`) is generated from the response body hash if not already set by the handler. +- **`last-modified`** -- Set to the current time when the response is first cached, if not already set. +- **`cache-control`** -- Automatically set based on the `swr`, `maxAge`, and `staleMaxAge` options: + - With `swr: true`: `s-maxage=, stale-while-revalidate=` + - With `swr: false`: `max-age=` + +### Conditional requests (304 Not Modified) + +Cached handlers automatically support conditional requests. When a client sends `if-none-match` or `if-modified-since` headers matching the cached response, Nitro returns a `304 Not Modified` response without a body. + +### Request method filtering + +Only `GET` and `HEAD` requests are cached. All other HTTP methods (`POST`, `PUT`, `DELETE`, etc.) automatically bypass the cache and call the handler directly. + +### Request deduplication + +When multiple concurrent requests hit the same cache key while the cache is being resolved, only one invocation of the handler runs. All concurrent requests wait for and share the same result. + +## Cached functions + +You can also cache a function using the `defineCachedFunction` function. This is useful for caching the result of a function that is not an event handler, but is part of one, and reusing it in multiple handlers. + +For example, you might want to cache the result of an API call for one hour: + +```ts [routes/api/stars/[...repo\\].ts] +import { defineCachedFunction } from "nitro/cache"; +import { defineHandler, type H3Event } from "nitro"; + +export default defineHandler(async (event) => { + const { repo } = event.context.params; + const stars = await cachedGHStars(repo).catch(() => 0) + + return { repo, stars } +}); + +const cachedGHStars = defineCachedFunction(async (repo: string) => { + const data = await fetch(`https://api.github.com/repos/${repo}`).then(res => res.json()); + + return data.stargazers_count; +}, { + maxAge: 60 * 60, + name: "ghStars", + getKey: (repo: string) => repo +}); +``` + +The stars will be cached in development inside `.nitro/cache/functions/ghStars//.json` with `value` being the number of stars. + +```json +{"expires":1677851092249,"value":43991,"mtime":1677847492540,"integrity":"ZUHcsxCWEH"} +``` + +::important +Because the cached data is serialized to JSON, it is important that the cached function does not return anything that cannot be serialized, such as Symbols, Maps, Sets... +:: + +::callout + If you are using edge workers to host your application, you should follow the instructions below. + ::collapsible{name="Edge workers instructions"} + In edge workers, the instance is destroyed after each request. Nitro automatically uses `event.waitUntil` to keep the instance alive while the cache is being updated while the response is sent to the client. + + To ensure that your cached functions work as expected in edge workers, **you should always pass the `event` as the first argument to the function using `defineCachedFunction`.** + + ```ts [routes/api/stars/[...repo\\].ts] {5,10,17} + import { defineCachedFunction } from "nitro/cache"; + + + export default defineHandler(async (event) => { + const { repo } = event.context.params; + const stars = await cachedGHStars(event, repo).catch(() => 0) + + return { repo, stars } + }); + + const cachedGHStars = defineCachedFunction(async (event: H3Event, repo: string) => { + const data = await fetch(`https://api.github.com/repos/${repo}`).then(res => res.json()); + + return data.stargazers_count; + }, { + maxAge: 60 * 60, + name: "ghStars", + getKey: (event: H3Event, repo: string) => repo + }); + ``` + + This way, the function will be able to keep the instance alive while the cache is being updated without slowing down the response to the client. + :: +:: + +## Using route rules + +This feature enables you to add caching routes based on a glob pattern directly in the main configuration file. This is especially useful to have a global cache strategy for a part of your application. + +Cache all the blog routes for 1 hour with `stale-while-revalidate` behavior: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + routeRules: { + "/blog/**": { cache: { maxAge: 60 * 60 } }, + }, +}); +``` + +If we want to use a [custom cache storage](#cache-storage) mount point, we can use the `base` option. + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + storage: { + redis: { + driver: "redis", + url: "redis://localhost:6379", + }, + }, + routeRules: { + "/blog/**": { cache: { maxAge: 60 * 60, base: "redis" } }, + }, +}); +``` + +### Route rules shortcuts + +You can use the `swr` shortcut for enabling `stale-while-revalidate` caching on route rules. When set to `true`, SWR is enabled with the default `maxAge`. When set to a number, it is used as the `maxAge` value in seconds. + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + routeRules: { + "/blog/**": { swr: true }, + "/api/**": { swr: 3600 }, + }, +}); +``` + +To explicitly disable caching on a route, set `cache: false`: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + routeRules: { + "/api/realtime/**": { cache: false }, + }, +}); +``` + +::note +When using route rules, cached handlers use the group `'nitro/route-rules'` instead of the default `'nitro/handlers'`. +:: + +## Cache storage + +Nitro stores the data in the `cache` storage mount point. + +- In production, it will use the [memory driver](https://unstorage.unjs.io/drivers/memory) by default. +- In development, it will use the [filesystem driver](https://unstorage.unjs.io/drivers/fs), writing to a temporary dir (`.nitro/cache`). + +To overwrite the production storage, set the `cache` mount point using the `storage` option: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + storage: { + cache: { + driver: 'redis', + /* redis connector options */ + } + } +}) +``` + +In development, you can also overwrite the cache mount point using the `devStorage` option: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + storage: { + cache: { + // production cache storage + }, + }, + devStorage: { + cache: { + // development cache storage + } + } +}) +``` + +## Options + +The `defineCachedHandler` and `defineCachedFunction` functions accept the following options: + +### Shared options + +These options are available for both `defineCachedHandler` and `defineCachedFunction`: + +::field-group + ::field{name="base" type="string"} + Name of the storage mountpoint to use for caching. :br + Default to `cache`. + :: + ::field{name="name" type="string"} + Guessed from function name if not provided, and falls back to `'_'` otherwise. + :: + ::field{name="group" type="string"} + Defaults to `'nitro/handlers'` for handlers and `'nitro/functions'` for functions. + :: + ::field{name="getKey()" type="(...args) => string"} + A function that accepts the same arguments as the original function and returns a cache key (`String`). :br + If not provided, a built-in hash function will be used to generate a key based on the function arguments. For cached handlers, the key is derived from the request URL path and search params. + :: + ::field{name="integrity" type="string"} + A value that invalidates the cache when changed. :br + By default, it is computed from **function code**, used in development to invalidate the cache when the function code changes. + :: + ::field{name="maxAge" type="number"} + Maximum age that cache is valid, in seconds. :br + Default to `1` (second). + :: + ::field{name="staleMaxAge" type="number"} + Maximum age that a stale cache is valid, in seconds. If set to `-1` a stale value will still be sent to the client while the cache updates in the background. :br + Defaults to `0` (disabled). + :: + ::field{name="swr" type="boolean"} + Enable `stale-while-revalidate` behavior to serve a stale cached response while asynchronously revalidating it. :br + When enabled, stale cached values are returned immediately while revalidation happens in the background. When disabled, the caller waits for the fresh value before responding (the stale entry is cleared). :br + Defaults to `true`. + :: + ::field{name="shouldInvalidateCache()" type="(...args) => boolean | Promise"} + A function that returns a `boolean` to invalidate the current cache and create a new one. + :: + ::field{name="shouldBypassCache()" type="(...args) => boolean | Promise"} + A function that returns a `boolean` to bypass the current cache without invalidating the existing entry. + :: + ::field{name="onError()" type="(error: unknown) => void"} + A custom error handler called when the cached function throws. :br + By default, errors are logged to the console and captured by the Nitro error handler. + :: +:: + +### Handler-only options + +These options are only available for `defineCachedHandler`: + +::field-group + ::field{name="headersOnly" type="boolean"} + When `true`, skip full response caching and only handle conditional request headers (`if-none-match`, `if-modified-since`) for `304 Not Modified` responses. The handler is called on every request but benefits from conditional caching. + :: + ::field{name="varies" type="string[]"} + An array of request header names to vary the cache key on. Headers listed here are preserved on the request during cache resolution and included in the cache key, making the cache unique per combination of header values. :br :br + Headers **not** listed in `varies` are stripped from the request before calling the handler to ensure consistent cache hits. :br :br + For multi-tenant environments, you may want to pass `['host', 'x-forwarded-host']` to ensure these headers are not discarded and that the cache is unique per tenant. + :: +:: + +### Function-only options + +These options are only available for `defineCachedFunction`: + +::field-group + ::field{name="transform()" type="(entry: CacheEntry, ...args) => any"} + Transform the cache entry before returning. The return value replaces the cached value. + :: + ::field{name="validate()" type="(entry: CacheEntry, ...args) => boolean"} + Validate a cache entry. Return `false` to treat the entry as invalid and trigger re-resolution. + :: +:: + +## SWR behavior + +The `stale-while-revalidate` (SWR) pattern is enabled by default (`swr: true`). Understanding how it interacts with other options: + +| `swr` | `maxAge` | Behavior | +|-------|----------|----------| +| `true` (default) | `1` (default) | Cache for 1 second, serve stale while revalidating | +| `true` | `3600` | Cache for 1 hour, serve stale while revalidating | +| `false` | `3600` | Cache for 1 hour, wait for fresh value when expired | +| `true` | `3600` with `staleMaxAge: 600` | Cache for 1 hour, serve stale for up to 10 minutes while revalidating | + +When `swr` is enabled and a cached value exists but has expired: +1. The stale cached value is returned immediately to the client. +2. The function/handler is called in the background to refresh the cache. +3. On edge workers, `event.waitUntil` is used to keep the background refresh alive. + +When `swr` is disabled and a cached value has expired: +1. The stale entry is cleared. +2. The client waits for the function/handler to resolve with a fresh value. + +## Cache keys and invalidation + +When using the `defineCachedFunction` or `defineCachedHandler` functions, the cache key is generated using the following pattern: + +```ts +`${options.base}:${options.group}:${options.name}:${options.getKey(...args)}.json` +``` + +For example, the following function: + +```ts +import { defineCachedFunction } from "nitro/cache"; + +const getAccessToken = defineCachedFunction(() => { + return String(Date.now()) +}, { + maxAge: 10, + name: "getAccessToken", + getKey: () => "default" +}); +``` + +Will generate the following cache key: + +```ts +cache:nitro/functions:getAccessToken:default.json +``` + +You can invalidate the cached function entry with: + +```ts +import { useStorage } from "nitro/storage"; + +await useStorage('cache').removeItem('nitro/functions:getAccessToken:default.json') +``` + +::note +For cached handlers, the cache key includes a hash of the URL path and, when using the [`varies`](#handler-only-options) option, hashes of the specified header values appended to the key. +:: + +::note +Responses with HTTP status codes `>= 400` or with an undefined body are not cached. This prevents caching error responses. +:: + +::read-more{to="/docs/storage"} +Read more about the Nitro storage. +:: diff --git a/docs/1.docs/8.storage.md b/docs/1.docs/8.storage.md new file mode 100644 index 0000000000..b23c88e7db --- /dev/null +++ b/docs/1.docs/8.storage.md @@ -0,0 +1,262 @@ +--- +icon: carbon:datastore +--- + +# KV Storage + +> Nitro provides a built-in storage layer that can abstract filesystem or database or any other data source. + +Nitro has built-in integration with [unstorage](https://unstorage.unjs.io) to provide a runtime agnostic persistent layer. + +## Usage + +To use the storage layer, you can use the `useStorage()` utility to access the storage instance. + +```ts +import { useStorage } from "nitro/storage"; + +// Default storage (in-memory) +await useStorage().setItem("test:foo", { hello: "world" }); +const value = await useStorage().getItem("test:foo"); + +// You can specify a base prefix with useStorage(base) +const testStorage = useStorage("test"); +await testStorage.setItem("foo", { hello: "world" }); +await testStorage.getItem("foo"); // { hello: "world" } + +// You can use generics to type the return value +await useStorage<{ hello: string }>("test").getItem("foo"); +await useStorage("test").getItem<{ hello: string }>("foo"); +``` + +:read-more{to="https://unstorage.unjs.io"} + +### Available methods + +The storage instance returned by `useStorage()` provides the following methods: + +| Method | Description | +|---|---| +| `getItem(key)` | Get the value of a key. Returns `null` if the key does not exist. | +| `getItems(items)` | Get multiple items at once. Accepts an array of keys or `{ key, options }` objects. | +| `getItemRaw(key)` | Get the raw value of a key without parsing. Useful for binary data. | +| `setItem(key, value)` | Set the value of a key. | +| `setItems(items)` | Set multiple items at once. Accepts an array of `{ key, value }` objects. | +| `setItemRaw(key, value)` | Set the raw value of a key without serialization. | +| `hasItem(key)` | Check if a key exists. Returns a boolean. | +| `removeItem(key)` | Remove a key from storage. | +| `getKeys(base?)` | Get all keys, optionally filtered by a base prefix. | +| `clear(base?)` | Clear all keys, optionally filtered by a base prefix. | +| `getMeta(key)` | Get metadata for a key (e.g., `mtime`, `atime`, `ttl`). | +| `setMeta(key, meta)` | Set metadata for a key. | +| `removeMeta(key)` | Remove metadata for a key. | +| `mount(base, driver)` | Dynamically mount a storage driver at a base path. | +| `unmount(base)` | Unmount a storage driver from a base path. | +| `watch(callback)` | Watch for changes. Callback receives `(event, key)` where event is `"update"` or `"remove"`. | +| `unwatch()` | Stop watching for changes. | + +Shorthand aliases are also available: `get`, `set`, `has`, `del`, `remove`, `keys`. + +```ts +import { useStorage } from "nitro/storage"; + +// Get all keys under a prefix +const keys = await useStorage("test").getKeys(); + +// Check if a key exists +const exists = await useStorage().hasItem("test:foo"); + +// Remove a key +await useStorage().removeItem("test:foo"); + +// Get raw binary data +const raw = await useStorage().getItemRaw("assets/server:image.png"); + +// Get metadata (type, etag, mtime, etc.) +const meta = await useStorage("assets/server").getMeta("file.txt"); +``` + +## Configuration + +You can mount one or multiple custom storage drivers using the `storage` option. + +The key is the mount point name, and the value is the driver name and configuration. + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + storage: { + redis: { + driver: "redis", + /* redis connector options */ + } + } +}) +``` + +Then, you can use the redis storage using the `useStorage("redis")` function. + +::read-more{to="https://unstorage.unjs.io/"} +You can find the driver list on [unstorage documentation](https://unstorage.unjs.io/) with their configuration. +:: + +### Development storage + +You can use the `devStorage` option to override storage configuration during development and prerendering. + +This is useful when your production driver is not available in development (e.g., a managed Redis instance). + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + storage: { + db: { + driver: "redis", + host: "prod.example.com", + } + }, + devStorage: { + db: { + driver: "fs", + base: "./.data/db" + } + } +}) +``` + +When running in development mode, `devStorage` mounts are merged on top of `storage` mounts, allowing you to use a local filesystem driver or an in-memory driver while developing. + +## Built-in mount points + +Nitro automatically mounts the following storage paths: + +### `/assets` + +Server assets are mounted at the `/assets` base path. This mount point provides read-only access to bundled server assets (see [Server assets](#server-assets)). + +```ts +import { useStorage } from "nitro/storage"; + +// Access server assets via the /assets mount +const content = await useStorage("assets/server").getItem("my-file.txt"); +``` + +### Default (in-memory) + +The root storage (without a base path) uses an in-memory driver by default. Data stored here is not persisted across restarts. + +```ts +import { useStorage } from "nitro/storage"; + +// In-memory by default, not persisted +await useStorage().setItem("counter", 1); +``` + +To persist data, mount a driver with a persistent backend (e.g., `fs`, `redis`, etc.) using the `storage` configuration option. + +## Server assets + +Nitro allows you to bundle files from an `assets/` directory at the root of your project. These files are accessible at runtime via the `assets/server` storage mount. + +``` +my-project/ + assets/ + data.json + templates/ + welcome.html + server/ + routes/ + index.ts +``` + +```ts [server/routes/index.ts] +import { useStorage } from "nitro/storage"; + +export default defineHandler(async () => { + const serverAssets = useStorage("assets/server"); + + const keys = await serverAssets.getKeys(); + const data = await serverAssets.getItem("data.json"); + const template = await serverAssets.getItem("templates/welcome.html"); + + return { keys, data, template }; +}); +``` + +### Custom asset directories + +You can register additional asset directories using the `serverAssets` config option: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + serverAssets: [ + { + baseName: "templates", + dir: "./templates", + } + ] +}) +``` + +Custom asset directories are accessible under `assets/`: + +```ts +import { useStorage } from "nitro/storage"; + +const templates = useStorage("assets/templates"); +const keys = await templates.getKeys(); +const html = await templates.getItem("email.html"); +``` + +### Asset metadata + +Server assets include metadata such as content type, ETag, and modification time: + +```ts +import { useStorage } from "nitro/storage"; + +const serverAssets = useStorage("assets/server"); + +const meta = await serverAssets.getMeta("image.png"); +// { type: "image/png", etag: "\"...\"", mtime: "2024-01-01T00:00:00.000Z" } + +// Useful for setting response headers +const raw = await serverAssets.getItemRaw("image.png"); +``` + +::note +In development, server assets are read directly from the filesystem. In production, they are bundled and inlined into the build output. +:: + +## Runtime configuration + +In scenarios where the mount point configuration is not known until runtime, Nitro can dynamically add mount points during startup using [plugins](/docs/plugins). + +```ts [plugins/storage.ts] +import { useStorage } from "nitro/storage"; +import { definePlugin } from "nitro"; +import redisDriver from "unstorage/drivers/redis"; + +export default definePlugin(() => { + const storage = useStorage() + + // Dynamically pass in credentials from runtime configuration, or other sources + const driver = redisDriver({ + base: "redis", + host: process.env.REDIS_HOST, + port: process.env.REDIS_PORT, + /* other redis connector options */ + }) + + // Mount driver + storage.mount("redis", driver) +}) +``` + +::warning +This is a temporary workaround, with a better solution coming in the future! Keep a lookout on the GitHub issue [here](https://github.com/nitrojs/nitro/issues/1161#issuecomment-1511444675). +:: diff --git a/docs/1.docs/99.migration.md b/docs/1.docs/99.migration.md new file mode 100644 index 0000000000..52a7108290 --- /dev/null +++ b/docs/1.docs/99.migration.md @@ -0,0 +1,221 @@ +--- +icon: ri:arrow-right-up-line +--- + +# Migration Guide + +> [!NOTE] +> This is a living document for migrating from Nitro 2 to 3. Please check it regularly while using the beta version. + +Nitro v3 introduces intentional backward-incompatible changes. This guide helps you migrate from Nitro v2. + +## `nitropack` is renamed to `nitro` + +The NPM package [nitropack](https://www.npmjs.com/package/nitropack) (v2) has been renamed to [nitro](https://www.npmjs.com/package/nitro) (v3). + +**Migration:** Update the `nitropack` dependency to `nitro` in `package.json`: + +```diff [release channel] +{ + "dependencies": { +-- "nitropack": "latest" +++ "nitro": "latest" + } +} +``` +```diff [nightly channel] +{ + "dependencies": { +-- "nitropack": "latest" +++ "nitro": "npm:nitro-nightly" + } +} +``` + +**Migration:** Search your codebase and rename all instances of nitropack to nitro: + +```diff +-- import { defineNitroConfig } from "nitropack/config" +++ import { defineNitroConfig } from "nitro/config" +``` + +## nitro/runtime + +Runtime utils had been moved to individual `nitro/*` subpath exports. Refer to docs for usage. + +```diff +-- import { useStorage } from "nitropack/runtime/storage" +++ import { useStorage } from "nitro/storage" +``` + +## Minimum Supported Node.js Version: 20 + +Nitro now requires a minimum Node.js version of 20, as Node.js 18 reaches end-of-life in [April 2025](https://nodejs.org/en/about/previous-releases). + +Please upgrade to the [latest LTS](https://nodejs.org/en/download) version (>= 20). + +**Migration:** + +- Check your local Node.js version using `node --version` and update if necessary. +- If you use a CI/CD system for deployment, ensure that your pipeline is running Node.js 20 or higher. +- If your hosting provider manages the Node.js runtime, make sure it's set to version 20, 22, or later. + +## Type Imports + +Nitro types are now only exported from `nitro/types`. + +**Migration:** Import types from nitro/types instead of nitro: + +```diff +-- import { NitroRuntimeConfig } from "nitropack" +++ import { NitroRuntimeConfig } from "nitro/types" +``` + +## App Config Support Removed + +Nitro v2 supported a bundled app config that allowed defining configurations in `app.config.ts` and accessing them at runtime via `useAppConfig()`. + +This feature had been removed. + +**Migration:** + +Use a regular `.ts` file in your server directory and import it directly. + +## Preset updates + +Nitro presets have been updated for the latest compatibility. + +Some (legacy) presets have been removed or renamed. + +| Old Preset | New Preset | +|------------------------------|-------------------------------| +| `node` | `node_middleware` (export changed to `middleware`) | +| `cloudflare`, `cloudflare_worker`, `cloudflare_module_legacy` | `cloudflare_module` | +| `deno-server-legacy` | `deno_server` with Deno v2 | +| `netlify-builder` | `netlify` or `netlify_edge` | +| `vercel-edge` | `vercel` with Fluid compute enabled | +| `azure`, `azure_functions` | `azure_swa` | +| `firebase` | `firebase_app_hosting` | +| `iis` | `iis_handler` | +| `deno` | `deno_deploy` | +| `edgio` | Discontinued | +| `cli` | Removed due to lack of use | +| `service_worker` | Removed due to instability | + +## Cloudflare Bindings Access + +In Nitro v2, Cloudflare environment variables and bindings were accessible via `event.context.cloudflare.env`. + +In Nitro v3, the Cloudflare runtime context is attached to the request's runtime object instead. + +**Migration:** + +```diff +-- const { cloudflare } = event.context +-- const binding = cloudflare.env.MY_BINDING +++ const { env } = event.req.runtime.cloudflare +++ const binding = env.MY_BINDING +``` + +## Changed nitro subpath imports + +Nitro v2 introduced multiple subpath exports, some of which have been removed or updated: + +- `nitro/rollup`, `nitropack/core` (use `nitro/builder`) +- `nitropack/runtime/*` (use `nitro/*`) +- `nitropack/kit` (removed) +- `nitropack/presets` (removed) + +An experimental `nitropack/kit` was introduced but has now been removed. A standalone Nitro Kit package may be introduced in the future with clearer objectives. + +**Migration:** + +- Use `NitroModule` from `nitro/types` instead of `defineNitroModule` from the kit. +- Prefer built-in Nitro presets (external presets are only for evaluation purposes). + +## H3 v2 + +Nitro v3 upgrades to [H3 v2](https://h3.dev), which includes API changes. All H3 utilities are imported from `nitro/h3`. + +### Web Standards + +H3 v2 is rewritten based on web standard primitives ([`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL), [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers), [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request), and [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)). + +Access to `event.node.{req,res}` is only available in Node.js runtime. `event.web` is renamed to `event.req` (instance of web [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request)). + +### Response Handling + +You should always explicitly **return** the response body or **throw** an error: + +```diff +-- import { send, sendRedirect, sendStream } from "nitro/h3" +-- send(event, value) +-- sendStream(event, stream) +-- sendRedirect(event, location, code) +++ import { redirect } from "nitro/h3" +++ return value +++ return stream +++ return redirect(event, location, code) +``` + +Other changes: + +- `sendError(event, error)` → `throw createError(error)` +- `sendNoContent(event)` → `return noContent(event)` +- `sendProxy(event, target)` → `return proxy(event, target)` + +### Request Body + +Most body utilities can be replaced with native `event.req` methods: + +```diff +-- import { readBody, readRawBody, readFormData } from "nitro/h3" +++ // Use native Request methods +++ const json = await event.req.json() +++ const text = await event.req.text() +++ const formData = await event.req.formData() +++ const stream = event.req.body +``` + +### Headers + +H3 now uses standard web [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers). Header values are always plain `string` (no `null`, `undefined`, or `string[]`). + +```diff +-- import { getHeader, setHeader, getResponseStatus } from "nitro/h3" +-- getHeader(event, "x-foo") +-- setHeader(event, "x-foo", "bar") +++ event.req.headers.get("x-foo") +++ event.res.headers.set("x-foo", "bar") +++ event.res.status // instead of getResponseStatus(event) +``` + +### Handler Utils + +```diff +-- import { eventHandler, defineEventHandler } from "nitro/h3" +++ import { defineHandler } from "nitro" +``` + +- `lazyEventHandler` → `defineLazyEventHandler` +- `useBase` → `withBase` + +### Error Utils + +```diff +-- import { createError, isError } from "nitro/h3" +++ import { HTTPError } from "nitro" +++ throw new HTTPError({ status: 404, message: "Not found" }) +++ HTTPError.isError(error) +``` + +### Node.js Utils + +```diff +-- import { defineNodeListener, fromNodeMiddleware, toNodeListener } from "nitro/h3" +++ import { defineNodeHandler, fromNodeHandler, toNodeHandler } from "nitro/h3" +``` + +## Optional Hooks + +If you were using `useNitroApp().hooks` outside of Nitro plugins before, it might be undefined. Use new `useNitroHooks()` to guarantee having an instance. diff --git a/docs/1.docs/99.nightly.md b/docs/1.docs/99.nightly.md new file mode 100644 index 0000000000..e1284cd68b --- /dev/null +++ b/docs/1.docs/99.nightly.md @@ -0,0 +1,39 @@ +--- +icon: ri:moon-fill +--- + +# Nightly Channel + +> Nitro has a nightly release channel that automatically releases for every commit to `main` branch to try latest changes. + +You can opt-in to the nightly release channel by updating your `package.json`: + +```json +{ + "devDependencies": { + "nitro": "npm:nitro-nightly@latest" + } +} +``` + +Remove the lockfile (`package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`, `bun.lock`, or `bun.lockb`) and reinstall the dependencies. + + + +::important +When using **Bun as package manager** in a mono-repo, you need to make sure nitro package is properly hoisted. + +
+ +```toml [bunfig.toml] +[install] +publicHoistPattern = ["nitro*"] +``` + +:: + + +::important +Avoid using ` install nitro-nightly`; it does not install correctly. +If you encounter issues, delete your `node_modules` and lock files, then follow the steps above. +:: diff --git a/docs/1.guide/0.index.md b/docs/1.guide/0.index.md deleted file mode 100644 index 683cc906bf..0000000000 --- a/docs/1.guide/0.index.md +++ /dev/null @@ -1,105 +0,0 @@ ---- -icon: ph:book-open-duotone ---- - -# Getting Started - -> Create web servers with all necessary features and deploy them wherever you prefer. - -## Intro - -Nitro is an open source framework to build web servers using [unjs/h3](https://h3.unjs.io) and lots of built-in features. -Nitro automatically makes your code compatible with any [deployment](/deploy) provider and runtime! - -> [!NOTE] -> Nitro can be used standalone or as the server engine of full-stack frameworks such as [Nuxt](https://nuxt.com). - - -## Quick start - -> [!TIP] -> Instead of setting up a local development environment, you can use the [online playground](https://stackblitz.com/github/nitrojs/nitro/tree/main/examples/hello-world). - -::note -Make sure you have installed the recommended setup: - -- Latest LTS version of either [Node.js](https://nodejs.org/en), [Bun](https://bun.sh/), or [Deno](https://deno.com/). -- [Visual Studio Code](https://code.visualstudio.com/) -:: - -Create a new project using starter template: - -:pm-x{command="giget@latest nitro nitro-app --install"} - - -```sh -cd nitro-app -``` - -Start the development server: - -:pm-run{script="dev"} - -Nitro is ready at `http://localhost:3000/`! - -::tip -Check `.nitro/dev/index.mjs` if you want to know what is happening -:: - -Build your production-ready server: - -:pm-run{script="build"} - -Output is in the `.output` directory and ready to be deployed on almost any provider with no dependencies. - -You can try it locally with: - -:pm-run{script="preview"} - -::read-more -You can find more examples in the Nitro repository: [nitrojs/nitro/examples](https://github.com/nitrojs/nitro/tree/main/examples) -:: - -## Directory structure - -The starter template includes some important files to get you started. - -### `routes/` - -The `routes/` directory contains your application handlers. You can create subdirectories inside `routes/` dir to create nested handlers. The file name is the route path. - -:read-more{to="/guide/routing"} - -### `api/` - -The `api/` directory is similar to `routes/` with the only difference that routes inside it will be prefixed with `/api/` for convenience. - -:read-more{to="/guide/routing"} - -### `utils/` - -This directory contains your application utils with auto import support. - -:read-more{to="/guide/utils"} - -### `plugins/` - -This directory contains your custom nitro plugins. - -:read-more{to="/guide/plugins"} - -### `nitro.config.ts` - -The `nitro.config.ts` file contains the configuration for Nitro. - -:read-more{to="/guide/configuration"} - -### `tsconfig.json` - -The `tsconfig.json` file contains the TypeScript configuration for your project. - -:read-more{to="/guide/typescript"} - -### `package.json` - -The `package.json` file contains all the dependencies and scripts for your project. diff --git a/docs/1.guide/1.utils.md b/docs/1.guide/1.utils.md deleted file mode 100644 index 7d644fd72c..0000000000 --- a/docs/1.guide/1.utils.md +++ /dev/null @@ -1,137 +0,0 @@ ---- -icon: ri:tools-line ---- - -# Server Utils - -> Enjoy auto-imported server utils and extend with your own utils. - -## Auto imports - -When reading the rest of the docs, you might notice that there are no `imports` in examples for using utilities. -It is because Nitro uses [unjs/unimport](https://github.com/unjs/unimport) to auto import utilities when used with full tree-shaking support so you don't have to! - -## H3 utils - -Nitro enables all [h3 utils](https://h3.unjs.io/utils) as auto imports so you can use `defineEventHandler`, `readBody`, etc. without manually importing them. - -::read-more{title="H3 Docs" to="https://h3.unjs.io/utils"} -:: - - -### `utils` directory - -You can add your application specific utils inside `utils/` directory and they will be auto-imported when used. -Every export in the `utils` directory and its subdirectories will become available globally in your application. - - -**Example:** Create a `utils/sum.ts` file where a function `useSum` is exported: - -```ts [utils/sum.ts] -export function useSum(a: number, b: number) { return a + b } -``` - -Use it in your `routes/index.ts` file without importing it: - -```ts [routes/index.ts] -export default defineEventHandler(() => { - const sum = useSum(1, 2) // auto-imported - return { sum } -}) -``` - -## Nitro utils - -Nitro also exposes several built-in utils: - - - -- `defineCachedFunction(fn, options)`{lang=ts} / `cachedFunction(fn, options)`{lang=ts} -- `defineCachedEventHandler(handler, options)`{lang=ts} / `cachedEventHandler(handler, options)`{lang=ts} -- `defineRenderHandler(handler)`{lang=ts} -- `defineRouteMeta(options)`{lang=ts} (experimental) -- `useRuntimeConfig(event?)`{lang=ts} -- `useAppConfig(event?)`{lang=ts} -- `useStorage(base?)`{lang=ts} -- `useNitroApp()`{lang=ts} -- `defineNitroPlugin(plugin)`{lang=ts} -- `nitroPlugin(plugin)`{lang=ts} -- `getRouteRules(event)`{lang=ts} - -::read-more{to="https://github.com/nitrojs/nitro/blob/v2/src/core/config/resolvers/imports.ts#L58"} -Check [the source code](https://github.com/nitrojs/nitro/blob/v2/src/core/config/resolvers/imports.ts#L58) for list of available Nitro auto imports. -:: - -::read-more{to="/guide/typescript"} -The types are auto-generated for global auto-imports when running the `prepare` or `dev` command. See [TypeScript](/guide/typescript) guide, for IDE support. -:: - -## Manual imports - -For some edge cases (IDE support and libraries in `node_modules`) it is impossible to rely on auto imports. - -You can explicitly import them from virtual `#imports` file. - -> [!TIP] -> Manually importing from `#imports` still has benefits of tree-shaking. - -```js [plugins/test.ts] -import { useStorage } from '#imports' -``` - -## Async Context (Experimental) - -Nitro (2.6+) enables a new server development experience in order to split application logic into smaller "composable" utilities that are fully decoupled from each other and can directly access a shared context (request event) without needing it to be passed along. This pattern is inspired from [Vue Composition API](https://vuejs.org/guide/extras/composition-api-faq.html#why-composition-api) and powered by [unjs/unctx](https://github.com/unjs/unctx). - -::note -This feature is currently supported for Node.js and Bun runtimes and also coming soon to other presets that support [`AsyncLocalStorage`](https://nodejs.org/api/async_context.html#class-asynclocalstorage) interface. -:: - -In order to enable async context feature, you have to enable `asyncContext` flag: - -::code-group -```ts [nitro.config.ts] -export default defineNitroConfig({ - experimental: { - asyncContext: true - } -}); -``` -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - nitro: { - experimental: { - asyncContext: true - } - } -}) -``` -:: - -After enabling this flag, you can use `useEvent()` (auto imported) in any utility or composable to access the request event without manually passing it along: - -::code-group -```ts [with async context] -// routes/index.ts -export default defineEventHandler(async () => { - const user = await useAuth() -}) - -// utils/auth.ts -export function useAuth() { - return useSession(useEvent()) -} -``` -```ts [without async context] -// routes/index.ts -export default defineEventHandler(async (event) => { - const user = await useAuth(event) -}) - -// utils/auth.ts -export function useAuth(event) { - return useSession(event) -} -``` -:: - diff --git a/docs/1.guide/10.tasks.md b/docs/1.guide/10.tasks.md deleted file mode 100644 index b3d89fa224..0000000000 --- a/docs/1.guide/10.tasks.md +++ /dev/null @@ -1,221 +0,0 @@ ---- -icon: codicon:run-all ---- - -# Tasks - -> Nitro tasks allow on-off operations in runtime. - -## Opt-in to the experimental feature - -> [!IMPORTANT] -> Tasks support is currently experimental. -> See [nitrojs/nitro#1974](https://github.com/nitrojs/nitro/issues/1974) for the relevant discussion. - -In order to use the tasks API you need to enable experimental feature flag. - -::code-group -```ts [nitro.config.ts] -export default defineNitroConfig({ - experimental: { - tasks: true - } -}) -``` - -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - nitro: { - experimental: { - tasks: true - } - } -}) -``` -:: - - -## Define tasks - -Tasks can be defined in `tasks/[name].ts` files. - -Nested directories are supported. The task name will be joined with `:`. (Example: `tasks/db/migrate.ts`task name will be `db:migrate`) - -**Example:** - -```ts [tasks/db/migrate.ts] -export default defineTask({ - meta: { - name: "db:migrate", - description: "Run database migrations", - }, - run({ payload, context }) { - console.log("Running DB migration task..."); - return { result: "Success" }; - }, -}); -``` - -> [!NOTE] -> Use `server/tasks/db/migrate.ts` for Nuxt. - - -## Scheduled tasks - -You can define scheduled tasks using Nitro configuration to automatically run after each period of time. - -::code-group -```ts [nitro.config.ts] -export default defineNitroConfig({ - scheduledTasks: { - // Run `cms:update` task every minute - '* * * * *': ['cms:update'] - } -}) -``` - -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - nitro: { - scheduledTasks: { - // Run `cms:update` task every minute - '* * * * *': ['cms:update'] - } - } -}) -``` - -:: - -> [!TIP] -> You can use [crontab.guru](https://crontab.guru/) to easily generate and understand cron tab patterns. - -### Platform support - -- `dev`, `node-server`, `bun` and `deno-server` presets are supported with [croner](https://croner.56k.guru/) engine. -- `cloudflare_module` preset have native integration with [Cron Triggers](https://developers.cloudflare.com/workers/configuration/cron-triggers/). Make sure to configure wrangler to use exactly same patterns you define in `scheduledTasks` to be matched. -- More presets (with native primitives support) are planned to be supported! - -## Programmatically run tasks - -To manually run tasks, you can use `runTask(name, { payload? })` utility. - -**Example:** - -```ts -// api/migrate.ts -export default eventHandler(async (event) => { - // IMPORTANT: Authenticate user and validate payload! - const payload = { ...getQuery(event) }; - const { result } = await runTask("db:migrate", { payload }); - - return { result }; -}); -``` - -## Run tasks with dev server - -Nitro's built-in dev server exposes tasks to be easily executed without programmatic usage. - -### Using API routes - -#### `/_nitro/tasks` - -This endpoint returns a list of available task names and their meta. - -```json -// [GET] /_nitro/tasks -{ - "tasks": { - "db:migrate": { - "description": "Run database migrations" - }, - "cms:update": { - "description": "Update CMS content" - } - }, - "scheduledTasks": [ - { - "cron": "* * * * *", - "tasks": [ - "cms:update" - ] - } - ] -} -``` - -#### `/_nitro/tasks/:name` - -This endpoint executes a task. You can provide a payload using both query parameters and body JSON payload. The payload sent in the JSON body payload must be under the `"payload"` property. - -::code-group -```ts [tasks/echo/payload.ts] -export default defineTask({ - meta: { - name: "echo:payload", - description: "Returns the provided payload", - }, - run({ payload, context }) { - console.log("Running echo task..."); - return { result: payload }; - }, -}); -``` -```json [GET] -// [GET] /_nitro/tasks/echo:payload?field=value&array=1&array=2 -{ - "field": "value", - "array": ["1", "2"] -} -``` -```json [POST] -/** - * [POST] /_nitro/tasks/echo:payload?field=value - * body: { - * "payload": { - * "answer": 42, - * "nested": { - * "value": true - * } - * } - * } - */ -{ - "field": "value", - "answer": 42, - "nested": { - "value": true - } -} -``` -:: - -> [!NOTE] -> The JSON payload included in the body will overwrite the keys present in the query params. - -### Using CLI - -> [!IMPORTANT] -> It is only possible to run these commands while the **dev server is running**. You should run them in a second terminal. - -#### List tasks - -```sh -nitro task list -``` - -#### Run a task - -```sh -nitro task run db:migrate --payload "{}" -``` - -## Notes - -### Concurrency - -Each task can have **one running instance**. Calling a task of same name multiple times in parallel, results in calling it once and all callers will get the same return value. - -> [!NOTE] -> Nitro tasks can be running multiple times and in parallel. diff --git a/docs/1.guide/2.routing.md b/docs/1.guide/2.routing.md deleted file mode 100644 index c0b3ac80f0..0000000000 --- a/docs/1.guide/2.routing.md +++ /dev/null @@ -1,324 +0,0 @@ ---- -icon: ri:direction-line ---- - -# Server Routes - -> Nitro supports filesystem routing to automatically map files to h3 routes. - -## Event handlers - -An [event handler](https://h3.unjs.io/guide/event-handler) is a function that will be bound to a route and executed when the route is matched by the router for an incoming request. - -:read-more{to="https://h3.unjs.io/guide/event-handler"} - -## Filesystem routing - -Nitro supports file-based routing for your API routes (files are automatically mapped to [h3 routes](https://h3.unjs.io/guide/router)). Defining a route is as simple as creating a file inside the `api/` or `routes/` directory. - -You can only define one handler per files and you can [append the HTTP method](#specific-request-method) to the filename to define a specific request method. - -```md -api/ - test.ts <-- /api/test -routes/ - hello.get.ts <-- GET /hello - hello.post.ts <-- POST /hello -nitro.config.ts -``` - -You can nest routes by creating subdirectories. - -```md -routes/ - communities/ - index.get.ts - index.post.ts - [id]/ - index.get.ts - index.post.ts - hello.get.ts - hello.post.ts -``` - -::note -If you are using [Nuxt](https://nuxt.com), move the `server/api/` and `server/routes/` instead. -:: - -::tip -Some providers like Vercel use a top-level `api/` directory as a feature, therefore routes placed in `/api` won't work. -You will have to use `routes/api/`. -:: - -### Simple routes - -First, create a file in `routes/` or `api/` directory. The filename will be the route path. - -Then, export a function wrapped in `defineEventHandler` that will be executed when the route is matched. - -```ts [/api/test.ts] -export default defineEventHandler(() => { - return { hello: 'API' } -}) -``` - -### Route with params - -#### Single param - -To define a route with params, use the `[]` syntax where `` is the name of the param. The param will be available in the `event.context.params` object or using the `getRouterParam` utility from [unjs/h3](https://h3.unjs.io). - -```ts [/routes/hello/[name\\].ts] -export default defineEventHandler(event => { - const name = getRouterParam(event, 'name') - - return `Hello ${name}!` -}) -``` - -Call the route with the param `/hello/nitro`, you will get: - -```txt [Response] -Hello nitro! -``` - -#### Multiple params - -You can define multiple params in a route using `[]/[]` syntax where each param is a folder. You **cannot** define multiple params in a single filename of folder. - -```ts [/routes/hello/[name\\]/[age\\].ts] -export default defineEventHandler(event => { - const name = getRouterParam(event, 'name') - const age = getRouterParam(event, 'age') - - return `Hello ${name}! You are ${age} years old.` -}) -``` - -#### Catch all params - -You can capture all the remaining parts of a URL using `[...]` syntax. This will include the `/` in the param. - -```ts [/routes/hello/[...name\\].ts] -export default defineEventHandler(event => { - const name = getRouterParam(event, 'name') - - return `Hello ${name}!` -}) -``` - -Call the route with the param `/hello/nitro/is/hot`, you will get: - -```txt [Response] -Hello nitro/is/hot! -``` - -### Specific request method - -You can append the HTTP method to the filename to force the route to be matched only for a specific HTTP request method, for example `hello.get.ts` will only match for `GET` requests. You can use any HTTP method you want. - -::code-group -```js [GET] -// routes/users/[id].get.ts -export default defineEventHandler(async (event) => { - const id = getRouterParam(event, 'id') - - // Do something with id - - return `User profile!` -}) -``` - -```js [POST] -// routes/users.post.ts -export default defineEventHandler(async event => { - const body = await readBody(event) - - // Do something with body like saving it to a database - - return { updated: true } -}) -``` -:: - -### Catch all route - -You can create a special route that will match all routes that are not matched by any other route. This is useful for creating a default route. - -To create a catch all route, create a file named `[...].ts` in the `routes/` or `api/` directory or in any subdirectory. - -```ts [/routes/[...\\].ts] -export default defineEventHandler(event => { - const url = getRequestURL(event) - - return `Hello ${url}!` -}) -``` - -### Environment specific handlers - -You can specify for a route that will only be included in specific builds by adding a `.dev`, `.prod` or `.prerender` suffix to the file name, for example: `routes/test.get.dev.ts` or `routes/test.get.prod.ts`. - -> [!TIP] -> You can specify multiple environments or specify a preset name as environment using programmatic registration of routes via `handlers[]` config. - - -## Middleware - -Nitro route middleware can hook into the request lifecycle. - -::tip -A middleware can modify the request before it is processed, not after. -:: - -:read-more{to="https://h3.unjs.io/guide/event-handler#middleware"} - -Middleware are auto-registered within the `middleware/` directory. - -```md -routes/ - hello.ts -middleware/ - auth.ts - logger.ts - ... -nitro.config.ts -``` - -### Simple middleware - -Middleware are defined exactly like route handlers with the only exception that they should not return anything. -Returning from middleware behaves like returning from a request - the value will be returned as a response and further code will not be ran. - -```ts [middleware/auth.ts] -export default defineEventHandler((event) => { - // Extends or modify the event - event.context.user = { name: 'Nitro' } -}) -``` - -Middleware in `middleware/` directory are automatically registered for all routes. If you want to register a middleware for a specific route, see [Object Syntax Event Handler](https://h3.unjs.io/guide/event-handler#object-syntax). - -::note -Returning anything from a middleware will close the request and should be avoided! Any returned value from middleware will be the response and further code will not be executed however **this is not recommended to do!** -:: - -### Route Meta - -You can define route handler meta at build-time using `defineRouteMeta` macro in the event handler files. - -> [!IMPORTANT] -> 🚧 This feature is currently experimental. - -```ts [/api/test.ts] -defineRouteMeta({ - openAPI: { - tags: ["test"], - description: "Test route description", - parameters: [{ in: "query", name: "test", required: true }], - }, -}); - -export default defineEventHandler(() => "OK"); -``` - -::read-more{to="https://swagger.io/specification/v3/"} -This feature is currently usable to specify OpenAPI meta. See swagger specification for available OpenAPI options. -:: - -### Execution order - -Middleware are executed in directory listing order. - -```md -middleware/ - auth.ts <-- First - logger.ts <-- Second - ... <-- Third -``` - -Prefix middleware with a number to control their execution order. - -```md -middleware/ - 1.logger.ts <-- First - 2.auth.ts <-- Second - 3.... <-- Third -``` -::note -Remember that file names are sorted as strings, thus for example if you have 3 files `1.filename.ts`, `2.filename.ts` and `10.filename.ts`, the `10.filename.ts` will come after the `1.filename.ts`. To avoid this, prefix `1-9` with a `0` like `01`, if you have more than 10 middleware in the same directory. -:: - -### Request filtering - -Middleware are executed on every request. - -Apply custom logic to scope them to specific conditions. - -For example, you can use the URL to apply a middleware to a specific route: - -```ts [middleware/auth.ts] -export default defineEventHandler((event) => { - // Will only execute for /auth route - if (getRequestURL(event).pathname.startsWith('/auth')) { - event.context.user = { name: 'Nitro' } - } -}) -``` - -## Error handling - -You can use the [utilities available in H3](https://h3.unjs.io/guide/event-handler#error-handling) to handle errors in both routes and middlewares. - -The way errors are sent back to the client depends on the route's path. For most routes `Content-Type` is set to `text/html` by default and a simple html error page is delivered. If the route starts with `/api/` (either because it is placed in `api/` or `routes/api/`) the default will change to `application/json` and a JSON object will be sent. - -This behaviour can be overridden by some request properties (e.g.: `Accept` or `User-Agent` headers). - -## Route Rules - -Nitro allows you to add logic at the top-level for each route of your configuration. It can be used for redirecting, proxying, caching and adding headers to routes. - -It is a map from route pattern (following [unjs/radix3](https://github.com/unjs/rou3/tree/radix3#route-matcher)) to route options. - -When `cache` option is set, handlers matching pattern will be automatically wrapped with `defineCachedEventHandler`. See the [cache guide](/guide/cache) to learn more about this function. - -::note -`swr: true|number` is shortcut for `cache: { swr: true, maxAge: number }` -:: - -You can set route rules in `nitro.config.ts` using the `routeRules` option. - -::code-group -```ts [nitro.config.ts] -export default defineNitroConfig({ - routeRules: { - '/blog/**': { swr: true }, - '/blog/**': { swr: 600 }, - '/blog/**': { static: true }, - '/blog/**': { cache: { /* cache options*/ } }, - '/assets/**': { headers: { 'cache-control': 's-maxage=0' } }, - '/api/v1/**': { cors: true, headers: { 'access-control-allow-methods': 'GET' } }, - '/old-page': { redirect: '/new-page' }, - '/old-page/**': { redirect: '/new-page/**' }, - '/proxy/example': { proxy: 'https://example.com' }, - '/proxy/**': { proxy: '/api/**' }, - } -}) -``` -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - routeRules: { - '/blog/**': { swr: true }, - '/blog/**': { swr: 600 }, - '/blog/**': { static: true }, - '/blog/**': { cache: { /* cache options*/ } }, - '/assets/**': { headers: { 'cache-control': 's-maxage=0' } }, - '/api/v1/**': { cors: true, headers: { 'access-control-allow-methods': 'GET' } }, - '/old-page': { redirect: '/new-page' }, - '/old-page/**': { redirect: '/new-page/**' }, - '/proxy/example': { proxy: 'https://example.com' }, - '/proxy/**': { proxy: '/api/**' }, - } -}) -``` -:: diff --git a/docs/1.guide/3.websocket.md b/docs/1.guide/3.websocket.md deleted file mode 100644 index fd5873a343..0000000000 --- a/docs/1.guide/3.websocket.md +++ /dev/null @@ -1,135 +0,0 @@ ---- -icon: cib:socket-io ---- - -# WebSocket - -> Nitro natively supports a cross platform WebSocket API - -Nitro natively supports runtime agnostic [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) API using [CrossWS](https://crossws.unjs.io/) and [H3 WebSocket](https://h3.unjs.io/guide/websocket). - -:read-more{title="WebSocket in MDN" to="https://developer.mozilla.org/en-US/docs/Web/API/WebSocket"} - -:read-more{title="CrossWS" to="https://crossws.unjs.io/"} - -## Opt-in to the experimental feature - -> [!IMPORTANT] -> WebSockets support is currently experimental. See [nitrojs/nitro#2171](https://github.com/nitrojs/nitro/issues/2171) for platform support status. - -In order to enable websocket support you need to enable the experimental `websocket` feature flag. - -::code-group -```ts [nitro.config.ts] -export default defineNitroConfig({ - experimental: { - websocket: true - } -}) -``` - -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - nitro: { - experimental: { - websocket: true - } - } -}) -``` -:: - -## Usage - -Create a websocket handler in `routes/_ws.ts` (or `server/routes/_ws.ts` for Nuxt). - -> [!TIP] -> You can use any route like `routes/chatroom.ts` to register upgrade handler on `/chatroom`. - - - -```ts [_ws.ts] -export default defineWebSocketHandler({ - open(peer) { - console.log("[ws] open", peer); - }, - - message(peer, message) { - console.log("[ws] message", peer, message); - if (message.text().includes("ping")) { - peer.send("pong"); - } - }, - - close(peer, event) { - console.log("[ws] close", peer, event); - }, - - error(peer, error) { - console.log("[ws] error", peer, error); - }, -}); - -``` - - - -> [!NOTE] -> Nitro allows you defining multiple websocket handlers using same routing of event handlers. - -Use a client to connect to server. Example: (`routes/websocket.ts` or `server/routes/websocket.ts` for Nuxt) - - - -```ts [index.ts] -export default defineEventHandler(() => { - return $fetch( - "https://raw.githubusercontent.com/unjs/crossws/main/examples/h3/public/index.html" - ); -}); - -``` - - - -Now you can try it on `/websocket` route! - -> [!TIP] -> Check out our [chat demo](https://nuxt-chat.pi0.io/) using Nitro Websocket API. - -## Server-Sent Events (SSE) - -As an alternative to WebSockets, you can use [Server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) - -### Example - -Create an SSE handler in `routes/sse.ts` (or `server/routes/sse.ts` for Nuxt). - -```ts [sse.ts] -export default defineEventHandler(async (event) => { - const eventStream = createEventStream(event) - - const interval = setInterval(async () => { - await eventStream.push(`Message @ ${new Date().toLocaleTimeString()}`) - }, 1000) - - eventStream.onClosed(async () => { - clearInterval(interval) - await eventStream.close() - }) - - return eventStream.send() -}) -``` - -Then connect to this SSE endpoint from the client - -```ts -const eventSource = new EventSource('http://localhost:3000/sse') - -eventSource.onmessage = (event) => { - console.log(event.data) -} -``` - -:read-more{to="https://h3.unjs.io/guide/websocket#server-sent-events-sse" title="SSE guide in H3"} diff --git a/docs/1.guide/4.storage.md b/docs/1.guide/4.storage.md deleted file mode 100644 index a663bbde41..0000000000 --- a/docs/1.guide/4.storage.md +++ /dev/null @@ -1,193 +0,0 @@ ---- -icon: carbon:datastore ---- - -# KV Storage - -> Nitro provides a built-in storage layer that can abstract filesystem or database or any other data source. - -Nitro has built-in integration with [unjs/unstorage](https://unstorage.unjs.io) to provide a runtime agnostic persistent layer. - -## Usage - -To use the storage layer, you can use the `useStorage()` and call `getItem(key)` to retrieve an item and `setItem(key, value)` to set an item. - -```ts -// Default storage is in memory -await useStorage().setItem('test:foo', { hello: 'world' }) -await useStorage().getItem('test:foo') - -// You can also specify the base in useStorage(base) -await useStorage('test').setItem('foo', { hello: 'world' }) - -// You can use data storage to write data to default .data/kv directory -const dataStorage = useStorage('data') -await dataStorage.setItem('test', 'works') -await dataStorage.getItem('data:test') // Value persists - -// You can use generics to define types -await useStorage<{ hello: string }>('test').getItem('foo') -await useStorage('test').getItem<{ hello: string }>('foo') -``` - -:read-more{to="https://unstorage.unjs.io"} - - -## Configuration - -You can mount one or multiple custom storage drivers using the `storage` config. -The key is the mount point name, and the value is the driver name and configuration. - -::code-group -```ts [nitro.config.ts] -export default defineNitroConfig({ - storage: { - redis: { - driver: 'redis', - /* redis connector options */ - }, - db: { - driver: 'fs', - base: './data/db' - } - } -}) -``` -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - nitro: { - storage: { - redis: { - driver: 'redis', - /* redis connector options */ - }, - db: { - driver: 'fs', - base: './.data/db' - } - } - } -}) -``` -:: - -::read-more{to="https://unstorage.unjs.io/"} -You can find the driver list on [unstorage documentation](https://unstorage.unjs.io/) with their configuration. -:: - -### Runtime configuration - -In scenarios where the mount point configuration is not known until runtime, Nitro can dynamically add mount points during startup using [plugins](/guide/plugins). - -::code-group -```ts [plugins/storage.ts] -import redisDriver from 'unstorage/drivers/redis' - -export default defineNitroPlugin(() => { - const storage = useStorage() - - // Dynamically pass in credentials from runtime configuration, or other sources - const driver = redisDriver({ - base: 'redis', - host: useRuntimeConfig().redis.host, - port: useRuntimeConfig().redis.port, - /* other redis connector options */ - }) - - // Mount driver - storage.mount('redis', driver) -}) -``` -``` ts [nitro.config.ts] -export default defineNitroConfig({ - runtimeConfig: { - redis: { // Default values - host: '', - port: 0, - /* other redis connector options */ - } - } -}) -``` -``` ts [nuxt.config.ts] -export default defineNuxtConfig({ - runtimeConfig: { - redis: { // Default values - host: '', - port: 0, - /* other redis connector options */ - } - } -}) -``` -:: - -::warning -This is a temporary workaround, with a better solution coming in the future! Keep a lookout on the GitHub issue [here](https://github.com/nitrojs/nitro/issues/1161#issuecomment-1511444675). -:: - -### Development-only mount points - -By default, Nitro will mount the project directory and some other dirs using the filesystem driver in development time. - -```js -// Access to project root dir -const rootStorage = useStorage('root') - -// Access to project src dir (same as root by default) -const srcStorage = useStorage('src') - -// Access to server cache dir -const cacheStorage = useStorage('cache') - -// Access to the temp build dir -const buildStorage = useStorage('build') -``` - -> [!TIP] -> You also can use the `devStorage` key to overwrite the storage configuration during development. This is very useful when you use a database in production and want to use the filesystem in development. - -In order to use the `devStorage` key, you need to use the `nitro dev` command and the key in the `storage` option must be the same as the production one. - -::code-group -```ts [nitro.config.ts] -export default defineNitroConfig({ - // Production - storage: { - db: { - driver: 'redis', - /* redis connector options */ - } - }, - // Development - devStorage: { - db: { - driver: 'fs', - base: './data/db' - } - } -}) -``` -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - nitro: { - // Production - storage: { - db: { - driver: 'redis', - /* redis connector options */ - } - }, - // Development - devStorage: { - db: { - driver: 'fs', - base: './data/db' - } - } - } -}) -``` -:: - -You will also be able to access to a `build` namespace in the storage layer only during development. It contains file generated by Nitro. diff --git a/docs/1.guide/5.database.md b/docs/1.guide/5.database.md deleted file mode 100644 index d4bc86797b..0000000000 --- a/docs/1.guide/5.database.md +++ /dev/null @@ -1,115 +0,0 @@ ---- -icon: ri:database-2-line ---- - -# SQL Database - -> Nitro provides a built-in and lightweight SQL database layer. - -The default database connection is **preconfigured** with [SQLite](https://db0.unjs.io/connectors/sqlite) and works out of the box for development mode and any Node.js compatible production deployments. By default, data will be stored in `.data/db.sqlite3`. - -> [!TIP] -> You can change default connection or define more connections to any of the [supported databases](https://db0.unjs.io/connectors/sqlite). - -> [!TIP] -> You can integrate database instance to any of the [supported ORMs](https://db0.unjs.io/integrations). - -:read-more{to="https://db0.unjs.io" title="DB0 Documentation"} - -## Opt-in to the experimental feature - -> [!IMPORTANT] -> Database support is currently experimental. -> Refer to the [db0 issues](https://github.com/unjs/db0/issues) for status and bug report. - -In order to enable database layer you need to enable experimental feature flag. - -::code-group -```ts [nitro.config.ts] -export default defineNitroConfig({ - experimental: { - database: true - } -}) -``` - -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - nitro: { - experimental: { - database: true - } - } -}) -``` -:: - -## Usage - - - -```ts [index.ts] -export default defineEventHandler(async () => { - const db = useDatabase(); - - // Create users table - await db.sql`DROP TABLE IF EXISTS users`; - await db.sql`CREATE TABLE IF NOT EXISTS users ("id" TEXT PRIMARY KEY, "firstName" TEXT, "lastName" TEXT, "email" TEXT)`; - - // Add a new user - const userId = String(Math.round(Math.random() * 10_000)); - await db.sql`INSERT INTO users VALUES (${userId}, 'John', 'Doe', '')`; - - // Query for users - const { rows } = await db.sql`SELECT * FROM users WHERE id = ${userId}`; - - return { - rows, - }; -}); - -``` - - - -## Configuration - -You can configure database connections using `database` config: - -::code-group -```ts [nitro.config.ts] -export default defineNitroConfig({ - database: { - default: { - connector: 'sqlite', - options: { name: 'db' } - }, - users: { - connector: 'postgresql', - url: 'postgresql://username:password@hostname:port/database_name' - } - } -}) -``` -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - nitro: { - database: { - default: { - connector: 'sqlite', - options: { name: 'db' } - }, - users: { - connector: 'postgresql', - options: { - url: 'postgresql://username:password@hostname:port/database_name' - } - } - } - } -}) -``` -:: - -> [!TIP] -> You can use the `devDatabase` config to overwrite the database configuration only for development mode. diff --git a/docs/1.guide/6.cache.md b/docs/1.guide/6.cache.md deleted file mode 100644 index 8dd06a3c51..0000000000 --- a/docs/1.guide/6.cache.md +++ /dev/null @@ -1,300 +0,0 @@ ---- -icon: ri:speed-line ---- - -# Cache - -> Nitro provides a caching system built on top of the storage layer. - -## Cached event handlers - -To cache an event handler, you simply need to use the `defineCachedEventHandler` method. - -It works like [`defineEventHandler`](https://h3.unjs.io/guide/event-handler) but with an additional second [options](#options) parameter. - -```ts [routes/cached.ts] -// Cache an API handler -export default defineCachedEventHandler((event) => { - // My event handler -}, { maxAge: 60 * 60 /* 1 hour */ }); -``` - -With this example, the response will be cached for 1 hour and a stale value will be sent to the client while the cache is being updated in the background. If you want to immediately return the updated response set `swr: false`. - -::important -All incoming request headers are dropped when handling cached responses. If you define the `varies` option, only the specified headers will be considered when caching and serving the responses. -:: - -See the [options](#options) section for more details about the available options. - -::note -You can also use the `cachedEventHandler` method as alias of `defineCachedEventHandler`. -:: - -## Cached functions - -You can also cache a function using the `defineCachedFunction` function. This is useful for caching the result of a function that is not an event handler, but is part of one, and reusing it in multiple handlers. - -For example, you might want to cache the result of an API call for one hour: - -::code-group -```ts [utils/github.ts] -export const cachedGHStars = defineCachedFunction(async (repo: string) => { - const data: any = await $fetch(`https://api.github.com/repos/${repo}`) - - return data.stargazers_count -}, { - maxAge: 60 * 60, - name: 'ghStars', - getKey: (repo: string) => repo -}) -``` -```ts [api/stars/[...repo\\].ts] -export default defineEventHandler(async (event) => { - const repo = event.context.params.repo - const stars = await cachedGHStars(repo).catch(() => 0) - - return { repo, stars } -}) -``` -:: - -The stars will be cached in development inside ```.nitro/cache/functions/ghStars//.json``` with `value` being the number of stars. - -```json -{"expires":1677851092249,"value":43991,"mtime":1677847492540,"integrity":"ZUHcsxCWEH"} -``` - -::important Because the cached data is serialized to JSON, it is important that the cached function does not return anything that cannot be serialized, such as Symbols, Maps, Sets… :: - -::note -You can also use the `cachedFunction` method as alias of `defineCachedFunction`. -:: - -### Edge workers - -In edge workers, the instance is destroyed after each request. Nitro automatically uses `event.waitUntil` to keep the instance alive while the cache is being updated while the response is sent to the client. - -To ensure that your cached functions work as expected in edge workers, you should always pass the `event` as the first argument to the function using `defineCachedFunction`. - -::code-group -```ts [utils/github.ts] -import type { H3Event } from 'h3' - -export const cachedGHStars = defineCachedFunction(async (event: H3Event, repo: string) => { - const data: any = await $fetch(`https://api.github.com/repos/${repo}`) - - return data.stargazers_count -}, { - maxAge: 60 * 60, - name: 'ghStars', - getKey: (event: H3Event, repo: string) => repo -}) -``` -```ts [api/stars/[...repo\\].ts] -export default defineEventHandler(async (event) => { - const repo = event.context.params.repo - const stars = await cachedGHStars(event, repo).catch(() => 0) - - return { repo, stars } -}) -``` -:: - -This way, the function will be able to keep the instance alive while the cache is being updated without slowing down the response to the client. - -## Caching route rules - -This feature enables you to add caching routes based on a glob pattern directly in the main configuration file. This is especially useful to have a global cache strategy for a part of your application. - - -Cache all the blog routes for 1 hour with `stale-while-revalidate` behavior: - -::code-group -```ts [nitro.config.ts] -export default defineNitroConfig({ - routeRules: { - "/blog/**": { cache: { maxAge: 60 * 60 } }, - }, -}); -``` -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - routeRules: { - "/blog/**": { cache: { maxAge: 60 * 60 } }, - }, -}); -``` -:: - -If we want to use a [custom storage](#customize-cache-storage) mount point, we can use the `base` option. - -::code-group -```ts [nitro.config.ts] -export default defineNitroConfig({ - storage: { - redis: { - driver: "redis", - url: "redis://localhost:6379", - }, - }, - routeRules: { - "/blog/**": { cache: { maxAge: 60 * 60, base: "redis" } }, - }, -}); -``` -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - nitro: { - storage: { - redis: { - driver: "redis", - url: "redis://localhost:6379", - }, - }, - }, - routeRules: { - "/blog/**": { cache: { maxAge: 60 * 60, base: "redis" } }, - }, -}); -``` -:: - -## Customize cache storage - -Nitro stores the data in the `cache:` mount point. - -- In production, it will use the [memory driver](https://unstorage.unjs.io/drivers/memory) by default. -- In development, it will use the [filesystem driver](https://unstorage.unjs.io/drivers/fs), writing to a temporary dir. - -To overwrite the production storage, set the `cache` mount point using the `storage` option: - -::code-group -```ts [nitro.config.ts] -export default defineNitroConfig({ - storage: { - cache: { - driver: 'redis', - /* redis connector options */ - } - } -}) -``` -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - nitro: { - storage: { - cache: { - driver: 'redis', - /* redis connector options */ - } - } - } -}) -``` -:: - -In development, you can also overwrite the cache mount point using the `devStorage` option: - -::code-group -```ts [nitro.config.ts] -export default defineNitroConfig({ - devStorage: { - cache: { - driver: 'redis', - /* redis connector options */ - } - } -}) -``` -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - nitro: { - devStorage: { - cache: { - driver: 'redis', - /* redis connector options */ - } - } - } -}) -``` -:: - -## Options - -The `cachedEventHandler` and `cachedFunction` functions accept the following options: - -::field-group - ::field{name="base" type="string"} - Name of the storage mountpoint to use for caching. :br - Default to `cache`. - :: - ::field{name="name" type="string"} - Guessed from function name if not provided, and falls back to `'_'` otherwise. - :: - ::field{name="group" type="string"} - Defaults to `'nitro/handlers'` for handlers and `'nitro/functions'` for functions. - :: - ::field{name="getKey()" type="(...args) => string"} - A function that accepts the same arguments as the original function and returns a cache key (`String`). :br - If not provided, a built-in hash function will be used to generate a key based on the function arguments. - :: - ::field{name="integrity" type="string"} - A value that invalidates the cache when changed. :br - By default, it is computed from **function code**, used in development to invalidate the cache when the function code changes. - :: - ::field{name="maxAge" type="number"} - Maximum age that cache is valid, in seconds. :br - Default to `1` (second). - :: - ::field{name="staleMaxAge" type="number"} - Maximum age that a stale cache is valid, in seconds. If set to `-1` a stale value will still be sent to the client while the cache updates in the background. :br - Defaults to `0` (disabled). - :: - ::field{name="swr" type="boolean"} - Enable `stale-while-revalidate` behavior to serve a stale cached response while asynchronously revalidating it. :br - Defaults to `true`. - :: - ::field{name="shouldInvalidateCache()" type="(..args) => boolean"} - A function that returns a `boolean` to invalidate the current cache and create a new one. - :: - ::field{name="shouldBypassCache()" type="(..args) => boolean"} - A function that returns a `boolean` to bypass the current cache without invalidating the existing entry. - :: - ::field{name="varies" type="string[]"} - An array of request headers to be considered for the cache, [learn more](https://github.com/nitrojs/nitro/issues/1031). If utilizing in a multi-tenant environment, you may want to pass `['host', 'x-forwarded-host']` to ensure these headers are not discarded and that the cache is unique per tenant. - :: -:: - -## Cache keys and invalidation - -When using the `defineCachedFunction` or `defineCachedEventHandler` functions, the cache key is generated using the following pattern: - -```ts -`${options.group}:${options.name}:${options.getKey(...args)}.json` -``` - -For example, the following function: - -```ts -const getAccessToken = defineCachedFunction(() => { - return String(Date.now()) -}, { - maxAge: 10, - name: 'getAccessToken', - getKey: () => 'default' -}) -``` - -Will generate the following cache key: - -```ts -nitro:functions:getAccessToken:default.json -``` - -You can invalidate the cached function entry with: - -```ts -await useStorage('cache').removeItem('nitro:functions:getAccessToken:default.json') -``` diff --git a/docs/1.guide/7.fetch.md b/docs/1.guide/7.fetch.md deleted file mode 100644 index 0b083be5be..0000000000 --- a/docs/1.guide/7.fetch.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -icon: ri:global-line ---- - -# Fetch - -> Nitro provides a built-in fetch API that can be used to get data from server endpoints or from other sources. It's built on top of the [unjs/ofetch](https://ofetch.unjs.io). - -## Usage - -In your handler, you just have to call the `$fetch` function to make a request. The response will be automatically parsed. - -```ts [Router Handler] -export default defineEventHandler(async (event) => { - const data = await $fetch('https://ungh.cc/orgs/unjs/repos') - - return data -}) -``` - -You can pass a generic type to the `$fetch` function to get a better type inference. - -```ts [Router Handler] -import { Repo } from '~/types' - -export default defineEventHandler(async (event) => { - const data = await $fetch('https://ungh.cc/orgs/unjs/repos') - - return data -}) -``` - -You can pass many options to the `$fetch` function like the method, headers, body, query, etc. - -```ts [Router Handler] -import { Repo } from '~/types' - -export default defineEventHandler(async (event) => { - const data = await $fetch('https://api.github.com/markdown', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: { - text: 'Hello **world**!' - } - }) - - return data -}) -``` - -See more about the usage of the `$fetch` function in the [unjs/ofetch](https://ofetch.unjs.io) documentation. - -## In-Server fetch - -You can also use the `$fetch` function to make internal requests to other handlers. - -```ts [Router Handler] -export default defineEventHandler(async (event) => { - const data = await $fetch('/api/users') - - return data -}) -``` - -In reality, no fetch request is made and the handler is directly called, thanks to [unjs/unenv](https://unenv.unjs.io). This is useful to avoid making HTTP request overhead. diff --git a/docs/1.guide/8.assets.md b/docs/1.guide/8.assets.md deleted file mode 100644 index 590fa0004c..0000000000 --- a/docs/1.guide/8.assets.md +++ /dev/null @@ -1,122 +0,0 @@ ---- -icon: ri:image-2-line ---- - -# Assets - -## Public assets - -Nitro handles assets via the `public/` directory. - - -All assets in `public/` directory will be automatically served. This means that you can access them directly from the browser without any special configuration. - -```md -public/ - image.png <-- /image.png - video.mp4 <-- /video.mp4 - robots.txt <-- /robots.txt -package.json -nitro.config.ts -``` - -### Production public assets - -When building your Nitro app, the `public/` directory will be copied to `.output/public/` and a manifest with metadata will be created and embedded in the server bundle. - -```json -{ - "/image.png": { - "type": "image/png", - "etag": "\"4a0c-6utWq0Kbk5OqDmksYCa9XV8irnM\"", - "mtime": "2023-03-04T21:39:45.086Z", - "size": 18956 - }, - "/robots.txt": { - "type": "text/plain; charset=utf-8", - "etag": "\"8-hMqyDrA8fJ0R904zgEPs3L55Jls\"", - "mtime": "2023-03-04T21:39:45.086Z", - "size": 8 - }, - "/video.mp4": { - "type": "video/mp4", - "etag": "\"9b943-4UwfQXKUjPCesGPr6J5j7GzNYGU\"", - "mtime": "2023-03-04T21:39:45.085Z", - "size": 637251 - } -} -``` - -This allows Nitro to know the public assets without scanning the directory, giving high performance with caching headers. - -## Server assets - -All assets in `assets/` directory will be added to the server bundle. After building your application, you can find them in the `.output/server/chunks/raw/` directory. Be careful with the size of your assets, as they will be bundled with the server bundle. - -They can be addressed by the `assets:server` mount point using the [storage layer](/guide/storage). - -For example, you could store a json file in `assets/data.json` and retrieve it in your handler: - -```js -export default defineEventHandler(async () => { - const data = await useStorage('assets:server').getItem(`data.json`) - return data -}) -``` - -### Custom server assets - -In order to add assets from a custom directory, you will need to define a path in your nitro config. This allows you to add assets from a directory outside of the `assets/` directory. - -::code-group -```js [nitro.config.ts] -export default defineNitroConfig({ - serverAssets: [{ - baseName: 'my_directory', - dir: './my_directory' - }] -}) -``` -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - nitro: { - serverAssets: [{ - baseName: 'my_directory', - dir: './server/my_directory' - }] - } -}) -``` -:: - -You could want to add a directory with html templates for example. - -::code-group -```js [nitro.config.ts] -export default defineNitroConfig({ - serverAssets: [{ - baseName: 'templates', - dir: './templates' - }] -}) -``` -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - nitro: { - serverAssets: [{ - baseName: 'templates', - dir: './templates' // Relative to `srcDir` (`server/` for nuxt) - }] - } -}) -``` -:: - -Then you can use the `assets:templates` base to retrieve your assets. - -```ts [handlers/success.ts] -export default defineEventHandler(async (event) => { - const html = await useStorage('assets:templates').getItem(`success.html`) - return html -}) -``` diff --git a/docs/1.guide/9.plugins.md b/docs/1.guide/9.plugins.md deleted file mode 100644 index 9b1fa89034..0000000000 --- a/docs/1.guide/9.plugins.md +++ /dev/null @@ -1,132 +0,0 @@ ---- -icon: ri:plug-line ---- - -# Plugins - -> Use plugins to extend Nitro's runtime behavior. - -Nitro plugins will be **executed once** during server startup in order to allow extending Nitro's runtime behavior. -They receive `nitroApp` context, which can be used to hook into Nitro lifecycle events. - -Plugins are auto-registered from `plugins/` directory and run synchronously (by order of file name) on the first Nitro initialization. - - -**Example:** - -```ts -// plugins/test.ts -export default defineNitroPlugin((nitroApp) => { - console.log('Nitro plugin', nitroApp) -}) -``` - -If you have plugins in another directory, you can use the `plugins` option: - -::code-group -```ts [nitro.config.ts] -export default defineNitroConfig({ - plugins: ['my-plugins/hello.ts'] -}) -``` -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - nitro: { - plugins: ['my-plugins/hello.ts'] - } -}) -``` -:: - -## Nitro runtime hooks - -You can use Nitro [hooks](https://github.com/unjs/hookable) to extend the default runtime behaviour of Nitro by registering custom (async or sync) functions to the lifecycle events within plugins. - -**Example:** - -```ts -export default defineNitroPlugin((nitro) => { - nitro.hooks.hook("close", async () => { - // Will run when nitro is being closed - }); -}) -``` - -### Available hooks - -See the [source code](https://github.com/nitrojs/nitro/blob/v2/src/core/index.ts#L75) for list of all available runtime hooks. - -- `"close", () => {}` -- `"error", (error, { event? }) => {}` -- `"render:response", (response, { event }) => {}` -- `"request", (event) => {}` -- `"beforeResponse", (event, { body }) => {}` -- `"afterResponse", (event, { body }) => {}` - -## Examples - -### Capturing errors - -You can use plugins to capture all application errors. - -```ts -export default defineNitroPlugin((nitro) => { - nitro.hooks.hook("error", async (error, { event }) => { - console.error(`${event.path} Application error:`, error) - }); -}) -``` - -### Graceful shutdown - -You can use plugins to register a hook that resolves when Nitro is closed. - -```ts -export default defineNitroPlugin((nitro) => { - nitro.hooks.hookOnce("close", async () => { - // Will run when nitro is closed - console.log("Closing nitro server...") - await new Promise((resolve) => setTimeout(resolve, 500)); - console.log("Task is done!"); - }); -}) -``` - -### Request and response lifecycle - -You can use plugins to register a hook that can run on request lifecycle: - -```ts -export default defineNitroPlugin((nitroApp) => { - nitroApp.hooks.hook("request", (event) => { - console.log("on request", event.path); - }); - - nitroApp.hooks.hook("beforeResponse", (event, { body }) => { - console.log("on response", event.path, { body }); - }); - - nitroApp.hooks.hook("afterResponse", (event, { body }) => { - console.log("on after response", event.path, { body }); - }); -}); -``` - -### Renderer response - -You can use plugins to register a hook that modifies the [`renderer`](https://nitro.build/config#renderer) response. - -::note -This **only works** for render handler defined with [`renderer`](https://nitro.build/config#renderer) and won't be called for other api/server routes. -In [Nuxt](https://nuxt.com/) this hook will be called for Server-side rendered pages -:: - -```ts -export default defineNitroPlugin((nitro) => { - - nitro.hooks.hook('render:response', (response, { event }) => { - // Inspect or Modify the renderer response here - console.log(response) - }) -}) -``` diff --git a/docs/1.guide/97.configuration.md b/docs/1.guide/97.configuration.md deleted file mode 100644 index fb78f09c55..0000000000 --- a/docs/1.guide/97.configuration.md +++ /dev/null @@ -1,115 +0,0 @@ ---- -icon: ri:settings-3-line ---- - -# Configuration - -> Customize and extend Nitro defaults. - -::read-more{to="/config"} -See [config reference](/config) for available options. -:: - -You can customize your Nitro builder with a configuration file. - -::code-group -```ts [nitro.config.ts] -export default defineNitroConfig({ - // Nitro options -}) -``` - -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - nitro: { - // Nitro options - } -}) -``` -:: - -> [!IMPORTANT] -> If you are using [Nuxt](https://nuxt.com), use the `nitro` option in your Nuxt config instead. - -> [!TIP] -> Nitro loads the configuration using [unjs/c12](https://github.com/unjs/c12), giving more possibilities such as using `.nitrorc` file in current working directory or in the user's home directory. - -## Runtime configuration - -Nitro provides a runtime config API to expose configuration within your application, with the ability to update it at runtime by setting environment variables. This is useful when you want to expose different configuration values for different environments (e.g. development, staging, production). For example, you can use this to expose different API endpoints for different environments or to expose different feature flags. - -First, you need to define the runtime config in your configuration file. - -::code-group -```ts [nitro.config.ts] -export default defineNitroConfig({ - runtimeConfig: { - apiToken: "dev_token", // `dev_token` is the default value - } -}) -``` - -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - runtimeConfig: { - apiToken: "dev_token", // `dev_token` is the default value - } -}) -``` -:: - -You can now access the runtime config using `useRuntimeConfig(event)`. Use `useRuntimeConfig(event)` within event handlers and utilities and **avoid** calling it in ambient global contexts. This could lead to unexpected behavior such as sharing the same runtime config across different requests. - -::code-group -```ts [api/example.get.ts (nitro)] -export default defineEventHandler((event) => { - return useRuntimeConfig(event).apiToken // Returns `dev_token` -}); -``` - -```ts [server/api/example.get.ts (nuxt)] -export default defineEventHandler((event) => { - return useRuntimeConfig(event).apiToken // dev_token -}); -``` -:: - -### Local development - -Finally, you can update the runtime config using environment variables. You can use a `.env` file in development and use platform variables in production (see below). - -Create an `.env` file in your project root: - -```bash [.env] -NITRO_API_TOKEN="123" -``` - -Re-start the development server, fetch the `/api/example` endpoint and you should see `123` as the response instead of `dev_token`. - -Do not forget that you can still universally access environment variables using `import.meta.env` or `process.env` but avoid using them in ambiant global contexts to prevent unexpected behavior. - -### Production - -You can define variables in your production environment to update the runtime config. All variables must be prefixed with `NITRO_` to be applied to the runtime config. They will override the runtime config variables defined within your `nitro.config.ts` file. - -::code-group -```bash [.env (nitro)] -NITRO_API_TOKEN="123" -``` - -```bash [.env (nuxt)] -NUXT_API_TOKEN="123" -``` -:: - -In runtime config, define key using camelCase. In environment variables, define key using snake_case and uppercase. - -```ts -{ - helloWorld: "foo" -} -``` - -```bash -NITRO_HELLO_WORLD="foo" -``` diff --git a/docs/1.guide/98.typescript.md b/docs/1.guide/98.typescript.md deleted file mode 100644 index b7fe9934d1..0000000000 --- a/docs/1.guide/98.typescript.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -icon: tabler:brand-typescript ---- - -# TypeScript - -> Nitro automatically generates the types for auto-imports and server routes :sparkles: - -## `tsconfig.json` - -To leverage type hints within your project, create a `tsconfig.json` file that extends auto-generated types. - -::code-group -```json [tsconfig.json (nitro)] -{ - "extends": "./.nitro/types/tsconfig.json" -} -``` - -```json [server/tsconfig.json (nuxt)] -{ - "extends": "../.nuxt/tsconfig.server.json" -} -``` -:: - -::tip -Starter templates have this file by default and usually you don't need to do anything. If this file does not exists, you can manually create it. -:: - -## Prepare types - -You can use `prepare` command to auto generate the types. -This can be useful in a CI environment or as a `postinstall` command in your `package.json`. - -:pm-x{command="nitro prepare"} - -::tip -When using `nitro dev` command, types are also auto-generated! -:: - -::note -For [Nuxt](https://nuxt.com) you should use `nuxi generate` -:: - diff --git a/docs/1.guide/99.nightly.md b/docs/1.guide/99.nightly.md deleted file mode 100644 index 06d26b573f..0000000000 --- a/docs/1.guide/99.nightly.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -icon: ri:moon-fill ---- - -# Nightly Channel - -> Nitro has a nightly release channel that automatically releases for every commit to `main` branch to try latest changes. - -You can opt-in to the nightly release channel by updating your `package.json`: - -::code-group -```diff [Nitro] -{ - "devDependencies": { --- "nitropack": "^2.0.0" -++ "nitropack": "npm:nitropack-nightly@latest" - } -} -``` -```diff [Nuxt] -{ - "devDependencies": { --- "nuxt": "^3.0.0" -++ "nuxt": "npm:nuxt-nightly@latest" - } -} -``` -:: - -::note -If you are using Nuxt, [use the Nuxt nightly channel](https://nuxt.com/docs/guide/going-further/nightly-release-channel#opting-in) as it already includes `nitropack-nightly`. -:: - -Remove the lockfile (`package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`, or `bun.lockb`) and reinstall the dependencies. diff --git a/docs/2.deploy/0.index.md b/docs/2.deploy/0.index.md index 02a8fe85df..c04e5aac6f 100644 --- a/docs/2.deploy/0.index.md +++ b/docs/2.deploy/0.index.md @@ -2,7 +2,7 @@ icon: ri:upload-cloud-2-line --- -# Overview +# Deploy > Learn more about Nitro deploy providers. @@ -11,7 +11,7 @@ Using built-in presets, you can easily configure Nitro to adjust its output form ## Default output -The default production output preset is [Node.js server](/deploy/node). +The default production output preset is [Node.js server](/deploy/runtimes/node). When running Nitro in development mode, Nitro will always use a special preset called `nitro-dev` using Node.js with ESM in an isolated Worker environment with behavior as close as possible to the production environment. @@ -21,7 +21,8 @@ When deploying to production using CI/CD, Nitro tries to automatically detect th - [aws amplify](/deploy/providers/aws-amplify) - [azure](/deploy/providers/azure) -- [cloudflare pages](/deploy/providers/cloudflare#cloudflare-pages) +- [cloudflare](/deploy/providers/cloudflare) +- [firebase app hosting](/deploy/providers/firebase#firebase-app-hosting) - [netlify](/deploy/providers/netlify) - [stormkit](/deploy/providers/stormkit) - [vercel](/deploy/providers/vercel) @@ -31,9 +32,11 @@ When deploying to production using CI/CD, Nitro tries to automatically detect th For Turborepo users, zero config detection will be interferenced by its Strict Environment Mode. You may need to allowing the variables explictly or use its Loose Environment Mode (with `--env-mode=loose` flag). :: +Other built-in providers are available with an explicit preset, including [zephyr](/deploy/providers/zephyr). + ## Changing the deployment preset -If you need to build Nitro against a specific provider, you can target it by defining an environment variable named `NITRO_PRESET` or `SERVER_PRESET`, or by updating your Nitro [configuration](/guide/configuration) or using `--preset` argument. +If you need to build Nitro against a specific provider, you can target it by defining an environment variable named `NITRO_PRESET` or `SERVER_PRESET`, or by updating your Nitro [configuration](/docs/configuration) or using `--preset` argument. Using the environment variable approach is recommended for deployments depending on CI/CD. @@ -45,7 +48,25 @@ nitro build --preset cloudflare_pages **Example:** Updating the `nitro.config.ts` file ```ts +import { defineNitroConfig } from "nitro/config"; + export default defineNitroConfig({ preset: 'cloudflare_pages' }) ``` + +## Compatibility date + +Deployment providers regularly update their runtime behavior. Nitro presets are updated to support these new features. + +To prevent breaking existing deployments, Nitro uses compatibility dates. These dates let you lock in behavior at the project creation time. You can also opt in to future updates when ready. + +When you create a new project, the `compatibilityDate` is set to the current date. This setting is saved in your project's configuration. + +You should update the compatibility date periodically. Always test your deployment thoroughly after updating. Below is a list of key dates and their effects. + + + + + + diff --git a/docs/2.deploy/1.workers.md b/docs/2.deploy/1.workers.md deleted file mode 100644 index 171007e7f0..0000000000 --- a/docs/2.deploy/1.workers.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -icon: ri:global-line ---- - -# Edge Workers - -> Nitro provides out of the box support for deploying to Edge Workers. - -## Deploy to workers - -Nitro provides out of the box support for deploying any Nitro app to different Edge Worker offerings as well as Service Workers. - -- [Cloudflare](/deploy/providers/cloudflare) -- [Deno Deploy](/deploy/providers/deno-deploy) -- [Vercel](/deploy/providers/vercel#vercel-edge-functions) -- [Netlify](/deploy/providers/netlify#netlify-edge-functions) -- [Browser Service Workers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) (via experimental preset `service-worker`) - -### Worker limitations - -- No support for raw TCP/IP traffic -- Execution time is limited compared to classic serverless offerings (normally 15-30 seconds) -- No access to the filesystem (use the [nitro storage](/guide/storage) layer) -- Bundle size is very limited (normally a few MBs) -- Limited access Node.js APIs (nitro provides compatibility layer via [unjs/unenv](https://github.com/unjs/unenv)) - -### Incompatible libraries - -::note -If you come across a library that you assume to be incompatible with edge workers, please open an issue on the [nitro repo](https://github.com/nitrojs/nitro/issues/new/choose) and help us keeping this list up to date. -:: - -The following libraries are known to be incompatible with edge workers because of one of the above mentioned limitations: - -#### `mongodb` - -> There are possible fixes for MongoDB, like using Realm and the [Realm SDK](https://www.mongodb.com/docs/realm/sdk/node/) or -> using http interfaces (only available when self hosting MongoDB), but these are untested. You can find an example for using realm [here](https://github.com/albionstatus/albionstatus-backend/) - -#### `mysql` - -> You can find an example with a modified MySQL driver [here](https://github.com/cloudflare/worker-template-mysql) - -- `rhea` -- `gremlin` -- `ioredis` -- `cassandra-driver` -- `kafkajs` diff --git a/docs/2.deploy/10.runtimes/1.node.md b/docs/2.deploy/10.runtimes/1.node.md index 475b4a0eae..034363c2a9 100644 --- a/docs/2.deploy/10.runtimes/1.node.md +++ b/docs/2.deploy/10.runtimes/1.node.md @@ -52,11 +52,11 @@ In addition to environment variables from the `node_server` preset, you can cust ## Handler (advanced) -**Preset:** `node` +**Preset:** `node_middleware` -Nitro also has a more low-level preset that directly exports a function with `(req, res) => {}` signature usable for middleware and custom servers. +Nitro also has a more low-level preset that directly exports a middleware usable for custom servers. -When running `nitro build` with the Node preset, the result will be an entry point exporting a function with the `(req, res) => {}` signature. +When running `nitro build` with the Node middleware preset, the result will be an entry point exporting a middleware handler. **Example:** diff --git a/docs/2.deploy/10.runtimes/_dir.yml b/docs/2.deploy/10.runtimes/_dir.yml deleted file mode 100644 index 10ec56caec..0000000000 --- a/docs/2.deploy/10.runtimes/_dir.yml +++ /dev/null @@ -1 +0,0 @@ -icon: codicon:run-all diff --git a/docs/2.deploy/10.runtimes/_winterjs.md b/docs/2.deploy/10.runtimes/_winterjs.md deleted file mode 100644 index 8a84ade019..0000000000 --- a/docs/2.deploy/10.runtimes/_winterjs.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -icon: game-icons:cold-heart ---- - -# WinterJS - -**Preset:** `winterjs` - -You can easily build Nitro powered applications to run with [wasmerio/winterjs](https://github.com/wasmerio/winterjs) runtime. - -[WinterJS](https://github.com/wasmerio/winterjs) is a JavaScript Service Workers server written in Rust, that uses the SpiderMonkey runtime to execute JavaScript (the same runtime that Firefox uses) ([announcement](https://wasmer.io/posts/announcing-winterjs-service-workers)). - - -::warning -🚧 WinterJS runtime is unstable and under heavy development. Follow [nitrojs/nitro#1861](https://github.com/nitrojs/nitro/issues/1861) for status and information. -:: - - -In order to build for this runtime, use `NITRO_PRESET="winterjs"` environment variable: - -```sh -NITRO_PRESET="winterjs" npm run build -``` - -Make sure you have `wasmer` installed locally ([install wasmer](https://docs.wasmer.io/install)) - -Run locally: - -```sh -wasmer run wasmer/winterjs --forward-host-env --net --mapdir app:.output app/server/index.mjs -``` diff --git a/docs/2.deploy/2.custom-presets.md b/docs/2.deploy/2.custom-presets.md deleted file mode 100644 index 235f4cd5ac..0000000000 --- a/docs/2.deploy/2.custom-presets.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -icon: ri:file-code-line -aside: false ---- - -# Custom Preset - -> If you want to use a provider that Nitro doesn't support, or want to modify an existing one, you can create a local custom preset in your project. - -Custom presets are local files that have a preset entry that defines builder configuration and a runtime entry point. - -::warning -Custom local preset support is an experimental feature. -:: - -## Example - -::note -Check [nitrojs/nitro-preset-starter](https://github.com/nitrojs/nitro-preset-starter) for a ready-to-use template. -:: - -First, we have to define our preset entry point in a local directory `preset/nitro.config.ts` - -```ts [./preset/nitro.config.ts] -import type { NitroPreset } from "nitropack"; -import { fileURLToPath } from "node:url" - -export default { - // extends: "node-server", // You can extend existing presets - entry: fileURLToPath(new URL("./entry.ts", import.meta.url)), - hooks: { - compiled() { - // ... - }, - }, -}; -``` - -The entry point will be used by your server or provider, and you can fully customize its behavior. - -::code-group -```ts [preset/entry.ts (Workers)] -import "#internal/nitro/virtual/polyfill"; - -const nitroApp = useNitroApp(); - -export default { - fetch(request: Request) { - const url = new URL(request.url); - return nitroApp.localFetch(url.pathname + url.search, { - context: {}, - host: url.hostname, - protocol: url.protocol, - method: request.method, - headers: request.headers, - body: undefined, - }); - }, -}; -``` - -```ts [preset/entry.ts (Node.js)] -import "#internal/nitro/virtual/polyfill"; -import { Server } from "node:http"; -import { toNodeListener } from "h3"; - -const nitroApp = useNitroApp(); -const server = new Server(toNodeListener(nitroApp.h3App)); - -// @ts-ignore -server.listen(3000, (err) => { - if (err) { - console.error(err); - process.exit(1); - } - console.log(`Listening on http://localhost:3000 (custom preset)`); -}); -``` -:: - - -Then in your nitro config file, you can use your custom preset. - -::code-group -```ts [nitro.config.ts] -export default defineNitroConfig({ - preset: "./preset", -}); -``` - -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - nitro: { - preset: "./preset", - } -}); -``` -:: - - -Refer to the Nitro [source code](https://github.com/nitrojs/nitro/tree/main/src) directly to have a better understanding of presets and entry points. diff --git a/docs/2.deploy/20.providers/_dir.yml b/docs/2.deploy/20.providers/_dir.yml deleted file mode 100644 index 659b365707..0000000000 --- a/docs/2.deploy/20.providers/_dir.yml +++ /dev/null @@ -1 +0,0 @@ -icon: tdesign:cloud diff --git a/docs/2.deploy/20.providers/alwaysdata.md b/docs/2.deploy/20.providers/alwaysdata.md index b3e2322670..bb9db3af52 100644 --- a/docs/2.deploy/20.providers/alwaysdata.md +++ b/docs/2.deploy/20.providers/alwaysdata.md @@ -26,7 +26,7 @@ 3. On your admin panel, [create a new site](https://admin.alwaysdata.com/site/add/) for your app with the following features: - *Addresses*: `[account_name].alwaysdata.net` - *Type*: Node.js - - *Command*: `node ./output/server/index.mjs` + - *Command*: `node .output/server/index.mjs` - *Working directory*: `www/my-app` (adapt it to your deployment path) - *Environment*: diff --git a/docs/2.deploy/20.providers/aws-amplify.md b/docs/2.deploy/20.providers/aws-amplify.md index c024db4ce0..7b99b91e1f 100644 --- a/docs/2.deploy/20.providers/aws-amplify.md +++ b/docs/2.deploy/20.providers/aws-amplify.md @@ -23,32 +23,19 @@ Integration with this provider is possible with [zero configuration](/deploy/#ze You can configure advanced options of this preset using `awsAmplify` option. -::code-group - ```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + export default defineNitroConfig({ awsAmplify: { // catchAllStaticFallback: true, // imageOptimization: { path: "/_image", cacheControl: "public, max-age=3600, immutable" }, // imageSettings: { ... }, + // runtime: "nodejs18.x", // default: "nodejs18.x" | "nodejs16.x" | "nodejs20.x" } }) ``` -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - nitro: { - awsAmplify: { - // catchAllStaticFallback: true, - // imageOptimization: { "/_image", cacheControl: "public, max-age=3600, immutable" }, - // imageSettings: { ... }, - } - } -}) -``` - -:: - ### `amplify.yml` You might need a custom `amplify.yml` file for advanced configuration. Here are two template examples: diff --git a/docs/2.deploy/20.providers/aws.md b/docs/2.deploy/20.providers/aws.md index 61b0a65a18..e0902705aa 100644 --- a/docs/2.deploy/20.providers/aws.md +++ b/docs/2.deploy/20.providers/aws.md @@ -22,24 +22,14 @@ const { statusCode, headers, body } = handler({ rawPath: '/' }) Nitro output, by default uses dynamic chunks for lazy loading code only when needed. However this sometimes can not be ideal for performance. (See discussions in [nitrojs/nitro#650](https://github.com/nitrojs/nitro/pull/650)). You can enabling chunk inlining behavior using [`inlineDynamicImports`](/config#inlinedynamicimports) config. -::code-group - ```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + export default defineNitroConfig({ inlineDynamicImports: true }); ``` -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - nitro: { - inlineDynamicImports: true - } -}) -``` - -:: - ## Response streaming @@ -48,6 +38,8 @@ export default defineNuxtConfig({ In order to enable response streaming, enable `awsLambda.streaming` flag: ```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + export default defineNitroConfig({ awsLambda: { streaming: true diff --git a/docs/2.deploy/20.providers/azure.md b/docs/2.deploy/20.providers/azure.md index 8b5d2a0eda..9a465a694e 100644 --- a/docs/2.deploy/20.providers/azure.md +++ b/docs/2.deploy/20.providers/azure.md @@ -4,7 +4,7 @@ ## Azure static web apps -**Preset:** `azure` +**Preset:** `azure-swa` :read-more{title="Azure Static Web Apps" to="https://azure.microsoft.com/en-us/products/app-service/static"} @@ -70,99 +70,3 @@ That's it! Now Azure Static Web Apps will automatically deploy your Nitro-powere If you are using runtimeConfig, you will likely want to configure the corresponding [environment variables on Azure](https://docs.microsoft.com/en-us/azure/static-web-apps/application-settings). -## Azure functions - -**Preset:** `azure_functions` - -::important -If you encounter any issues, please ensure you're using a Node.js 16+ runtime. You can find more information about [how to set the Node version in the Azure docs](https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-node?tabs=v2#setting-the-node-version). -Please see [nitrojs/nitro#2114](https://github.com/nitrojs/nitro/issues/2114) for some common issues. -:: - -### Local preview - -Install [Azure Functions Core Tools](https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local) if you want to test locally. - -You can invoke a development environment from the serverless directory. - -```bash -NITRO_PRESET=azure_functions npx nypm@latest build -cd .output -func start -``` - -You can now visit `http://localhost:7071/` in your browser and browse your site running locally on Azure Functions. - -### Deploy from your local machine - -To deploy, just run the following command: - -```bash -# To publish the bundled zip file -az functionapp deployment source config-zip -g -n --src dist/deploy.zip -# Alternatively you can publish from source -cd dist && func azure functionapp publish --javascript -``` - -### Deploy from CI/CD via GitHub actions - -First, obtain your Azure Functions Publish Profile and add it as a secret to your GitHub repository settings following [these instructions](https://github.com/Azure/functions-action#using-publish-profile-as-deployment-credential-recommended). - -Then create the following file as a workflow: - -```yaml [.github/workflows/azure.yml] -name: azure -on: - push: - branches: - - main - pull_request: - branches: - - main -jobs: - deploy: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ ubuntu-latest ] - node: [ 14 ] - steps: - - uses: actions/setup-node@v2 - with: - node-version: ${{ matrix.node }} - - - name: Checkout - uses: actions/checkout@master - - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "::set-output name=dir::$(yarn cache dir)" - - - uses: actions/cache@v2 - id: yarn-cache - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn-azure - - - name: Install Dependencies - if: steps.cache.outputs.cache-hit != 'true' - run: yarn - - - name: Build - run: npm run build - env: - NITRO_PRESET: azure_functions - - - name: 'Deploy to Azure Functions' - uses: Azure/functions-action@v1 - with: - app-name: - package: .output/deploy.zip - publish-profile: ${{ secrets.AZURE_FUNCTIONAPP_PUBLISH_PROFILE }} -``` - -### Optimizing Azure functions - -Consider [turning on immutable packages](https://docs.microsoft.com/en-us/azure/app-service/deploy-run-package) to support running your app from the zip file. This can speed up cold starts. diff --git a/docs/2.deploy/20.providers/cloudflare.md b/docs/2.deploy/20.providers/cloudflare.md index d68b9ab1d1..8473d191d3 100644 --- a/docs/2.deploy/20.providers/cloudflare.md +++ b/docs/2.deploy/20.providers/cloudflare.md @@ -2,179 +2,178 @@ > Deploy Nitro apps to Cloudflare. -## Cloudflare Pages +## Cloudflare Workers -**Preset:** `cloudflare_pages` +**Preset:** `cloudflare_module` -:read-more{title="Cloudflare Pages" to="https://pages.cloudflare.com/"} +:read-more{title="Cloudflare Workers" to="https://developers.cloudflare.com/workers/"} ::note -This is the recommended preset for Cloudflare deployments, please consider using the alternative ones if you need special features. +Integration with this provider is possible with [zero configuration](/deploy#zero-config-providers) supporting [workers builds (beta)](https://developers.cloudflare.com/workers/ci-cd/builds/). :: -::note -Integration with this provider is possible with [zero configuration](/deploy#zero-config-providers). +::important +To use Workers with Static Assets, you need a Nitro compatibility date set to `2024-09-19` or later. :: -Nitro automatically generates a `_routes.json` file that controls which routes get served from files and which are served from the Worker script. The auto-generated routes file can be overridden with the config option `cloudflare.pages.routes` ([read more](https://developers.cloudflare.com/pages/platform/functions/routing/#functions-invocation-routes)). - -### Building your Application using the preset - -The preset only applies for the application build process. - -If you use the [Cloudflare Pages GitHub/GitLab integration](https://developers.cloudflare.com/pages/get-started/#connect-your-git-provider-to-pages), and you don't need to preview your application locally, Nitro does not require any type of configuration. When you push to your repository, the Cloudflare Pages CI/CD process will automatically build your project and Nitro will detect the correct environment and build your application accordingly. - -If instead you want preview your application locally and/or manually deploy it, when building the application you will need to let Nitro know that the target environment is the Cloudflare Pages one, you can do that in two ways: - -- By defining either the `NITRO_PRESET` or the `SERVER_PRESET` environment variable set to `cloudflare_pages` when running the build process, like so: - - ```bash - NITRO_PRESET=cloudflare_pages npm run build - ``` - -- Or by updating your Nitro [preset configuration](/config#preset): +The following shows an example `nitro.config.ts` file for deploying a Nitro app to Cloudflare Workers. - ```json5 - "preset": "cloudflare_pages", - ``` +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; - and then running the standard build command: +export default defineNitroConfig({ + compatibilityDate: "2024-09-19", + preset: "cloudflare_module", + cloudflare: { + deployConfig: true, + nodeCompat: true + } +}) +``` - :pm-run{script="build"} +By setting `deployConfig: true`, Nitro will automatically generate a `wrangler.json` for you with the correct configuration. +If you need to add [Cloudflare Workers configuration](https://developers.cloudflare.com/workers/wrangler/configuration/), such as [bindings](https://developers.cloudflare.com/workers/runtime-apis/bindings/), you can either: -### Wrangler +- Set these in your Nitro config under the `cloudflare: { wrangler : {} }`. This has the same type as `wrangler.json`. +- Provide your own `wrangler.json`. Nitro will merge your config with the appropriate settings, including pointing to the build output. -To preview your application locally or manually deploy it you will need to use the [wrangler](https://github.com/cloudflare/workers-sdk/tree/main/packages/wrangler) CLI tool, simply install it as a node dependency: +### Local Preview -:pm-install{name="wrangler"} +You can use [Wrangler](https://github.com/cloudflare/workers-sdk/tree/main/packages/wrangler) to preview your app locally: -### Preview your app locally +:pm-run{script="build"} -After having built your application you can preview it locally with wrangler by running: +:pm-x{command="wrangler dev"} -:pm-x{command="wrangler pages dev dist"} +### Manual Deploy -### Deploy from your local machine using wrangler +After having built your application you can manually deploy it with Wrangler. -After having built your application you can manually deploy it with wrangler, in order to do so first make sure to be -logged into your Cloudflare account: +First make sure to be logged into your Cloudflare account: :pm-x{command="wrangler login"} Then you can deploy the application with: -:pm-x{command="wrangler pages deploy dist"} +:pm-x{command="wrangler deploy"} -## Cloudflare Module Workers +### Runtime Hooks -**Preset:** `cloudflare_module` +You can use [runtime hooks](/docs/plugins#nitro-runtime-hooks) below in order to extend [Worker handlers](https://developers.cloudflare.com/workers/runtime-apis/handlers/). -::note -**Note:** This preset uses the [module worker syntax](https://developers.cloudflare.com/workers/learning/migrating-to-module-workers/) for deployment. -:: +:read-more{to="/docs/plugins#nitro-runtime-hooks"} -When using Workers you will need a `wrangler.toml` file, in your root directory. To using Workers with [Static Assets](https://developers.cloudflare.com/workers/static-assets/) (BETA with [limitations](https://developers.cloudflare.com/workers/static-assets/#limitations)), you also need a compatibility date set to `2024-09-19` or later, in your `wrangler.toml` file and nitro configuration file. +- [`cloudflare:scheduled`](https://developers.cloudflare.com/workers/runtime-apis/handlers/scheduled/) +- [`cloudflare:email`](https://developers.cloudflare.com/email-routing/email-workers/runtime-api/) +- [`cloudflare:queue`](https://developers.cloudflare.com/queues/configuration/javascript-apis/#consumer) +- [`cloudflare:tail`](https://developers.cloudflare.com/workers/runtime-apis/handlers/tail/) +- `cloudflare:trace` -The following shows a typical `wrangler.toml` file and a `nitro.config.ts` file for a Nitro application: +### Additional Exports -::code-group +You can add a `exports.cloudflare.ts` file to your project root to export additional handlers or properties to the Cloudflare Worker entrypoint. -```ts [nitro.config.ts] -export default defineNitroConfig({ - compatibilityDate: "2024-09-19", -}) +```ts [exports.cloudflare.ts] +export class MyWorkflow extends WorkflowEntrypoint { + async run(event: WorkflowEvent, step: WorkflowStep) { + // ... + } +} ``` -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - compatibilityDate: "2024-09-19", -}) -``` +Nitro will automatically detect this file and include its exports in the final build. +::warning +The `exports.cloudflare.ts` file must not have a default export. :: -```ini [wrangler.toml] -name = "nitro-app" -compatibility_date = "2024-09-19" -main = "./.output/server/index.mjs" -assets = { directory = "./.output/public/", binding = "ASSETS" } -``` - +You can also customize the entrypoint file location using the `cloudflare.exports` option in your `nitro.config.ts`: +```ts [nitro.config.ts] +export default defineConfig({ + cloudflare: { + exports: "custom-exports-entry.ts" + } +}) +``` -## Runtime hooks +### Scheduled Tasks (Cron Triggers) -You can use [runtime hooks](/guide/plugins#nitro-runtime-hooks) below in order to extend [worker handlers](https://developers.cloudflare.com/workers/runtime-apis/handlers/). +When using [Nitro tasks](/docs/tasks) with `scheduledTasks`, Nitro automatically generates [Cron Triggers](https://developers.cloudflare.com/workers/configuration/cron-triggers/) in the wrangler config at build time. -:read-more{to="/guide/plugins#nitro-runtime-hooks"} +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; -- [`cloudflare:scheduled`](https://developers.cloudflare.com/workers/runtime-apis/handlers/scheduled/) -- [`cloudflare:email`](https://developers.cloudflare.com/email-routing/email-workers/runtime-api/) -- [`cloudflare:queue`](https://developers.cloudflare.com/queues/configuration/javascript-apis/#consumer) -- [`cloudflare:tail`](https://developers.cloudflare.com/workers/runtime-apis/handlers/tail/) -- `cloudflare:trace` +export default defineNitroConfig({ + preset: "cloudflare_module", + experimental: { + tasks: true, + }, + scheduledTasks: { + "* * * * *": ["cms:update"], + "0 15 1 * *": ["db:cleanup"], + }, + cloudflare: { + deployConfig: true, + }, +}) +``` +No manual Wrangler configuration is needed - Nitro handles it for you. -### Preview your app locally +## Cloudflare Pages -You can use [wrangler](https://github.com/cloudflare/workers-sdk/tree/main/packages/wrangler), to preview your app locally: +**Preset:** `cloudflare_pages` -```bash -NITRO_PRESET=cloudflare npm run build +:read-more{title="Cloudflare Pages" to="https://pages.cloudflare.com/"} -# If you have added a 'wrangler.toml' file like above in the root of your project: -npx wrangler dev +::note +Integration with this provider is possible with [zero configuration](/deploy#zero-config-providers). +:: -# If you don't have a 'wrangler.toml', directly use: -npx wrangler dev .output/server/index.mjs --site .output/public -``` +::warning +Cloudflare [Workers Module](#cloudflare-workers) is the new recommended preset for deployments. Please consider using the pages only if you need specific features. +:: -### Deploy from your local machine using wrangler +The following shows an example `nitro.config.ts` file for deploying a Nitro app to Cloudflare Pages. -Install [wrangler](https://github.com/cloudflare/workers-sdk/tree/main/packages/wrangler) and login to your Cloudflare account: +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; -```bash -npm i wrangler -wrangler login +export default defineNitroConfig({ + preset: "cloudflare_pages", + cloudflare: { + deployConfig: true, + nodeCompat:true + } +}) ``` -Generate your app using the `cloudflare_module` preset: +Nitro automatically generates a `_routes.json` file that controls which routes get served from files and which are served from the Worker script. The auto-generated routes file can be overridden with the config option `cloudflare.pages.routes` ([read more](https://developers.cloudflare.com/pages/platform/functions/routing/#functions-invocation-routes)). -```bash -NITRO_PRESET=cloudflare_module npm run build -``` +### Local Preview -You can then preview it locally: +You can use [Wrangler](https://github.com/cloudflare/workers-sdk/tree/main/packages/wrangler) to preview your app locally: -```bash -# If you have a 'wrangler.toml' like above: -npx wrangler dev +:pm-run{script="build"} -# If you don't have a 'wrangler.toml': -npx wrangler dev .output/server/index.mjs --site .output/public -``` +:pm-x{command="wrangler pages dev"} -and publish it: +### Manual Deploy -:pm-x{command="wrangler deploy"} +After having built your application you can manually deploy it with Wrangler, in order to do so first make sure to be +logged into your Cloudflare account: -## Cloudflare Service Workers +:pm-x{command="wrangler login"} -**Preset:** `cloudflare` +Then you can deploy the application with: -::note -**Note:** This preset uses the [service worker syntax](https://developers.cloudflare.com/workers/learning/service-worker/) for deployment. -:: +:pm-x{command="wrangler pages deploy"} -::warning -**Note:** This preset is deprecated. -:: - -The way this preset works is identical to that of the `cloudflare_module` one presented above, with the only difference being that such preset inherits all the [disadvantages](https://developers.cloudflare.com/workers/reference/migrate-to-module-workers/#advantages-of-migrating) that such syntax brings. ## Deploy within CI/CD using GitHub Actions -Regardless on whether you're using Cloudflare Pages or Cloudflare workers, you can use the [Wrangler GitHub actions](https://github.com/marketplace/actions/deploy-to-cloudflare-workers-with-wrangler) to deploy your application. +Regardless on whether you're using Cloudflare Pages or Cloudflare Workers, you can use the [Wrangler GitHub actions](https://github.com/marketplace/actions/deploy-to-cloudflare-workers-with-wrangler) to deploy your application. ::note **Note:** Remember to [instruct Nitro to use the correct preset](/deploy#changing-the-deployment-preset) (note that this is necessary for all presets including the `cloudflare_pages` one). @@ -191,12 +190,15 @@ Make sure to only access environment variables **within the event lifecycle** a **Example:** If you have set the `SECRET` and `NITRO_HELLO_THERE` environment variables set you can access them in the following way: ```ts +import { defineHandler } from "nitro"; +import { useRuntimeConfig } from "nitro/runtime-config"; + console.log(process.env.SECRET) // note that this is in the global scope! so it doesn't actually work and the variable is undefined! -export default defineEventHandler((event) => { +export default defineHandler((event) => { // note that all the below are valid ways of accessing the above mentioned variables - useRuntimeConfig(event).helloThere - useRuntimeConfig(event).secret + useRuntimeConfig().helloThere + useRuntimeConfig().secret process.env.NITRO_HELLO_THERE import.meta.env.SECRET }); @@ -204,7 +206,7 @@ export default defineEventHandler((event) => { ### Specify Variables in Development Mode -For development, you can use a `.env` file to specify environment variables: +For development, you can use a `.env` or `.env.local` file to specify environment variables: ```ini NITRO_HELLO_THERE="captain" @@ -212,14 +214,14 @@ SECRET="top-secret" ``` ::note -**Note:** Make sure you add `.env` to the `.gitignore` file so that you don't commit it as it can contain sensitive information. +**Note:** Make sure you add `.env` and `.env.local` to the `.gitignore` file so that you don't commit it as it can contain sensitive information. :: ### Specify Variables for local previews After build, when you try out your project locally with `wrangler dev` or `wrangler pages dev`, in order to have access to environment variables you will need to specify the in a `.dev.vars` file in the root of your project (as presented in the [Pages](https://developers.cloudflare.com/pages/functions/bindings/#interact-with-your-environment-variables-locally) and [Workers](https://developers.cloudflare.com/workers/configuration/environment-variables/#interact-with-environment-variables-locally) documentation). -If you are using a `.env` file while developing, your `.dev.vars` should be identical to it. +If you are using a `.env` or `.env.local` file while developing, your `.dev.vars` should be identical to it. ::note **Note:** Make sure you add `.dev.vars` to the `.gitignore` file so that you don't commit it as it can contain sensitive information. @@ -227,18 +229,20 @@ If you are using a `.env` file while developing, your `.dev.vars` should be iden ### Specify Variables for Production -For production, use the cloudflare dashboard or the [`wrangler secret`](https://developers.cloudflare.com/workers/wrangler/commands/#secret) command to set environment variables and secrets. +For production, use the Cloudflare dashboard or the [`wrangler secret`](https://developers.cloudflare.com/workers/wrangler/commands/#secret) command to set environment variables and secrets. -### Specify Variables using `wrangler.toml` +### Specify Variables using `wrangler.toml`/`wrangler.json` -You can specify a custom `wrangler.toml` file and define vars inside. +You can specify a custom `wrangler.toml`/`wrangler.json` file and define vars inside. ::warning -Note that this isn't recommend for sensitive data. +Note that this isn't recommend for sensitive data like secrets. :: **Example:** +::code-group + ```ini [wrangler.toml] # Shared [vars] @@ -251,7 +255,27 @@ NITRO_HELLO_THERE="captain" SECRET="top-secret" ``` -## Direct access to cloudflare bindings +```json [wrangler.json] +{ + "vars": { + "NITRO_HELLO_THERE": "general", + "SECRET": "secret" + }, + "env": { + "production": { + "vars": { + "NITRO_HELLO_THERE": "captain", + "SECRET": "top-secret" + } + } + } +} + +``` + +:: + +## Direct access to Cloudflare bindings Bindings are what allows you to interact with resources from the Cloudflare platform, examples of such resources are key-value data storages ([KVs](https://developers.cloudflare.com/kv/)) and serverless SQL databases ([D1s](https://developers.cloudflare.com/d1/)). @@ -260,30 +284,31 @@ For more details on Bindings and how to use them please refer to the Cloudflare :: > [!TIP] -> Nitro provides high level API to interact with primitives such as [KV Storage](/guide/storage) and [Database](/guide/database) and you are highly recommended to prefer using them instead of directly depending on low-level APIs for usage stability. +> Nitro provides high level API to interact with primitives such as [KV Storage](/docs/storage) and [Database](/docs/database) and you are highly recommended to prefer using them instead of directly depending on low-level APIs for usage stability. -:read-more{title="Database Layer" to="/guide/database"} +:read-more{title="Database Layer" to="/docs/database"} -:read-more{title="KV Storage" to="/guide/storage"} +:read-more{title="KV Storage" to="/docs/storage"} -In runtime, you can access bindings from the request event, by accessing its `context.cloudflare.env` field, this is for example how you can access a D1 bindings: +In runtime, you can access bindings from the request event via `event.req.runtime.cloudflare.env`. This is for example how you can access a D1 binding: ```ts -defineEventHandler(async (event) => { - const { cloudflare } = event.context - const stmt = await cloudflare.env.MY_D1.prepare('SELECT id FROM table') +import { defineHandler } from "nitro"; + +defineHandler(async (event) => { + const { env } = event.req.runtime.cloudflare + const stmt = await env.MY_D1.prepare('SELECT id FROM table') const { results } = await stmt.all() }) ``` -### Access to the bindings in local env +### Access to the bindings in local dev -In order to access bindings during local dev mode, regardless of the chosen preset, it is recommended to use a `wrangler.toml` file (as well as a `.dev.vars` one) in combination with the [`nitro-cloudflare-dev` module](https://github.com/nitrojs/nitro-cloudflare-dev) as illustrated below. +To access bindings in dev mode, we first define them. You can do this in a `wrangler.jsonc`/`wrangler.json`/`wrangler.toml` file -> [!NOTE] -> The `nitro-cloudflare-dev` module is experimental. The Nitro team is looking into a more native integration which could in the near future make the module unneeded. +For example, to define a variable and a KV namespace in `wrangler.toml`: -In order to access bindings in dev mode we start by defining the bindings in a `wrangler.toml` file, this is for example how you would define a variable and a KV namespace: +::code-group ```ini [wrangler.toml] [vars] @@ -294,35 +319,45 @@ binding = "MY_KV" id = "xxx" ``` -> [!NOTE] -> Only bindings in the default environment are recognized. - -Next we install the `nitro-cloudflare-dev` module as well as the required `wrangler` package (if not already installed): +```json [wrangler.json] +{ + "vars": { + "MY_VARIABLE": "my-value", + }, + "kv_namespaces": [ + { + "binding": "MY_KV", + "id": "xxx" + } + ] +} +``` -:pm-install{name="-D nitro-cloudflare-dev wrangler"} +:: -Then define module: +Next we install the required `wrangler` package (if not already installed): -::code-group +:pm-install{name="wrangler -D"} -```js [nitro.config.js] -import nitroCloudflareBindings from "nitro-cloudflare-dev"; +From this moment, when running -export default defineNitroConfig({ - modules: [nitroCloudflareBindings], -}); -``` +:pm-run{script="dev"} -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - modules: ['nitro-cloudflare-dev'] -}) -``` +you will be able to access the `MY_VARIABLE` and `MY_KV` from the request event just as illustrated above. -:: +#### Wrangler environments -From this moment, when running +If you have multiple Wrangler environments, you can specify which Wrangler environment to use during Cloudflare dev emulation: -:pm-run{script="dev"} +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; -you will be able to access the `MY_VARIABLE` and `MY_KV` from the request event just as illustrated above. +export default defineNitroConfig({ + preset: 'cloudflare_module', + cloudflare: { + dev: { + environment: 'preview' + } + } +}) +``` diff --git a/docs/2.deploy/20.providers/deno-deploy.md b/docs/2.deploy/20.providers/deno-deploy.md index cbfd6387c4..861ab11428 100644 --- a/docs/2.deploy/20.providers/deno-deploy.md +++ b/docs/2.deploy/20.providers/deno-deploy.md @@ -21,7 +21,7 @@ cd .output deployctl deploy --project=my-project server/index.ts ``` -## Deploy within CI/CD using gitHub actions +## Deploy within CI/CD using GitHub actions You just need to include the deployctl GitHub Action as a step in your workflow. @@ -43,9 +43,9 @@ on: jobs: deploy: steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - run: corepack enable - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v6 with: node-version: 18 cache: pnpm diff --git a/docs/2.deploy/20.providers/digitalocean.md b/docs/2.deploy/20.providers/digitalocean.md index 41537f2c63..2a85097259 100644 --- a/docs/2.deploy/20.providers/digitalocean.md +++ b/docs/2.deploy/20.providers/digitalocean.md @@ -23,7 +23,7 @@ ```json { "engines": { - "node": "16.x" + "node": "20.x" } } ``` diff --git a/docs/2.deploy/20.providers/edgio.md b/docs/2.deploy/20.providers/edgio.md deleted file mode 100644 index 1503432806..0000000000 --- a/docs/2.deploy/20.providers/edgio.md +++ /dev/null @@ -1,47 +0,0 @@ -# Edgio - -> Deploy Nitro apps to Edgio. - -**Preset:** `edgio` - -:read-more{title="edgio.io" to="https://edg.io/"} - -Edgio (formerly Layer0) extends the capabilities of a traditional CDN by not only hosting your static content, but also providing server-side rendering for progressive web applications as well as caching both your APIs and HTML at the network edge to provide your users with the fastest browsing experience. - -If this is your first time deploying to Edgio, the interactive CLI as part of the `deploy` command will prompt to authenticate using your browser. You may also [sign up](https://app.layer0.co/signup) prior to deployment. - -## Install the Eedgio CLI - -```bash -npm i -g @edgio/cli -``` - -## Testing production build locally with Edgio - -You can use Nitropack to test your app's development experience locally: - -```bash -NITRO_PRESET=edgio npx nitropack build -``` - -To simulate on local how your app would run in production with Edgio, run the following command: - -```bash -edgio build && edgio run --production -``` - -## Deploying from your local machine - -Once you have tested your application locally, you may deploy using: - -```bash -edgio deploy -``` - -## Deploying using CI/CD - -If you are deploying from a non-interactive environment, you will need to create an account on [Edgio Developer Console](https://app.layer0.co) first and setup a [deploy token](https://docs.edg.io/guides/basics/deployments#deploy-from-ci). Once the deploy token is created, save it as a secret to your environment. You can start the deploy by running: - -```bash -edgio deploy --token=XXX -``` diff --git a/docs/2.deploy/20.providers/firebase.md b/docs/2.deploy/20.providers/firebase.md index 6e1a9ca69c..d0633c36a8 100644 --- a/docs/2.deploy/20.providers/firebase.md +++ b/docs/2.deploy/20.providers/firebase.md @@ -1,23 +1,17 @@ # Firebase -> Deploy Nitro apps to Firebase hosting. +> Deploy Nitro apps to Firebase. ::note You will need to be on the [**Blaze plan**](https://firebase.google.com/pricing) (Pay as you go) to get started. :: - - -## Firebase hosting - -**Preset:** `firebase` - -:read-more{title="Firebase Hosting" to="https://firebase.google.com/docs/hosting"} - -::important -This preset will deploy to firebase functions 1st gen by default. If you want to deploy to firebase functions 2nd gen, see the [instructions below](#using-2nd-generation-firebase-functions). -:: - -### Project Setup - -#### Using firebase CLI (recommended) - -You may instead prefer to set up your project with the Firebase CLI, which will fetch your project ID for you, add required dependencies (see above) and even set up automated deployments via GitHub Actions (for hosting only). [Learn about installing the firebase CLI](https://firebase.google.com/docs/cli#windows-npm). - -1. Install firebase CLI globally - -Always try to use the latest version of the Firebase CLI. - -```bash -npm install -g firebase-tools@latest -``` - -**Note**: You need to be on [^11.18.0](https://github.com/firebase/firebase-tools/releases/tag/v11.18.0) to deploy a `nodejs18` function. - -2. Initialize your firebase project - -```bash -firebase login -firebase init hosting -``` - -When prompted, you can enter `.output/public` as the public directory. In the next step, **do not** configure your project as a single-page app. - -Once complete, add the following to your `firebase.json` to enable server rendering in Cloud Functions: - -```json [firebase.json] -{ - "functions": { "source": ".output/server" }, - "hosting": [ - { - "site": "", - "public": ".output/public", - "cleanUrls": true, - "rewrites": [{ "source": "**", "function": "server" }] - } - ] -} -``` - -You can find more details in the [Firebase documentation](https://firebase.google.com/docs/hosting/quickstart). - -#### Alternative method - -If you don't already have a `firebase.json` in your root directory, Nitro will create one the first time you run it. In this file, you will need to replace `` with the ID of your Firebase project. This file should then be committed to the git. - -1. Create a `.firebaserc` file - -It is recommended to create a `.firebaserc` file so you don't need to manually pass your project ID to your `firebase` commands (with `--project `): - -```json [.firebaserc] -{ - "projects": { - "default": "" - } -} -``` - -This file is usually generated when you initialize your project with the Firebase CLI. But if you don't have one, you can create it manually. - -2. Install firebase dependencies - -Then, add Firebase dependencies to your project: - -:pm-install{name="firebase-admin firebase-functions firebase-functions-test" dev} - -3. Log into the firebase CLI - -Make sure you are authenticated with the firebase cli. Run this command and follow the prompts: - -:pm-x{command="firebase-tools login"} - -### Local preview - -You can preview a local version of your site if you need to test things out without deploying. - -```bash -NITRO_PRESET=firebase npm run build -firebase emulators:start -``` - -### Build and deploy - -Deploy to Firebase Hosting by running a Nitro build and then running the `firebase deploy` command. - -```bash -NITRO_PRESET=firebase npm run build -``` - -:pm-x{command="firebase-tools deploy"} - -If you installed the Firebase CLI globally, you can also run: - -```bash -firebase deploy -``` - -### Using 2nd generation firebase functions + - Choose a unique ID for your backend. +4. Click Finish & Deploy to create your first rollout. -- [Comparison between 1st and 2nd generation functions](https://firebase.google.com/docs/functions/version-comparison) - -To switch to the more recent and, recommended generation of firebase functions, set the `firebase.gen` option to `2`: - -::code-group - -```ts{3} [nitro.config.ts] -export default defineNitroConfig({ - firebase: { - gen: 2 - // ... - } -}) -``` - -```ts{4} [nuxt.config.ts] -export default defineNuxtConfig({ - nitro: { - firebase: { - gen: 2 - // ... - } - } -}) -``` - -:: - -::note -If you cannot use configuration for any reason, alternatively you can use `NITRO_FIREBASE_GEN` environment variable. -:: - -If you already have a deployed version of your website and want to upgrade to 2nd gen, [see the Migration process on Firebase docs](https://firebase.google.com/docs/functions/2nd-gen-upgrade). Namely, the CLI will ask you to delete your existing functions before deploying the new ones. - -### Options - -You can set options for the firebase functions in your `nitro.config.ts` file: - -::code-group - -```ts [nitro.config.ts] -export default defineNitroConfig({ - firebase: { - gen: 2, - httpsOptions: { - region: 'europe-west1', - maxInstances: 3, - }, - }, -}); -``` - -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - nitro: { - firebase: { - gen: 2, - httpsOptions: { - region: 'europe-west1', - maxInstances: 3, - }, - }, - }, -}); -``` - -:: - -You can also set options for 1st generation Cloud Functions if the `gen` option is set to `1`. Note these are different from the options for 2nd generation Cloud Functions. - -#### Runtime Node.js version - -You can set custom Node.js version in configuration: - -::code-group - -```ts [nitro.config.ts] -export default defineNitroConfig({ - firebase: { - nodeVersion: "20" // Can be "16", "18", "20" or "22" - }, -}); -``` - -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - nitro: { - firebase: { - nodeVersion: "20" // Can be "16", "18", "20" or "22" - }, - }, -}); -``` - -:: - -Firebase tools use the `engines.node` version in `package.json` to determine which node version to use for your functions. Nitro automatically writes to the `.output/server/package.json` with configured Node.js version. - -You might also need to add a runtime key to your `firebase.json` file: - -```json [firebase.json] -{ - "functions": { - "source": ".output/server", - "runtime": "nodejs20" - } -} -``` - -You can read more about this in [Firebase Docs](https://firebase.google.com/docs/functions/manage-functions?gen=2nd#set_nodejs_version). - -### If your firebase project has other cloud functions - -You may be warned that other cloud functions will be deleted when you deploy your nitro project. This is because nitro will deploy your entire project to firebase functions. If you want to deploy only your nitro project, you can use the `--only` flag: - -```bash -firebase deploy --only functions:server,hosting -``` - -### Advanced - -#### Renaming function - -When deploying multiple apps within the same Firebase project, you must give your server a unique name in order to avoid overwriting -your functions. - -You can specify a new name for the deployed Firebase function in your configuration: - -::code-group - -```ts [nitro.config.ts] -export default defineNitroConfig({ - firebase: { - serverFunctionName: "" - } -}) -``` - -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - nitro: { - firebase: { - serverFunctionName: "" - } - } -}) -``` - -:: - -::important -`firebase.serverFunctionName` must be a valid JS variable name and cannot include dashes (`-`). -:: +When you deploy with Firebase App Hosting, the App Hosting preset will be run automatically at build time. diff --git a/docs/2.deploy/20.providers/flightcontrol.md b/docs/2.deploy/20.providers/flightcontrol.md index 9dbf49bdd9..535bc15c22 100644 --- a/docs/2.deploy/20.providers/flightcontrol.md +++ b/docs/2.deploy/20.providers/flightcontrol.md @@ -6,10 +6,6 @@ :read-more{title="flightcontrol.dev" to="https://flightcontrol.dev?ref=nitro"} -::note -Flightcontrol has zero config support for [Nuxt](https://nuxt.com/) projects. -:: - ## Set Up your flightcontrol account On a high level, the steps you will need to follow to deploy a project for the first time are: diff --git a/docs/2.deploy/20.providers/github-pages.md b/docs/2.deploy/20.providers/github-pages.md index 5fc7d6620d..bec179ba35 100644 --- a/docs/2.deploy/20.providers/github-pages.md +++ b/docs/2.deploy/20.providers/github-pages.md @@ -28,9 +28,9 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - run: corepack enable - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v6 with: node-version: "18" diff --git a/docs/2.deploy/20.providers/heroku.md b/docs/2.deploy/20.providers/heroku.md index 08e7696b8c..6f5e417ccf 100644 --- a/docs/2.deploy/20.providers/heroku.md +++ b/docs/2.deploy/20.providers/heroku.md @@ -39,7 +39,7 @@ 1. Add the heroku Nginx buildpack [here](https://github.com/heroku/heroku-buildpack-nginx.git) -1. Change to the 'node' preset in your `nuxt.config` +1. Change to the 'node' preset in your `nitro.config` ```json5 "nitro": { @@ -68,7 +68,7 @@ ```ts import fs from "fs" - export default defineNitroPlugin((nitroApp) => { + export default definePlugin((nitroApp) => { if((process.env.NODE_ENV || 'development') != 'development') { fs.openSync('/tmp/app-initialized', 'w') } diff --git a/docs/2.deploy/20.providers/iis.md b/docs/2.deploy/20.providers/iis.md index 84d857eca0..94539c0996 100644 --- a/docs/2.deploy/20.providers/iis.md +++ b/docs/2.deploy/20.providers/iis.md @@ -14,7 +14,7 @@ ## Using IIS handler -**Preset:** `iis_handler` / `iis` +**Preset:** `iis_handler` You can use IIS http handler directly. @@ -24,9 +24,9 @@ You can use IIS http handler directly. ## IIS config options -::code-group - ```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + export default defineNitroConfig({ // IIS options default iis: { @@ -37,19 +37,3 @@ export default defineNitroConfig({ }, }); ``` - -```ts [nuxt.config.ts] -export default defineNuxtConfig({ - nitro: { - // IIS options default - iis: { - // merges in a pre-existing web.config file to the nitro default file - mergeConfig: true, - // overrides the default nitro web.config file all together - overrideConfig: false, - }, - }, -}); -``` - -:: diff --git a/docs/2.deploy/20.providers/netlify.md b/docs/2.deploy/20.providers/netlify.md index 71a65766ed..4ed6cdb2d4 100644 --- a/docs/2.deploy/20.providers/netlify.md +++ b/docs/2.deploy/20.providers/netlify.md @@ -39,18 +39,6 @@ Nitro output can directly run the server at the edge. Closer to your users. Make sure the publish directory is set to `dist` when creating a new project. :: -## On-demand builders - -**Preset:** `netlify_builder` - -::warning -**Note:** This preset is deprecated. Instead, use the `netlify` preset with the `isr` route rule. -:: - -On-demand Builders are serverless functions used to generate web content as needed that’s automatically cached on Netlify’s Edge CDN. They enable you to build pages for your site when a user visits them for the first time and then cache them at the edge for subsequent visits. - -:read-more{title="Netlify On-demand Builders" to="https://docs.netlify.com/configure-builds/on-demand-builders/"} - ## Custom deploy configuration You can provide additional deploy configuration using the `netlify` key inside `nitro.config`. It will be merged with built-in auto-generated config. Currently the only supported value is `images.remote_images`, for [configuring Netlify Image CDN](https://docs.netlify.com/image-cdn/create-integration/). diff --git a/docs/2.deploy/20.providers/platform-sh.md b/docs/2.deploy/20.providers/platform-sh.md index d437100629..6701406570 100644 --- a/docs/2.deploy/20.providers/platform-sh.md +++ b/docs/2.deploy/20.providers/platform-sh.md @@ -14,7 +14,7 @@ Then in repository create `.platform.app.yaml` file: ```yaml [.platform.app.yaml] name: nitro-app -type: 'nodejs:18' +type: 'nodejs:20' disk: 128 web: commands: @@ -25,7 +25,7 @@ hooks: build: | corepack enable npx nypm install - NITR_PRESET=platform_sh npm run build + NITRO_PRESET=platform_sh npm run build mounts: '.data': source: local diff --git a/docs/2.deploy/20.providers/render.md b/docs/2.deploy/20.providers/render.md index 3723e9c701..b337b3ce31 100644 --- a/docs/2.deploy/20.providers/render.md +++ b/docs/2.deploy/20.providers/render.md @@ -11,7 +11,7 @@ 1. [Create a new Web Service](https://dashboard.render.com/select-repo?type=web) and select the repository that contains your code. 2. Ensure the 'Node' environment is selected. 3. Update the start command to `node .output/server/index.mjs` -4. Click 'Advanced' and add an environment variable with `NITRO_PRESET` set to `render_com`. You may also need to add a `NODE_VERSION` environment variable set to `18` for the build to succeed ([docs](https://render.com/docs/node-version)). +4. Click 'Advanced' and add an environment variable with `NITRO_PRESET` set to `render_com`. You may also need to add a `NODE_VERSION` environment variable set to `20` for the build to succeed ([docs](https://render.com/docs/node-version)). 5. Click 'Create Web Service'. ## Infrastructure as Code (IaC) diff --git a/docs/2.deploy/20.providers/vercel.md b/docs/2.deploy/20.providers/vercel.md index a6c61c0e44..e835edf324 100644 --- a/docs/2.deploy/20.providers/vercel.md +++ b/docs/2.deploy/20.providers/vercel.md @@ -1,38 +1,123 @@ # Vercel -> Deploy Nitro apps to Vercel Functions. +> Deploy Nitro apps to Vercel. **Preset:** `vercel` -:read-more{title="Vercel Functions" to="https://vercel.com/docs/functions"} +:read-more{title="Vercel Framework Support" to="https://vercel.com/docs/frameworks"} ::note Integration with this provider is possible with [zero configuration](/deploy/#zero-config-providers). :: -## Deploy using git +## Getting started -1. Push your code to your git repository (GitHub, GitLab, Bitbucket). -2. [Import your project](https://vercel.com/new) into Vercel. -3. Vercel will detect that you are using Nitro and will enable the correct settings for your deployment. -4. Your application is deployed! +Deploying to Vercel comes with the following features: +- [Preview deployments](https://vercel.com/docs/deployments/environments) +- [Fluid compute](https://vercel.com/docs/fluid-compute) +- [Observability](https://vercel.com/docs/observability) +- [Vercel Firewall](https://vercel.com/docs/vercel-firewall) -After your project has been imported and deployed, all subsequent pushes to branches will generate [Preview Deployments](https://vercel.com/docs/concepts/deployments/environments#preview), and all changes made to the Production Branch (commonly “main”) will result in a [Production Deployment](https://vercel.com/docs/concepts/deployments/environments#production). +And much more. Learn more in [the Vercel documentation](https://vercel.com/docs). -Learn more about Vercel’s [Git Integration](https://vercel.com/docs/concepts/git). +### Deploy with Git -## Monorepo - -Monorepos are supported by Vercel. However a custom "[Root Directory](https://vercel.com/docs/deployments/configure-a-build#root-directory)" must be specified in "Project Settings > General" tab. Make sure that "Include source files outside of the Root Directory" is checked. - -Examples of values for "Root Directory": `apps/web` or `packages/app`. +Vercel supports Nitro with zero-configuration. [Deploy Nitro to Vercel now](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fvercel%2Ftree%2Fmain%2Fexamples%2Fnitro). ## API routes Nitro `/api` directory isn't compatible with Vercel. Instead, you should use: - `routes/api/` for standalone usage -- `server/api/` with [Nuxt](https://nuxt.com). + +## Bun runtime + +:read-more{title="Vercel" to="https://vercel.com/docs/functions/runtimes/bun"} + +You can use [Bun](https://bun.com) instead of Node.js by specifying the runtime using the `vercel.functions` key inside `nitro.config`: + +```ts [nitro.config.ts] +export default defineNitroConfig({ + vercel: { + functions: { + runtime: "bun1.x" + } + } +}) +``` + +Alternatively, Nitro also detects Bun automatically if you specify a `bunVersion` property in your `vercel.json`: + +```json [vercel.json] +{ + "$schema": "https://openapi.vercel.sh/vercel.json", + "bunVersion": "1.x" +} +``` + +## Proxy route rules + +Nitro automatically optimizes `proxy` route rules on Vercel by generating [CDN-level rewrites](https://vercel.com/docs/rewrites) at build time. This means matching requests are proxied at the edge without invoking a serverless function, reducing latency and cost. + +```ts [nitro.config.ts] +export default defineNitroConfig({ + routeRules: { + // Proxied at CDN level — no function invocation + "/api/**": { + proxy: "https://api.example.com/**", + }, + }, +}); +``` + +### When CDN rewrites apply + +A proxy rule is offloaded to a Vercel CDN rewrite when **all** of the following are true: + +- The target is an **external URL** (starts with `http://` or `https://`). +- No advanced `ProxyOptions` are set on the rule. + +### Fallback to runtime proxy + +When the proxy rule uses any of the following `ProxyOptions`, Nitro keeps it as a runtime proxy handled by the serverless function: + +- `headers` — custom headers on the outgoing request to the upstream +- `forwardHeaders` / `filterHeaders` — header filtering +- `fetchOptions` — custom fetch options +- `cookieDomainRewrite` / `cookiePathRewrite` — cookie manipulation +- `onResponse` — response callback + +::note +Response headers defined on the route rule via the `headers` option are still applied to CDN-level rewrites. Only request-level `ProxyOptions.headers` (sent to the upstream) require a runtime proxy. +:: + +## Scheduled tasks (Cron Jobs) + +:read-more{title="Vercel Cron Jobs" to="https://vercel.com/docs/cron-jobs"} + +Nitro automatically converts your [`scheduledTasks`](/docs/tasks#scheduled-tasks) configuration into [Vercel Cron Jobs](https://vercel.com/docs/cron-jobs) at build time. Define your schedules in your Nitro config and deploy - no manual `vercel.json` cron configuration required. + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + experimental: { + tasks: true + }, + scheduledTasks: { + // Run `cms:update` every hour + '0 * * * *': ['cms:update'], + // Run `db:cleanup` every day at midnight + '0 0 * * *': ['db:cleanup'] + } +}) +``` + +### Secure cron job endpoints + +:read-more{title="Securing cron jobs" to="https://vercel.com/docs/cron-jobs/manage-cron-jobs#securing-cron-jobs"} + +To prevent unauthorized access to the cron handler, set a `CRON_SECRET` environment variable in your Vercel project settings. When `CRON_SECRET` is set, Nitro validates the `Authorization` header on every cron invocation. ## Custom build output configuration @@ -49,9 +134,9 @@ To revalidate a page on demand: 2. Update your configuration: - ::code-group - ```ts [nitro.config.ts] + import { defineNitroConfig } from "nitro/config"; + export default defineNitroConfig({ vercel: { config: { @@ -61,25 +146,11 @@ To revalidate a page on demand: }) ``` - ```ts [nuxt.config.ts] - export default defineNuxtConfig({ - nitro: { - vercel: { - config: { - bypassToken: process.env.VERCEL_BYPASS_TOKEN - } - } - } - }) - ``` - - :: - 3. To trigger "On-Demand Incremental Static Regeneration (ISR)" and revalidate a path to a Prerender Function, make a GET or HEAD request to that path with a header of x-prerender-revalidate: `bypassToken`. When that Prerender Function endpoint is accessed with this header set, the cache will be revalidated. The next request to that function should return a fresh response. ### Fine-grained ISR config via route rules -By default, query paramas are ignored by cache. +By default, query params affect cache keys but are not passed to the route handler unless specified. You can pass an options object to `isr` route rule to configure caching behavior. @@ -89,8 +160,8 @@ You can pass an options object to `isr` route rule to configure caching behavior - If an empty array, query values are not considered for caching. - If `undefined` each unique query value is cached independently. - For wildcard `/**` route rules, `url` is always added - - `passQuery`: When `true`, the query string will be present on the `request` argument passed to the invoked function. The `allowQuery` filter still applies. +- `exposeErrBody`: When `true`, expose the response body regardless of status code including error status codes. (default `false` ```ts export default defineNitroConfig({ @@ -99,14 +170,9 @@ export default defineNitroConfig({ isr: { allowQuery: ["q"], passQuery: true, + exposeErrBody: true }, }, }, }); ``` - -## Vercel edge functions - -**Preset:** `vercel_edge` (deprecated) - -We recommend migrating to the default Node.js runtime and enabling [Fluid compute](https://vercel.com/docs/functions/fluid-compute). diff --git a/docs/2.deploy/20.providers/zephyr.md b/docs/2.deploy/20.providers/zephyr.md new file mode 100644 index 0000000000..77fe3aff6c --- /dev/null +++ b/docs/2.deploy/20.providers/zephyr.md @@ -0,0 +1,98 @@ +# Zephyr Cloud + +> Deploy Nitro apps to [Zephyr Cloud](https://zephyr-cloud.io). + +**Preset:** `zephyr` + +:read-more{title="Zephyr Cloud Docs" to="https://docs.zephyr-cloud.io"} + +Zephyr support is built into Nitro through the `zephyr` preset. + +For most Zephyr-specific topics such as BYOC, cloud integrations, environments, and CI/CD authentication, refer to the [Zephyr Cloud docs](https://docs.zephyr-cloud.io). + +::note +Zephyr is a little different from most Nitro deployment providers. Instead of targeting a single hosting vendor directly, Zephyr acts as a deployment control plane on top of either Zephyr-managed infrastructure or your own cloud integrations. +:: + +## BYOC model + +Zephyr supports a BYOC (Bring Your Own Cloud) model. In Zephyr's architecture, the control plane stays managed by Zephyr, while the data plane (workers and storage) runs in your cloud accounts. + +This lets you keep Zephyr's deployment workflow while using any supported Zephyr cloud integration. See the [Zephyr BYOC docs](https://docs.zephyr-cloud.io/features/byoc) for the current list of supported providers. + +## Deploy with Nitro CLI + +Use Nitro's deploy command to build and upload your app to Zephyr in one step: + +```bash +npx nitro deploy --preset zephyr +``` + +Nitro will upload the generated output using `zephyr-agent`. If `zephyr-agent` is missing, Nitro will prompt to install it locally and will install it automatically in CI. + +## Deploy during build + +Zephyr is a little different here from most Nitro providers: we recommend enabling deployment during `nitro build` and treating build as the primary deployment step. + +If your CI pipeline already runs `nitro build`, enable deployment during the build step: + +```ts [nitro.config.ts] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + preset: "zephyr", + zephyr: { + deployOnBuild: true, + }, +}); +``` + +Then your normal build command is enough: + +:pm-run{script="build"} + +After the build finishes, Nitro uploads the generated output to Zephyr, deploys it to the edge, and prints the deployment URL: + +```txt +◐ Building [Nitro] (preset: zephyr, compatibility: YYYY-MM-DD) +... +ZEPHYR Uploaded local snapshot in 110ms +ZEPHYR Deployed to Zephyr's edge in 700ms. +ZEPHYR +ZEPHYR https://my-app.zephyrcloud.app +``` + +## CI authentication + +Zephyr requires an API token for non-interactive deployments. The example below uses the simpler personal-token style setup with `ZE_SECRET_TOKEN` together with `zephyr.deployOnBuild`. + +```yaml [.github/workflows/deploy.yml] +name: Deploy with Zephyr + +on: + push: + branches: [main] + +jobs: + deploy: + runs-on: ubuntu-latest + env: + ZE_SECRET_TOKEN: ${{ secrets.ZEPHYR_AUTH_TOKEN }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + - run: npm ci + - run: npm run build +``` + +For more advanced CI/CD setups, Zephyr also documents organization-level server-token authentication using `ZE_SERVER_TOKEN`. See the [Zephyr CI/CD server token docs](https://docs.zephyr-cloud.io/features/ci-cd-server-token). + +## Options + +### `zephyr.deployOnBuild` + +Deploy to Zephyr during `nitro build` when using the `zephyr` preset. + +- Default: `false` diff --git a/docs/2.deploy/20.providers/zerops.md b/docs/2.deploy/20.providers/zerops.md index b623c97875..fef6e5e2c6 100644 --- a/docs/2.deploy/20.providers/zerops.md +++ b/docs/2.deploy/20.providers/zerops.md @@ -47,7 +47,7 @@ zerops: build: base: nodejs@20 envVariables: - SERVER_PRESET: zerops + NITRO_PRESET: zerops buildCommands: - pnpm i - pnpm run build @@ -68,7 +68,7 @@ zerops: build: base: nodejs@20 envVariables: - SERVER_PRESET: zerops-static + NITRO_PRESET: zerops-static buildCommands: - pnpm i - pnpm build diff --git a/docs/3.config/0.index.md b/docs/3.config/0.index.md index 8bcf9ae016..ff8ab02dec 100644 --- a/docs/3.config/0.index.md +++ b/docs/3.config/0.index.md @@ -10,17 +10,41 @@ icon: ri:settings-3-line ### `preset` -Use `preset` option `NITRO_PRESET` environment variable for custom **production** preset. +Use `preset` option or `NITRO_PRESET` environment variable for custom **production** preset. Preset for development mode is always `nitro_dev` and default `node_server` for production building a standalone Node.js server. The preset will automatically be detected when the `preset` option is not set and running in known environments. +```ts +export default defineNitroConfig({ + preset: "cloudflare_pages", // deploy to Cloudflare Pages +}); +``` + +### `debug` + +- Default: `false`{lang=ts} (`true`{lang=ts} when `DEBUG` environment variable is set) + +Enable debug mode for verbose logging and additional development information. + +```ts +export default defineNitroConfig({ + debug: true, +}); +``` + ### `logLevel` - Default: `3`{lang=ts} (`1`{lang=ts} when the testing environment is detected) -Log verbosity level. See [unjs/consola](https://github.com/unjs/consola?tab=readme-ov-file#log-level) for more information. +Log verbosity level. See [consola](https://github.com/unjs/consola?tab=readme-ov-file#log-level) for more information. + +```ts +export default defineNitroConfig({ + logLevel: 4, // verbose logging +}); +``` ### `runtimeConfig` @@ -28,18 +52,71 @@ Log verbosity level. See [unjs/consola](https://github.com/unjs/consola?tab=read Server runtime configuration. -**Note:**: `nitro` namespace is reserved. +**Note:** `nitro` namespace is reserved. + +```ts +export default defineNitroConfig({ + runtimeConfig: { + apiSecret: "default-secret", // override with NITRO_API_SECRET + }, +}); +``` ### `compatibilityDate` Deployment providers introduce new features that Nitro presets can leverage, but some of them need to be explicitly opted into. -Set it to latest tested date in `YY-MM-DD` format to leverage latest preset features. +Set it to latest tested date in `YYYY-MM-DD` format to leverage latest preset features. + +If this configuration is not provided, Nitro will use `"latest"` behavior by default. + +```ts +export default defineNitroConfig({ + compatibilityDate: "2025-01-01", +}); +``` + +### `static` + +- Default: `false`{lang=ts} + +Enable static site generation mode. -If this configuration is not provided, Nitro will continue using the current (v2.9) behavior for presets and show a warning. +```ts +export default defineNitroConfig({ + static: true, // prerender all routes +}); +``` ## Features +### `features` + +- Default: `{}`{lang=ts} + +Enable built-in features. + +#### `runtimeHooks` + +- Default: auto-detected (enabled if there is at least one nitro plugin) + +Enable runtime hooks for request and response. + +#### `websocket` + +- Default: `false`{lang=ts} + +Enable WebSocket support. + +```ts +export default defineNitroConfig({ + features: { + runtimeHooks: true, + websocket: true, // enable WebSocket support + }, +}); +``` + ### `experimental` - Default: `{}` @@ -48,13 +125,55 @@ Enable experimental features. #### `openAPI` +- Default: `false`{lang=ts} + Enable `/_scalar`, `/_swagger` and `/_openapi.json` endpoints. -- Default: `false` +::note +Prefer using the top-level [`openAPI`](#openapi) option for configuration. +:: + +#### `typescriptBundlerResolution` + +Enable TypeScript bundler module resolution. See [TypeScript#51669](https://github.com/microsoft/TypeScript/pull/51669). + +#### `asyncContext` + +Enable native async context support for `useRequest()`. + +#### `sourcemapMinify` + +Set to `false` to disable experimental sourcemap minification. + +#### `envExpansion` -To define the OpenAPI specification on your routes, take a look at [defineRouteMeta](/guide/routing#route-meta) +Allow env expansion in runtime config. See [#2043](https://github.com/nitrojs/nitro/pull/2043). -You can pass an object on the root level to modify your OpenAPI specification: +#### `database` + +Enable experimental database support. See [Database](/docs/database). + +#### `tasks` + +Enable experimental tasks support. See [Tasks](/docs/tasks). + +```ts +export default defineNitroConfig({ + experimental: { + typescriptBundlerResolution: true, + asyncContext: true, + envExpansion: true, + database: true, + tasks: true, + }, +}); +``` + +### `openAPI` + +Top-level OpenAPI configuration. + +You can pass an object to modify your OpenAPI specification: ```js openAPI: { @@ -66,7 +185,7 @@ openAPI: { } ``` -Theses routes are disabled by default in production. To enable them, use the `production` key. +These routes are disabled by default in production. To enable them, use the `production` key. `"runtime"` allows middleware usage, and `"prerender"` is the most efficient because the JSON response is constant. ```js @@ -104,14 +223,6 @@ openAPI: { } ``` -#### `wasm` - -Enable WASM support - -#### `legacyExternals` - -When enabled, legacy (unstable) experimental rollup externals algorithm will be used. - ### `future` - Default: `{}` @@ -122,39 +233,116 @@ New features pending for a major version to avoid breaking changes. Uses built-in SWR functionality (using caching layer and storage) for Netlify and Vercel presets instead of falling back to ISR behavior. +```ts +export default defineNitroConfig({ + future: { + nativeSWR: true, + }, +}); +``` + ### `storage` - Default: `{}` -Storage configuration, read more in the [Storage Layer](/guide/storage) section. +Storage configuration, read more in the [Storage Layer](/docs/storage) section. + +```ts +export default defineNitroConfig({ + storage: { + redis: { + driver: "redis", + url: "redis://localhost:6379", + }, + }, +}); +``` + +### `devStorage` + +- Default: `{}` -### `timing` +Storage configuration overrides for development mode. -- Default: `false`{lang=ts} +```ts +export default defineNitroConfig({ + devStorage: { + redis: { + driver: "fs", + base: "./data/redis", // use filesystem in development + }, + }, +}); +``` + +### `database` + +Database connection configurations. Requires `experimental.database: true`. + +```ts +database: { + default: { + connector: "sqlite", + options: { name: "db" } + } +} +``` -Enable timing information: +### `devDatabase` -- Nitro startup time log -- `Server-Timing` header on HTTP responses +Database connection configuration overrides for development mode. + +```ts +export default defineNitroConfig({ + devDatabase: { + default: { + connector: "sqlite", + options: { name: "db-dev" }, // separate dev database + }, + }, +}); +``` ### `renderer` -Path to main render (file should export an event handler as default) +- Type: `false`{lang=ts} | `{ handler?: string, static?: boolean, template?: string }`{lang=ts} + +Points to main render entry (file should export an event handler as default). + +```ts +export default defineNitroConfig({ + renderer: { + handler: "~/renderer", // path to the render handler + }, +}); +``` ### `serveStatic` -- Type: `boolean` | `'node'`{lang=ts} | `'deno'`{lang=ts} -- Default: depends of the deployment preset used. +- Type: `boolean`{lang=ts} | `'node'`{lang=ts} | `'deno'`{lang=ts} | `'inline'`{lang=ts} +- Default: depends on the deployment preset used. Serve `public/` assets in production. -**Note:** It is highly recommended that your edge CDN (Nginx, Apache, Cloud) serves the `.output/public/` directory instead of enabling compression and higher lever caching. +**Note:** It is highly recommended that your edge CDN (Nginx, Apache, Cloud) serves the `.output/public/` directory instead to enable compression and higher level caching. + +```ts +export default defineNitroConfig({ + serveStatic: "node", // serve static assets using Node.js +}); +``` ### `noPublicDir` - Default: `false`{lang=ts} -If enabled, disabled `.output/public` directory creation. Skipping to copy `public/` dir and also disables pre-rendering. +If enabled, disables `.output/public` directory creation. Skips copying `public/` dir and also disables pre-rendering. + +```ts +export default defineNitroConfig({ + noPublicDir: true, // skip public directory output +}); +``` ### `publicAssets` @@ -181,79 +369,51 @@ The `dir` option is where your files live on your file system; the `baseURL` opt ### `compressPublicAssets` -- Default: `{ gzip: false, brotli: false }`{lang=ts} - -If enabled, Nitro will generate a pre-compressed (gzip and/or brotli) version of supported types of public assets and prerendered routes -larger than 1024 bytes into the public directory. The best compression level is used. Using this option you can support zero overhead asset compression without using a CDN. - -List of compressible MIME types: - -- `application/dash+xml` -- `application/eot` -- `application/font` -- `application/font-sfnt` -- `application/javascript` -- `application/json` -- `application/opentype` -- `application/otf` -- `application/pdf` -- `application/pkcs7-mime` -- `application/protobuf` -- `application/rss+xml` -- `application/truetype` -- `application/ttf` -- `application/vnd.apple.mpegurl` -- `application/vnd.mapbox-vector-tile` -- `application/vnd.ms-fontobject` -- `application/wasm` -- `application/xhtml+xml` -- `application/xml` -- `application/x-font-opentype` -- `application/x-font-truetype` -- `application/x-font-ttf` -- `application/x-httpd-cgi` -- `application/x-javascript` -- `application/x-mpegurl` -- `application/x-opentype` -- `application/x-otf` -- `application/x-perl` -- `application/x-ttf` -- `font/eot` -- `font/opentype` -- `font/otf` -- `font/ttf` -- `image/svg+xml` -- `text/css` -- `text/csv` -- `text/html` -- `text/javascript` -- `text/js` -- `text/plain` -- `text/richtext` -- `text/tab-separated-values` -- `text/xml` -- `text/x-component` -- `text/x-java-source` -- `text/x-script` -- `vnd.apple.mpegurl` +- Default: `{ gzip: false, brotli: false, zstd: false }`{lang=ts} -### `serverAssets` +If enabled, Nitro will generate a pre-compressed (gzip, brotli, and/or zstd) version of supported types of public assets and prerendered routes +larger than 1024 bytes into the public directory. Default compression levels are used. Using this option you can support zero overhead asset compression without using a CDN. -Assets can be accessed in server logic and bundled in production. [Read more](/guide/assets#server-assets). +```ts +export default defineNitroConfig({ + compressPublicAssets: { + gzip: true, + brotli: true, // enable gzip and brotli pre-compression + }, +}); +``` -### `devServer` +### `serverAssets` -- Default: `{ watch: [] }`{lang=ts} +Assets can be accessed in server logic and bundled in production. [Read more](/docs/assets#server-assets). -Dev server options. You can use `watch` to make the dev server reload if any file changes in specified paths. +```ts +export default defineNitroConfig({ + serverAssets: [ + { + baseName: "templates", + dir: "./templates", // bundle templates/ as server assets + }, + ], +}); +``` -### `watchOptions` +### `modules` -Watch options for development mode. See [chokidar](https://github.com/paulmillr/chokidar) for more information. +- Default: `[]`{lang=ts} -### `imports` +An array of Nitro modules. Modules can be a string (path), a module object with a `setup` function, or a function. -Auto import options. See [unjs/unimport](https://github.com/unjs/unimport) for more information. +```ts +export default defineNitroConfig({ + modules: [ + "./modules/my-module.ts", + (nitro) => { + nitro.hooks.hook("compiled", () => { /* ... */ }); + }, + ], +}); +``` ### `plugins` @@ -261,62 +421,129 @@ Auto import options. See [unjs/unimport](https://github.com/unjs/unimport) for m An array of paths to nitro plugins. They will be executed by order on the first initialization. -Note that Nitro auto-register the plugins in the `plugins/` directory, [learn more](/guide/plugins). +Note that Nitro auto-registers the plugins in the `plugins/` directory, [learn more](/docs/plugins). -### `virtual` +```ts +export default defineNitroConfig({ + plugins: [ + "~/plugins/my-plugin.ts", + ], +}); +``` + +### `tasks` - Default: `{}` -A map from dynamic virtual import names to their contents or an (async) function that returns it. +Task definitions. Each key is a task name with a `handler` path and optional `description`. -## Routing +```ts +tasks: { + 'db:migrate': { + handler: './tasks/db-migrate', + description: 'Run database migrations' + } +} +``` -### `baseURL` +### `scheduledTasks` -Default: `/`{lang=ts} (or `NITRO_APP_BASE_URL` environment variable if provided) +- Default: `{}` -Server's main base URL. +Map of cron expressions to task name(s). -### `apiBaseURL` +```ts +scheduledTasks: { + '0 * * * *': 'cleanup:temp', + '*/5 * * * *': ['health:check', 'metrics:collect'] +} +``` -- Default : `/api` +### `imports` -Changes the default api base URL prefix. +- Default: `false`{lang=ts} -### `handlers` +Auto import options. Set to an object to enable. See [unimport](https://github.com/unjs/unimport) for more information. -Server handlers and routes. +```ts +export default defineNitroConfig({ + imports: { + dirs: ["./utils"], // auto-import from utils/ directory + }, +}); +``` -If `routes/`, `api/` or `middleware/` directories exist, they will be automatically added to the handlers array. +### `virtual` -### `devHandlers` +- Default: `{}` -Regular handlers refer to the path of handlers to be imported and transformed by rollup. +A map from dynamic virtual import names to their contents or an (async) function that returns it. -There are situations in that we directly want to provide a handler instance with programmatic usage. +```ts +export default defineNitroConfig({ + virtual: { + "#config": `export default { version: "1.0.0" }`, + }, +}); +``` -We can use `devHandlers` but note that they are **only available in development mode** and **not in production build**. +### `ignore` -For example: +- Default: `[]` + +Array of glob patterns to ignore when scanning directories. ```ts -import { defineEventHandler } from 'h3' +export default defineNitroConfig({ + ignore: [ + "routes/_legacy/**", // skip legacy route handlers + ], +}); +``` + +### `wasm` + +- Default: `{}`{lang=ts} +- Type: `false`{lang=ts} | `UnwasmPluginOptions`{lang=ts} +WASM support configuration. See [unwasm](https://github.com/unjs/unwasm) for options. + +```ts export default defineNitroConfig({ - devHandlers: [ - { - route: '/', - handler: defineEventHandler((event) => { - console.log(event) - }) - } - ] -}) + wasm: {}, // enable WASM import support +}); ``` -::note{type=info} -Note that `defineEventHandler` is a helper function from [`h3`](https://github.com/unjs/h3) library. -:: +## Dev + +### `devServer` + +- Default: `{ watch: [] }`{lang=ts} + +Dev server options. You can use `watch` to make the dev server reload if any file changes in specified paths. + +Supports `port`, `hostname`, `watch`, and `runner` options. + +```ts +export default defineNitroConfig({ + devServer: { + port: 3001, + watch: ["./server/plugins"], + }, +}); +``` + +### `watchOptions` + +Watch options for development mode. See [chokidar](https://github.com/paulmillr/chokidar) for more information. + +```ts +export default defineNitroConfig({ + watchOptions: { + ignored: ["**/node_modules/**", "**/dist/**"], + }, +}); +``` ### `devProxy` @@ -333,48 +560,139 @@ You can use this option to override development server routes and proxy-pass req } ``` -See [unjs/httpxy](https://github.com/unjs/httpxy) for all available target options. +See [httpxy](https://github.com/unjs/httpxy) for all available target options. -### `errorHandler` +## Logging -Path to a custom runtime error handler. Replacing nitro's built-in error page. -The error handler is given an `H3Error` and `H3Event`. If the handler returns a promise it is awaited. -The handler is expected to send a response of its own. -Below is an example where a plain-text response is returned using h3's functions. +### `logging` -**Example:** +- Default: `{ compressedSizes: true, buildSuccess: true }`{lang=ts} -```js [nitro.config] +Control build logging behavior. Set `compressedSizes` to `false` to skip reporting compressed bundle sizes. Set `buildSuccess` to `false` to suppress the build success message. + +```ts export default defineNitroConfig({ - errorHandler: "~/error", + logging: { + compressedSizes: false, // skip compressed size reporting + buildSuccess: false, + }, }); ``` -```js [error.ts] -export default defineNitroErrorHandler((error, event) => { - setResponseHeader(event, 'Content-Type', 'text/plain') - return send(event, '[custom error handler] ' + error.stack) -}); -``` +## Routing -### `routeRules` +### `baseURL` -**🧪 Experimental!** +Default: `/`{lang=ts} (or `NITRO_APP_BASE_URL` environment variable if provided) -Route options. It is a map from route pattern (following [unjs/radix3](https://github.com/unjs/rou3/tree/radix3#route-matcher)) to route options. +Server's main base URL. -When `cache` option is set, handlers matching pattern will be automatically wrapped with `defineCachedEventHandler`. +```ts +export default defineNitroConfig({ + baseURL: "/app/", // serve app under /app/ prefix +}); +``` -See the [Cache API](/guide/cache) for all available cache options. +### `apiBaseURL` -::note -`swr: true|number` is shortcut for `cache: { swr: true, maxAge: number }` -:: +- Default: `/api` -**Example:** +Changes the default API base URL prefix. -```js -routeRules: { +```ts +export default defineNitroConfig({ + apiBaseURL: "/server/api", // api routes under /server/api/ +}); +``` + +### `handlers` + +Server handlers and routes. + +If `routes/`, `api/` or `middleware/` directories exist inside the server directory, they will be automatically added to the handlers array. + +```ts +export default defineNitroConfig({ + handlers: [ + { route: "/health", handler: "./handlers/health.ts" }, + { route: "/admin/**", handler: "./handlers/admin.ts", method: "get" }, + ], +}); +``` + +### `devHandlers` + +Regular handlers refer to the path of handlers to be imported and transformed by the bundler. + +There are situations in that we directly want to provide a handler instance with programmatic usage. + +We can use `devHandlers` but note that they are **only available in development mode** and **not in production build**. + +```ts +export default defineNitroConfig({ + devHandlers: [ + { route: "/__dev", handler: eventHandler(() => "dev-only route") }, + ], +}); +``` + +### `routes` + +- Default: `{}`{lang=ts} + +Inline route definitions. A map from route pattern to handler path or handler options. + +```ts +export default defineNitroConfig({ + routes: { + "/hello": "./routes/hello.ts", + "/greet": { handler: "./routes/greet.ts", method: "post" }, + }, +}); +``` + +### `errorHandler` + +- Type: `string`{lang=ts} | `string[]`{lang=ts} + +Path(s) to custom runtime error handler(s). Replaces nitro's built-in error page. + +**Example:** + +```js [nitro.config] +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + errorHandler: "~/error", +}); +``` + +```js [error.ts] +export default defineNitroErrorHandler((error, event) => { + return new Response('[custom error handler] ' + error.stack, { + headers: { 'Content-Type': 'text/plain' } + }); +}); +``` + +### `routeRules` + +**🧪 Experimental!** + +Route options. It is a map from route pattern (following [rou3](https://github.com/h3js/rou3)) to route options. + +When `cache` option is set, handlers matching pattern will be automatically wrapped with `defineCachedEventHandler`. + +See the [Cache API](/docs/cache) for all available cache options. + +::note +`swr: true|number` is shortcut for `cache: { swr: true, maxAge: number }` +:: + +**Example:** + +```js +routeRules: { '/blog/**': { swr: true }, '/blog/**': { swr: 600 }, '/blog/**': { static: true }, @@ -386,6 +704,7 @@ routeRules: { '/old-page/**': { redirect: '/new-page/**' }, '/proxy/example': { proxy: 'https://example.com' }, '/proxy/**': { proxy: '/api/**' }, + '/admin/**': { basicAuth: { username: 'admin', password: 'secret' } }, } ``` @@ -413,7 +732,7 @@ Any route (string) that starts with a prefix listed in `ignore` or matches a reg If `crawlLinks` option is set to `true`, nitro starts with `/` by default (or all routes in `routes` array) and for HTML pages extracts `` tags and prerender them as well. -You can set `failOnError` option to `true` to stop the CI when an error if Nitro could not prerender a route. +You can set `failOnError` option to `true` to stop the CI when Nitro could not prerender a route. The `interval` and `concurrency` options lets you control the speed of pre-rendering, can be useful to avoid hitting some rate-limit if you call external APIs. @@ -432,13 +751,42 @@ The prerenderer will attempt to render pages 3 times with a delay of 500ms. Use ## Directories +### `workspaceDir` + +Project workspace root directory. + +The workspace (e.g. pnpm workspace) directory is automatically detected when the `workspaceDir` option is not set. + +```ts +export default defineNitroConfig({ + workspaceDir: "../", // monorepo root +}); +``` + ### `rootDir` -Project main directory +Project main directory. -### `srcDir` +```ts +export default defineNitroConfig({ + rootDir: "./src/server", +}); +``` + +### `serverDir` -Project source directory. Same as `rootDir` unless specified. Helpful to move code into `src/`. +- Default: `false`{lang=ts} +- Type: `boolean`{lang=ts} | `"./"` | `"./server"` | `string`{lang=ts} + +Server directory for scanning `api/`, `routes/`, `plugins/`, `utils/`, `middleware/`, `assets/`, and `tasks/` folders. + +When set to `false`, automatic directory scanning is disabled. Set to `"./"` to use the root directory, or `"./server"` to use a `server/` subdirectory. + +```ts +export default defineNitroConfig({ + serverDir: "./server", // scan server/ subdirectory +}); +``` ### `scanDirs` @@ -446,23 +794,47 @@ Project source directory. Same as `rootDir` unless specified. Helpful to move co List of directories to scan and auto-register files, such as API routes. +```ts +export default defineNitroConfig({ + scanDirs: ["./modules/auth/api", "./modules/billing/api"], +}); +``` + ### `apiDir` -- Default : `api` +- Default: `api` Defines a different directory to scan for api route handlers. +```ts +export default defineNitroConfig({ + apiDir: "endpoints", // scan endpoints/ instead of api/ +}); +``` + ### `routesDir` -- Default : `routes` +- Default: `routes` Defines a different directory to scan for route handlers. +```ts +export default defineNitroConfig({ + routesDir: "pages", // scan pages/ instead of routes/ +}); +``` + ### `buildDir` -- Default: `.nitro` +- Default: `node_modules/.nitro` -nitro's temporary working directory for generating build-related files. +Nitro's temporary working directory for generating build-related files. + +```ts +export default defineNitroConfig({ + buildDir: ".nitro", // use .nitro/ in project root +}); +``` ### `output` @@ -470,96 +842,306 @@ nitro's temporary working directory for generating build-related files. Output directories for production bundle. -## Advanced +```ts +export default defineNitroConfig({ + output: { + dir: "dist", + serverDir: "dist/server", + publicDir: "dist/public", + }, +}); +``` -### `dev` +## Build -- Default: `true` for development and `false` for production. +### `builder` -**⚠️ Caution! This is an advanced configuration. Things can go wrong if misconfigured.** +- Type: `"rollup"`{lang=ts} | `"rolldown"`{lang=ts} | `"vite"`{lang=ts} +- Default: `undefined`{lang=ts} (auto-detected) -### `typescript` +Specify the bundler to use for building. -Default: `{ generateTsConfig: true }` +```ts +export default defineNitroConfig({ + builder: "vite", +}); +``` -### `nodeModulesDirs` +### `rollupConfig` -**⚠️ Caution! This is an advanced configuration. Things can go wrong if misconfigured.** +Additional rollup configuration. -Additional `node_modules` to search when resolving a module. By default user directory is added. +```ts +export default defineNitroConfig({ + rollupConfig: { + output: { manualChunks: { vendor: ["lodash-es"] } }, + }, +}); +``` -### `hooks` +### `rolldownConfig` -**⚠️ Caution! This is an advanced configuration. Things can go wrong if misconfigured.** +Additional rolldown configuration. -nitro hooks. See [unjs/hookable](https://github.com/unjs/hookable) for more information. +```ts +export default defineNitroConfig({ + rolldownConfig: { + output: { banner: "/* built with nitro */" }, + }, +}); +``` -### `commands` +### `entry` -**⚠️ Caution! This is an advanced configuration. Things can go wrong if misconfigured.** +Bundler entry point. -Preview and deploy command hints are usually filled by deployment presets. +```ts +export default defineNitroConfig({ + entry: "./server/entry.ts", // custom entry file +}); +``` -### `devErrorHandler` +### `unenv` -**⚠️ Caution! This is an advanced configuration. Things can go wrong if misconfigured.** +[unenv](https://github.com/unjs/unenv/) preset(s) for environment compatibility. -A custom error handler function for development errors. +```ts +export default defineNitroConfig({ + unenv: { + alias: { "my-module": "my-module/web" }, + }, +}); +``` -## Rollup +### `alias` -### `rollupConfig` +Path aliases for module resolution. -Additional rollup configuration. +```ts +export default defineNitroConfig({ + alias: { + "~utils": "./src/utils", + "#shared": "./shared", + }, +}); +``` -### `entry` +### `minify` -Rollup entry. +- Default: `false` -### `unenv` +Minify bundle. -Options for [unjs/unenv](https://github.com/unjs/unenv/) preset. +```ts +export default defineNitroConfig({ + minify: true, // minify production bundle +}); +``` -### `alias` +### `inlineDynamicImports` -Rollup aliases options. +- Default: `false` -### `minify` +Bundle all code into a single file instead of creating separate chunks per route. -- Default: `false` +When `false`, each route handler becomes a separate chunk loaded on-demand. When `true`, everything is bundled together. Some presets enable this by default. -Minify bundle. +```ts +export default defineNitroConfig({ + inlineDynamicImports: true, // single output file +}); +``` -### `inlineDynamicImports` +### `sourcemap` -Avoid creating chunks. +- Default: `false`{lang=ts} -### `sourceMap` +Enable source map generation. See [options](https://rollupjs.org/configuration-options/#output-sourcemap). -Enable source map generation. See [options](https://rollupjs.org/configuration-options/#output-sourcemap) -- Default: `true` +```ts +export default defineNitroConfig({ + sourcemap: true, // generate .map files +}); +``` ### `node` -Specify whether the build is used for Node.js or not. If set to `false`, nitro tries to mock Node.js dependencies using [unjs/unenv](https://github.com/unjs/unenv) and adjust its behavior. +- Default: `true`{lang=ts} -### `analyze` +Specify whether the build is used for Node.js or not. If set to `false`, nitro tries to mock Node.js dependencies using [unenv](https://github.com/unjs/unenv) and adjust its behavior. -If enabled, will analyze server bundle after build using [rollup-plugin-visualizer](https://github.com/btd/rollup-plugin-visualizer). You can also pass your custom options. +```ts +export default defineNitroConfig({ + node: false, // target non-Node.js runtimes +}); +``` ### `moduleSideEffects` -Default: `['unenv/polyfill/', 'node-fetch-native/polyfill']` +Default: `['unenv/polyfill/']` + +Specifies module imports that have side-effects. -Rollup specific option. Specifies module imports that have side-effects +```ts +export default defineNitroConfig({ + moduleSideEffects: ["unenv/polyfill/", "reflect-metadata"], +}); +``` ### `replace` -Rollup specific option. +Build-time string replacements. + +```ts +export default defineNitroConfig({ + replace: { + "process.env.APP_VERSION": JSON.stringify("1.0.0"), + }, +}); +``` ### `commonJS` -Rollup specific option. Specifies additional configuration for the rollup CommonJS plugin. +Specifies additional configuration for the rollup CommonJS plugin. + +```ts +export default defineNitroConfig({ + commonJS: { + requireReturnsDefault: "auto", + }, +}); +``` + +### `exportConditions` + +Custom export conditions for module resolution. + +```ts +export default defineNitroConfig({ + exportConditions: ["worker", "production"], +}); +``` + +### `noExternals` + +- Default: `false`{lang=ts} + +Prevent specific packages from being externalized. Set to `true` to bundle all dependencies, or pass an array of package names/patterns. + +```ts +export default defineNitroConfig({ + noExternals: true, // bundle all dependencies +}); +``` + +### `traceDeps` + +- Default: `[]`{lang=ts} + +Additional dependencies to trace and include in the build output. + +```ts +export default defineNitroConfig({ + traceDeps: ["sharp", "better-sqlite3"], +}); +``` + +### `oxc` + +OXC options for rolldown builds. Includes `minify` and `transform` sub-options. + +```ts +export default defineNitroConfig({ + oxc: { + minify: { compress: true, mangle: true }, + }, +}); +``` + +## Advanced + +### `dev` + +- Default: `true` for development and `false` for production. + +**⚠️ Caution! This is an advanced configuration. Things can go wrong if misconfigured.** + +```ts +export default defineNitroConfig({ + dev: true, // force development mode behavior +}); +``` + +### `typescript` + +Default: `{ strict: true, generateRuntimeConfigTypes: false, generateTsConfig: false }`{lang=ts} + +TypeScript configuration options including `strict`, `generateRuntimeConfigTypes`, `generateTsConfig`, `tsConfig`, `generatedTypesDir`, and `tsconfigPath`. + +```ts +export default defineNitroConfig({ + typescript: { + strict: true, + generateTsConfig: true, + }, +}); +``` + +### `hooks` + +**⚠️ Caution! This is an advanced configuration. Things can go wrong if misconfigured.** + +nitro hooks. See [hookable](https://github.com/unjs/hookable) for more information. + +```ts +export default defineNitroConfig({ + hooks: { + compiled(nitro) { + console.log("Build compiled successfully!"); + }, + }, +}); +``` + +### `commands` + +**⚠️ Caution! This is an advanced configuration. Things can go wrong if misconfigured.** + +Preview and deploy command hints are usually filled by deployment presets. + +```ts +export default defineNitroConfig({ + commands: { + preview: "node ./server/index.mjs", + }, +}); +``` + +### `devErrorHandler` + +**⚠️ Caution! This is an advanced configuration. Things can go wrong if misconfigured.** + +A custom error handler function for development errors. + +```ts +export default defineNitroConfig({ + devErrorHandler: (error, event) => { + return new Response(`Dev error: ${error.message}`, { status: 500 }); + }, +}); +``` + +### `framework` + +- Default: `{ name: "nitro", version: "" }`{lang=ts} + +Framework information. Used by presets and build info. Typically set by higher-level frameworks (e.g. Nuxt). + +```ts +export default defineNitroConfig({ + framework: { name: "my-framework", version: "2.0.0" }, +}); +``` ## Preset options @@ -567,10 +1149,39 @@ Rollup specific option. Specifies additional configuration for the rollup Common The options for the firebase functions preset. See [Preset Docs](/deploy/providers/firebase#options) +```ts +export default defineNitroConfig({ + firebase: { + gen: 2, // use Cloud Functions 2nd gen + region: "us-central1", + }, +}); +``` + ### `vercel` The options for the vercel preset. See [Preset Docs](/deploy/providers/vercel) +```ts +export default defineNitroConfig({ + vercel: { + config: { runtime: "nodejs20.x" }, + }, +}); +``` + ### `cloudflare` The options for the cloudflare preset. See [Preset Docs](/deploy/providers/cloudflare) + +```ts +export default defineNitroConfig({ + cloudflare: { + wrangler: { compatibility_date: "2025-01-01" }, + }, +}); +``` + +### `zephyr` + +The options for the zephyr preset. See [Preset Docs](/deploy/providers/zephyr#options) diff --git a/docs/4.examples/0.index.md b/docs/4.examples/0.index.md new file mode 100644 index 0000000000..3c1b20e9c3 --- /dev/null +++ b/docs/4.examples/0.index.md @@ -0,0 +1,7 @@ +--- +icon: i-lucide-folder-code +--- + +# Examples + +> Explore Nitro examples to learn how to build full-stack applications diff --git a/docs/4.examples/api-routes.md b/docs/4.examples/api-routes.md new file mode 100644 index 0000000000..496c622295 --- /dev/null +++ b/docs/4.examples/api-routes.md @@ -0,0 +1,159 @@ +--- +category: features +icon: i-lucide-route +--- + +# API Routes + +> File-based API routing with HTTP method support and dynamic parameters. + + + +::code-tree{defaultValue="api/hello.ts" expandAll} + +```html [index.html] + + + + + + API Routes + + +

API Routes:

+
+ + +``` + +```ts [nitro.config.ts] +import { defineConfig } from "nitro"; + +export default defineConfig({ + serverDir: "./", +}); +``` + +```json [package.json] +{ + "type": "module", + "scripts": { + "dev": "nitro dev", + "build": "nitro build" + }, + "devDependencies": { + "nitro": "latest" + } +} +``` + +```json [tsconfig.json] +{ + "extends": "nitro/tsconfig" +} +``` + +```ts [vite.config.ts] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); +``` + +```ts [api/hello.ts] +import { defineHandler } from "nitro"; + +export default defineHandler(() => "Nitro is amazing!"); +``` + +```ts [api/test.get.ts] +import { defineHandler } from "nitro"; + +export default defineHandler(() => "Test get handler"); +``` + +```ts [api/test.post.ts] +import { defineHandler } from "nitro"; + +export default defineHandler(async (event) => { + const body = await event.req.json(); + return { + message: "Test post handler", + body, + }; +}); +``` + +```ts [api/hello/[name].ts] +import { defineHandler } from "nitro"; + +export default defineHandler((event) => `Hello (param: ${event.context.params!.name})!`); +``` + +:: + + + + + +Nitro supports file-based routing in the `api/` or `routes/` directory. Each file becomes an API endpoint based on its path. + +## Basic Route + +Create a file in the `api/` directory to define a route. The file path becomes the URL path: + +```ts [api/hello.ts] +import { defineHandler } from "nitro"; + +export default defineHandler(() => "Nitro is amazing!"); +``` + +This creates a `GET /api/hello` endpoint. + +## Dynamic Routes + +Use square brackets `[param]` for dynamic URL segments. Access params via `event.context.params`: + +```ts [api/hello/[name].ts] +import { defineHandler } from "nitro"; + +export default defineHandler((event) => `Hello (param: ${event.context.params!.name})!`); +``` + +This creates a `GET /api/hello/:name` endpoint (e.g., `/api/hello/world`). + +## HTTP Methods + +Suffix your file with the HTTP method (`.get.ts`, `.post.ts`, `.put.ts`, `.delete.ts`, etc.): + +### GET Handler + +```ts [api/test.get.ts] +import { defineHandler } from "nitro"; + +export default defineHandler(() => "Test get handler"); +``` + +### POST Handler + +```ts [api/test.post.ts] +import { defineHandler } from "nitro"; + +export default defineHandler(async (event) => { + const body = await event.req.json(); + return { + message: "Test post handler", + body, + }; +}); +``` + + + +## Learn More + +- [Routing](/docs/routing) diff --git a/docs/4.examples/auto-imports.md b/docs/4.examples/auto-imports.md new file mode 100644 index 0000000000..1c9d61bde5 --- /dev/null +++ b/docs/4.examples/auto-imports.md @@ -0,0 +1,108 @@ +--- +category: config +icon: i-lucide-import +--- + +# Auto Imports + +> Automatic imports for utilities and composables. + + + +::code-tree{defaultValue="nitro.config.ts" expandAll} + +```ts [nitro.config.ts] +import { defineConfig } from "nitro"; + +export default defineConfig({ + serverDir: true, + imports: {}, +}); +``` + +```json [package.json] +{ + "type": "module", + "scripts": { + "dev": "nitro dev", + "build": "nitro build" + }, + "devDependencies": { + "nitro": "latest" + } +} +``` + +```ts [server.ts] +import { defineHandler } from "nitro"; +import { makeGreeting } from "./server/utils/hello.ts"; + +export default defineHandler(() => `

${makeGreeting("Nitro")}

`); +``` + +```json [tsconfig.json] +{ + "include": [".nitro/types/nitro-imports.d.ts", "src"] +} +``` + +```ts [vite.config.ts] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); +``` + +```ts [server/utils/hello.ts] +export function makeGreeting(name: string) { + return `Hello, ${name}!`; +} +``` + +:: + + + + + +Functions exported from `server/utils/` are automatically available without explicit imports when auto-imports are enabled. Define a utility once and use it anywhere in your server code. + +## Configuration + +Enable auto-imports by setting `imports` in your config: + +```ts [nitro.config.ts] +import { defineConfig } from "nitro"; + +export default defineConfig({ + serverDir: true, + imports: {}, +}); +``` + +## Using Auto Imports + +1. Create a utility file in `server/utils/`: + +```ts [server/utils/hello.ts] +export function makeGreeting(name: string) { + return `Hello, ${name}!`; +} +``` + +2. The function is available without importing it: + +```ts [server.ts] +import { defineHandler } from "nitro"; +import { makeGreeting } from "./server/utils/hello.ts"; + +export default defineHandler(() => `

${makeGreeting("Nitro")}

`); +``` + +With this setup, any function exported from `server/utils/` becomes globally available. Nitro scans the directory and generates the necessary imports automatically. + + + +## Learn More + +- [Configuration](/docs/configuration) diff --git a/docs/4.examples/cached-handler.md b/docs/4.examples/cached-handler.md new file mode 100644 index 0000000000..86885345a2 --- /dev/null +++ b/docs/4.examples/cached-handler.md @@ -0,0 +1,95 @@ +--- +category: features +icon: i-lucide-clock +--- + +# Cached Handler + +> Cache route responses with configurable bypass logic. + + + +::code-tree{defaultValue="server.ts" expandAll} + +```ts [nitro.config.ts] +import { defineConfig } from "nitro"; + +export default defineConfig({}); +``` + +```json [package.json] +{ + "type": "module", + "scripts": { + "dev": "nitro dev", + "build": "nitro build" + }, + "devDependencies": { + "nitro": "latest" + } +} +``` + +```ts [server.ts] +import { html } from "nitro"; +import { defineCachedHandler } from "nitro/cache"; + +export default defineCachedHandler( + async () => { + await new Promise((resolve) => setTimeout(resolve, 500)); + return html` + Response generated at ${new Date().toISOString()} (took 500ms) +
(skip cache) + `; + }, + { shouldBypassCache: ({ req }) => req.url.includes("skipCache=true") } +); +``` + +```json [tsconfig.json] +{ + "extends": "nitro/tsconfig" +} +``` + +```ts [vite.config.ts] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); +``` + +:: + + + + + +This example shows how to cache an expensive operation (a 500 ms delay) and conditionally bypass the cache using a query parameter. On first request, the handler executes and caches the result. Subsequent requests return the cached response instantly until the cache expires or is bypassed. + +## How It Works + +```ts [server.ts] +import { html } from "nitro"; +import { defineCachedHandler } from "nitro/cache"; + +export default defineCachedHandler( + async () => { + await new Promise((resolve) => setTimeout(resolve, 500)); + return html` + Response generated at ${new Date().toISOString()} (took 500ms) +
(skip cache) + `; + }, + { shouldBypassCache: ({ req }) => req.url.includes("skipCache=true") } +); +``` + +The handler simulates a slow operation with a 500ms delay. As `defineCachedHandler` wraps it, the response is cached after the first execution. The `shouldBypassCache` option checks for `?skipCache=true` in the URL and when present the cache is skipped and the handler runs fresh. + + + +## Learn More + +- [Cache](/docs/cache) +- [Storage](/docs/storage) diff --git a/docs/4.examples/custom-error-handler.md b/docs/4.examples/custom-error-handler.md new file mode 100644 index 0000000000..b1c24d02a7 --- /dev/null +++ b/docs/4.examples/custom-error-handler.md @@ -0,0 +1,112 @@ +--- +category: features +icon: i-lucide-alert-circle +--- + +# Custom Error Handler + +> Customize error responses with a global error handler. + + + +::code-tree{defaultValue="error.ts" expandAll} + +```ts [error.ts] +import { defineErrorHandler } from "nitro"; + +export default defineErrorHandler((error, _event) => { + return new Response(`Custom Error Handler: ${error.message}`, { + status: 500, + headers: { "Content-Type": "text/plain" }, + }); +}); +``` + +```ts [nitro.config.ts] +import { defineConfig } from "nitro"; +// import errorHandler from "./error"; + +export default defineConfig({ + errorHandler: "./error.ts", + // devErrorHandler: errorHandler, +}); +``` + +```json [package.json] +{ + "type": "module", + "scripts": { + "dev": "nitro dev", + "build": "nitro build" + }, + "devDependencies": { + "nitro": "latest" + } +} +``` + +```ts [server.ts] +import { defineHandler, HTTPError } from "nitro"; + +export default defineHandler(() => { + throw new HTTPError("Example Error!", { status: 500 }); +}); +``` + +```json [tsconfig.json] +{ + "extends": "nitro/tsconfig" +} +``` + +```ts [vite.config.ts] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); +``` + +:: + + + + + +This example shows how to intercept all errors and return a custom response format. When any route throws an error, Nitro calls your error handler instead of returning the default error page. + +## Error Handler + +Create an `error.ts` file in your project root to define the global error handler: + +```ts [error.ts] +import { defineErrorHandler } from "nitro"; + +export default defineErrorHandler((error, _event) => { + return new Response(`Custom Error Handler: ${error.message}`, { + status: 500, + headers: { "Content-Type": "text/plain" }, + }); +}); +``` + +The handler receives the thrown error and the H3 event object. You can use the event to access request details like headers, cookies, or the URL path to customize responses per route. + +## Triggering an Error + +The main handler throws an error to demonstrate the custom error handler: + +```ts [server.ts] +import { defineHandler, HTTPError } from "nitro"; + +export default defineHandler(() => { + throw new HTTPError("Example Error!", { status: 500 }); +}); +``` + +When you visit the page, instead of seeing a generic error page, you'll see "Custom Error Handler: Example Error!" because the error handler intercepts the thrown error. + + + +## Learn More + +- [Server Entry](/docs/server-entry) diff --git a/docs/4.examples/database.md b/docs/4.examples/database.md new file mode 100644 index 0000000000..5b7ff8cd15 --- /dev/null +++ b/docs/4.examples/database.md @@ -0,0 +1,171 @@ +--- +category: features +icon: i-lucide-database +--- + +# Database + +> Built-in database support with SQL template literals. + + + +::code-tree{defaultValue="server.ts" expandAll} + +```ts [nitro.config.ts] +import { defineConfig } from "nitro"; + +export default defineConfig({ + experimental: { + database: true, + tasks: true, + }, + database: { + default: { connector: "sqlite" }, + }, +}); +``` + +```json [package.json] +{ + "type": "module", + "scripts": { + "dev": "nitro dev", + "build": "nitro build" + }, + "devDependencies": { + "nitro": "latest" + } +} +``` + +```ts [server.ts] +import { defineHandler } from "nitro"; +import { useDatabase } from "nitro/database"; + +export default defineHandler(async () => { + const db = useDatabase(); + + // Create users table + await db.sql`DROP TABLE IF EXISTS users`; + await db.sql`CREATE TABLE IF NOT EXISTS users ("id" TEXT PRIMARY KEY, "firstName" TEXT, "lastName" TEXT, "email" TEXT)`; + + // Add a new user + const userId = String(Math.round(Math.random() * 10_000)); + await db.sql`INSERT INTO users VALUES (${userId}, 'John', 'Doe', '')`; + + // Query for users + const { rows } = await db.sql`SELECT * FROM users WHERE id = ${userId}`; + + return { + rows, + }; +}); +``` + +```json [tsconfig.json] +{ + "extends": "nitro/tsconfig" +} +``` + +```ts [vite.config.ts] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); +``` + +```ts [tasks/db/migrate.ts] +import { defineTask } from "nitro/task"; +import { useDatabase } from "nitro/database"; + +export default defineTask({ + meta: { + description: "Run database migrations", + }, + async run() { + const db = useDatabase(); + + console.log("Running database migrations..."); + + // Create users table + await db.sql`DROP TABLE IF EXISTS users`; + await db.sql`CREATE TABLE IF NOT EXISTS users ("id" TEXT PRIMARY KEY, "firstName" TEXT, "lastName" TEXT, "email" TEXT)`; + + return { + result: "Database migrations complete!", + }; + }, +}); +``` + +:: + + + + + +Nitro provides a built-in database layer that uses SQL template literals for safe, parameterized queries. This example creates a users table, inserts a record, and queries it back. + +## Querying the Database + +```ts [server.ts] +import { defineHandler } from "nitro"; +import { useDatabase } from "nitro/database"; + +export default defineHandler(async () => { + const db = useDatabase(); + + // Create users table + await db.sql`DROP TABLE IF EXISTS users`; + await db.sql`CREATE TABLE IF NOT EXISTS users ("id" TEXT PRIMARY KEY, "firstName" TEXT, "lastName" TEXT, "email" TEXT)`; + + // Add a new user + const userId = String(Math.round(Math.random() * 10_000)); + await db.sql`INSERT INTO users VALUES (${userId}, 'John', 'Doe', '')`; + + // Query for users + const { rows } = await db.sql`SELECT * FROM users WHERE id = ${userId}`; + + return { + rows, + }; +}); +``` + +Retrieve the database instance using `useDatabase()`. The database can be queried using `db.sql`, and variables like `${userId}` are automatically escaped to prevent SQL injection. + +## Running Migrations with Tasks + +Nitro tasks let you run operations outside of request handlers. For database migrations, create a task file in `tasks/` and run it via the CLI. This keeps schema changes separate from your application code. + +```ts [tasks/db/migrate.ts] +import { defineTask } from "nitro/task"; +import { useDatabase } from "nitro/database"; + +export default defineTask({ + meta: { + description: "Run database migrations", + }, + async run() { + const db = useDatabase(); + + console.log("Running database migrations..."); + + // Create users table + await db.sql`DROP TABLE IF EXISTS users`; + await db.sql`CREATE TABLE IF NOT EXISTS users ("id" TEXT PRIMARY KEY, "firstName" TEXT, "lastName" TEXT, "email" TEXT)`; + + return { + result: "Database migrations complete!", + }; + }, +}); +``` + + + +## Learn More + +- [Database](/docs/database) +- [Tasks](/docs/tasks) diff --git a/docs/4.examples/elysia.md b/docs/4.examples/elysia.md new file mode 100644 index 0000000000..63a4fb9bc0 --- /dev/null +++ b/docs/4.examples/elysia.md @@ -0,0 +1,84 @@ +--- +category: backend frameworks +icon: i-skill-icons-elysia-dark +--- + +# Elysia + +> Integrate Elysia with Nitro using the server entry. + + + +::code-tree{defaultValue="server.ts" expandAll} + +```ts [nitro.config.ts] +import { defineConfig } from "nitro"; + +export default defineConfig({}); +``` + +```json [package.json] +{ + "type": "module", + "scripts": { + "build": "nitro build", + "dev": "nitro dev" + }, + "devDependencies": { + "elysia": "^1.4.22", + "nitro": "latest" + } +} +``` + +```ts [server.ts] +import { Elysia } from "elysia"; + +const app = new Elysia(); + +app.get("/", () => "Hello, Elysia with Nitro!"); + +export default app.compile(); +``` + +```json [tsconfig.json] +{ + "extends": "nitro/tsconfig" +} +``` + +```ts [vite.config.ts] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); +``` + +:: + + + + + +## Server Entry + +```ts [server.ts] +import { Elysia } from "elysia"; + +const app = new Elysia(); + +app.get("/", () => "Hello, Elysia with Nitro!"); + +export default app.compile(); +``` + +Nitro auto-detects `server.ts` in your project root and uses it as the server entry. The Elysia app handles all incoming requests, giving you full control over routing and middleware. + +Call `app.compile()` before exporting to optimize the router for production. + + + +## Learn More + +- [Server Entry](/docs/server-entry) +- [Elysia Documentation](https://elysiajs.com/) diff --git a/docs/4.examples/express.md b/docs/4.examples/express.md new file mode 100644 index 0000000000..6cde151cf2 --- /dev/null +++ b/docs/4.examples/express.md @@ -0,0 +1,91 @@ +--- +category: backend frameworks +icon: i-simple-icons-express +--- + +# Express + +> Integrate Express with Nitro using the server entry. + + + +::code-tree{defaultValue="server.node.ts" expandAll} + +```ts [nitro.config.ts] +import { defineConfig } from "nitro"; + +export default defineConfig({}); +``` + +```json [package.json] +{ + "type": "module", + "scripts": { + "build": "nitro build", + "dev": "nitro dev" + }, + "devDependencies": { + "@types/express": "^5.0.6", + "express": "^5.2.1", + "nitro": "latest" + } +} +``` + +```ts [server.node.ts] +import Express from "express"; + +const app = Express(); + +app.use("/", (_req, res) => { + res.send("Hello from Express with Nitro!"); +}); + +export default app; +``` + +```json [tsconfig.json] +{ + "extends": "nitro/tsconfig" +} +``` + +```ts [vite.config.ts] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); +``` + +:: + + + + + +## Server Entry + +```ts [server.node.ts] +import Express from "express"; + +const app = Express(); + +app.use("/", (_req, res) => { + res.send("Hello from Express with Nitro!"); +}); + +export default app; +``` + +Nitro auto-detects `server.node.ts` in your project root and uses it as the server entry. The Express app handles all incoming requests, giving you full control over routing and middleware. + +::note +The `.node.ts` suffix indicates this entry is Node.js specific and won't work in other runtimes like Cloudflare Workers or Deno. +:: + + + +## Learn More + +- [Server Entry](/docs/server-entry) +- [Express Documentation](https://expressjs.com/) diff --git a/docs/4.examples/fastify.md b/docs/4.examples/fastify.md new file mode 100644 index 0000000000..f7d0f50619 --- /dev/null +++ b/docs/4.examples/fastify.md @@ -0,0 +1,92 @@ +--- +category: backend frameworks +icon: i-simple-icons-fastify +--- + +# Fastify + +> Integrate Fastify with Nitro using the server entry. + + + +::code-tree{defaultValue="server.node.ts" expandAll} + +```ts [nitro.config.ts] +import { defineConfig } from "nitro"; + +export default defineConfig({}); +``` + +```json [package.json] +{ + "type": "module", + "scripts": { + "build": "nitro build", + "dev": "nitro dev" + }, + "devDependencies": { + "fastify": "^5.7.4", + "nitro": "latest" + } +} +``` + +```ts [server.node.ts] +import Fastify from "fastify"; + +const app = Fastify(); + +app.get("/", () => "Hello, Fastify with Nitro!"); + +await app.ready(); + +export default app.routing; +``` + +```json [tsconfig.json] +{ + "extends": "nitro/tsconfig" +} +``` + +```ts [vite.config.ts] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); +``` + +:: + + + + + +## Server Entry + +```ts [server.node.ts] +import Fastify from "fastify"; + +const app = Fastify(); + +app.get("/", () => "Hello, Fastify with Nitro!"); + +await app.ready(); + +export default app.routing; +``` + +Nitro auto-detects `server.node.ts` in your project root and uses it as the server entry. + +Call `await app.ready()` to initialize all registered plugins before exporting. Export `app.routing` (not `app`) to provide Nitro with the request handler function. + +::note +The `.node.ts` suffix indicates this entry is Node.js specific and won't work in other runtimes like Cloudflare Workers or Deno. +:: + + + +## Learn More + +- [Server Entry](/docs/server-entry) +- [Fastify Documentation](https://fastify.dev/) diff --git a/docs/4.examples/hello-world.md b/docs/4.examples/hello-world.md new file mode 100644 index 0000000000..f31fb111a1 --- /dev/null +++ b/docs/4.examples/hello-world.md @@ -0,0 +1,83 @@ +--- +category: features +icon: i-lucide-sparkles +--- + +# Hello World + +> Minimal Nitro server using the web standard fetch handler. + + + +::code-tree{defaultValue="server.ts" expandAll} + +```ts [nitro.config.ts] +import { defineConfig } from "nitro"; + +export default defineConfig({}); +``` + +```json [package.json] +{ + "type": "module", + "scripts": { + "build": "nitro build", + "dev": "nitro dev", + "preview": "node .output/server/index.mjs" + }, + "devDependencies": { + "nitro": "latest" + } +} +``` + +```ts [server.ts] +export default { + fetch(req: Request) { + return new Response("Nitro Works!"); + }, +}; +``` + +```json [tsconfig.json] +{ + "extends": "nitro/tsconfig" +} +``` + +```ts [vite.config.ts] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); +``` + +:: + + + + + +The simplest Nitro server. Export an object with a `fetch` method that receives a standard `Request` and returns a `Response`. No frameworks, no abstractions, just the web platform. + + +## Server Entry + +```ts [server.ts] +export default { + fetch(req: Request) { + return new Response("Nitro Works!"); + }, +}; +``` + +The `fetch` method follows the same signature as Service Workers and Cloudflare Workers. This pattern works across all deployment targets because it uses web standards. + +Add the Nitro plugin to Vite and it handles the rest: dev server, hot reloading, and production builds. + + + +## Learn More + +- [Server Entry](/docs/server-entry) +- [Configuration](/docs/configuration) diff --git a/docs/4.examples/hono.md b/docs/4.examples/hono.md new file mode 100644 index 0000000000..19f265f91b --- /dev/null +++ b/docs/4.examples/hono.md @@ -0,0 +1,88 @@ +--- +category: backend frameworks +icon: i-logos-hono +--- + +# Hono + +> Integrate Hono with Nitro using the server entry. + + + +::code-tree{defaultValue="server.ts" expandAll} + +```ts [nitro.config.ts] +import { defineConfig } from "nitro"; + +export default defineConfig({}); +``` + +```json [package.json] +{ + "type": "module", + "scripts": { + "build": "nitro build", + "dev": "nitro dev" + }, + "devDependencies": { + "hono": "^4.11.8", + "nitro": "latest" + } +} +``` + +```ts [server.ts] +import { Hono } from "hono"; + +const app = new Hono(); + +app.get("/", (c) => { + return c.text("Hello, Hono with Nitro!"); +}); + +export default app; +``` + +```json [tsconfig.json] +{ + "extends": "nitro/tsconfig" +} +``` + +```ts [vite.config.ts] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); +``` + +:: + + + + + +## Server Entry + +```ts [server.ts] +import { Hono } from "hono"; + +const app = new Hono(); + +app.get("/", (c) => { + return c.text("Hello, Hono with Nitro!"); +}); + +export default app; +``` + +Nitro auto-detects `server.ts` in your project root and uses it as the server entry. The Hono app handles all incoming requests, giving you full control over routing and middleware. + +Hono is cross-runtime compatible, so this server entry works across all Nitro deployment targets including Node.js, Deno, Bun, and Cloudflare Workers. + + + +## Learn More + +- [Server Entry](/docs/server-entry) +- [Hono Documentation](https://hono.dev/) diff --git a/docs/4.examples/import-alias.md b/docs/4.examples/import-alias.md new file mode 100644 index 0000000000..74d947816e --- /dev/null +++ b/docs/4.examples/import-alias.md @@ -0,0 +1,111 @@ +--- +category: config +icon: i-lucide-at-sign +--- + +# Import Alias + +> Custom import aliases for cleaner module paths. + + + +::code-tree{defaultValue="server/routes/index.ts" expandAll} + +```ts [nitro.config.ts] +import { defineConfig } from "nitro"; + +export default defineConfig({ + serverDir: true, +}); +``` + +```json [package.json] +{ + "type": "module", + "imports": { + "#server/*": "./server/*" + }, + "scripts": { + "build": "nitro build", + "dev": "nitro dev", + "preview": "node .output/server/index.mjs" + }, + "devDependencies": { + "nitro": "latest" + } +} +``` + +```json [tsconfig.json] +{ + "extends": "nitro/tsconfig", + "compilerOptions": { + "paths": { + "~server/*": ["./server/*"] + } + } +} +``` + +```ts [vite.config.ts] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()], resolve: { tsconfigPaths: true } }); +``` + +```ts [server/routes/index.ts] +import { sum } from "~server/utils/math.ts"; + +import { rand } from "#server/utils/math.ts"; + +export default () => { + const [a, b] = [rand(1, 10), rand(1, 10)]; + const result = sum(a, b); + return `The sum of ${a} + ${b} = ${result}`; +}; +``` + +```ts [server/utils/math.ts] +export function rand(min: number, max: number): number { + return Math.floor(Math.random() * (max - min + 1)) + min; +} + +export function sum(a: number, b: number): number { + return a + b; +} +``` + +:: + + + + + +Import aliases like `~` and `#` let you reference modules with shorter paths instead of relative imports. + +## Importing Using Aliases + +```ts [server/routes/index.ts] +import { sum } from "~server/utils/math.ts"; + +import { rand } from "#server/utils/math.ts"; + +export default () => { + const [a, b] = [rand(1, 10), rand(1, 10)]; + const result = sum(a, b); + return `The sum of ${a} + ${b} = ${result}`; +}; +``` + +The route imports the `sum` function using `~server/` and `rand` using `#server/`. Both resolve to the same `server/utils/math.ts` file. The handler generates two random numbers and returns their sum. + +## Configuration + +Aliases can be configured in `package.json` imports field or `nitro.config.ts`. + + + +## Learn More + +- [Configuration](/docs/configuration) diff --git a/docs/4.examples/middleware.md b/docs/4.examples/middleware.md new file mode 100644 index 0000000000..0829c05ac6 --- /dev/null +++ b/docs/4.examples/middleware.md @@ -0,0 +1,105 @@ +--- +category: features +icon: i-lucide-layers +--- + +# Middleware + +> Request middleware for authentication, logging, and request modification. + + + +::code-tree{defaultValue="server/middleware/auth.ts" expandAll} + +```ts [nitro.config.ts] +import { defineConfig } from "nitro"; + +export default defineConfig({ + serverDir: true, +}); +``` + +```json [package.json] +{ + "type": "module", + "scripts": { + "dev": "nitro dev", + "build": "nitro build" + }, + "devDependencies": { + "nitro": "latest" + } +} +``` + +```ts [server.ts] +import { defineHandler } from "nitro"; + +export default defineHandler((event) => ({ + auth: event.context.auth, +})); +``` + +```json [tsconfig.json] +{ + "extends": "nitro/tsconfig" +} +``` + +```ts [vite.config.ts] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); +``` + +```ts [server/middleware/auth.ts] +import { defineMiddleware } from "nitro"; + +export default defineMiddleware((event) => { + event.context.auth = { name: "User " + Math.round(Math.random() * 100) }; +}); +``` + +:: + + + + + +Middleware functions run before route handlers on every request. They can modify the request, add context, or return early responses. + +## Defining Middleware + +Create files in `server/middleware/`. They run in alphabetical order: + +```ts [server/middleware/auth.ts] +import { defineMiddleware } from "nitro"; + +export default defineMiddleware((event) => { + event.context.auth = { name: "User " + Math.round(Math.random() * 100) }; +}); +``` + +Middleware can: +- Add data to `event.context` for use in handlers +- Return a response early to short-circuit the request +- Modify request headers or other properties + +## Accessing Context in Handlers + +Data added to `event.context` in middleware is available in all subsequent handlers: + +```ts [server.ts] +import { defineHandler } from "nitro"; + +export default defineHandler((event) => ({ + auth: event.context.auth, +})); +``` + + + +## Learn More + +- [Routing](/docs/routing) diff --git a/docs/4.examples/mono-jsx.md b/docs/4.examples/mono-jsx.md new file mode 100644 index 0000000000..8c3de4b505 --- /dev/null +++ b/docs/4.examples/mono-jsx.md @@ -0,0 +1,82 @@ +--- +category: server side rendering +icon: i-lucide-brackets +--- + +# Mono JSX + +> Server-side JSX rendering in Nitro with mono-jsx. + + + +::code-tree{defaultValue="server.tsx" expandAll} + +```ts [nitro.config.ts] +import { defineConfig } from "nitro"; + +export default defineConfig({}); +``` + +```json [package.json] +{ + "type": "module", + "scripts": { + "dev": "nitro dev", + "build": "nitro build" + }, + "devDependencies": { + "mono-jsx": "latest", + "nitro": "latest" + } +} +``` + +```tsx [server.tsx] +export default () => ( + +

Nitro + mono-jsx works!

+ +); +``` + +```json [tsconfig.json] +{ + "extends": "nitro/tsconfig", + "compilerOptions": { + "jsx": "react-jsx", + "jsxImportSource": "mono-jsx" + } +} +``` + +```ts [vite.config.ts] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); +``` + +:: + + + + + +## Server Entry + +```tsx [server.tsx] +export default () => ( + +

Nitro + mono-jsx works!

+ +); +``` + +Nitro auto-detects `server.tsx` and uses mono-jsx to transform JSX into HTML. Export a function that returns JSX, and Nitro sends the rendered HTML as the response. + + + +## Learn More + +- [Renderer](/docs/renderer) +- [mono-jsx](https://github.com/aspect-dev/mono-jsx) diff --git a/docs/4.examples/nano-jsx.md b/docs/4.examples/nano-jsx.md new file mode 100644 index 0000000000..1ace032569 --- /dev/null +++ b/docs/4.examples/nano-jsx.md @@ -0,0 +1,84 @@ +--- +category: server side rendering +icon: i-lucide-brackets +--- + +# Nano JSX + +> Server-side JSX rendering in Nitro with nano-jsx. + + + +::code-tree{defaultValue="server.tsx" expandAll} + +```ts [nitro.config.ts] +import { defineConfig } from "nitro"; + +export default defineConfig({}); +``` + +```json [package.json] +{ + "type": "module", + "scripts": { + "dev": "nitro dev", + "build": "nitro build" + }, + "devDependencies": { + "nano-jsx": "^0.2.1", + "nitro": "latest" + } +} +``` + +```tsx [server.tsx] +import { defineHandler, html } from "nitro"; +import { renderSSR } from "nano-jsx"; + +export default defineHandler(() => { + return html(renderSSR(() =>

Nitro + nano-jsx works!

)); +}); +``` + +```json [tsconfig.json] +{ + "extends": "nitro/tsconfig", + "compilerOptions": { + "jsx": "react-jsx", + "jsxImportSource": "nano-jsx/esm" + } +} +``` + +```ts [vite.config.ts] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); +``` + +:: + + + + + +## Server Entry + +```tsx [server.tsx] +import { defineHandler, html } from "nitro"; +import { renderSSR } from "nano-jsx"; + +export default defineHandler(() => { + return html(renderSSR(() =>

Nitro + nano-jsx works!

)); +}); +``` + +Nitro auto-detects `server.tsx` and uses it as the server entry. Use `renderSSR` from nano-jsx to convert JSX into an HTML string. The `html` helper from H3 sets the correct content type header. + + + +## Learn More + +- [Renderer](/docs/renderer) +- [nano-jsx](https://nanojsx.io/) diff --git a/docs/4.examples/plugins.md b/docs/4.examples/plugins.md new file mode 100644 index 0000000000..9158ff30eb --- /dev/null +++ b/docs/4.examples/plugins.md @@ -0,0 +1,105 @@ +--- +category: features +icon: i-lucide-plug +--- + +# Plugins + +> Extend Nitro with custom plugins for hooks and lifecycle events. + + + +::code-tree{defaultValue="server/plugins/test.ts" expandAll} + +```ts [nitro.config.ts] +import { defineConfig } from "nitro"; + +export default defineConfig({ + serverDir: true, +}); +``` + +```json [package.json] +{ + "type": "module", + "scripts": { + "dev": "nitro dev", + "build": "nitro build" + }, + "devDependencies": { + "nitro": "latest" + } +} +``` + +```ts [server.ts] +import { eventHandler } from "h3"; + +export default eventHandler(() => "

Hello Nitro!

"); +``` + +```json [tsconfig.json] +{ + "extends": "nitro/tsconfig" +} +``` + +```ts [vite.config.ts] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); +``` + +```ts [server/plugins/test.ts] +import { definePlugin } from "nitro"; +import { useNitroHooks } from "nitro/app"; + +export default definePlugin((nitroApp) => { + const hooks = useNitroHooks(); + hooks.hook("response", (event) => { + event.headers.set("content-type", "html; charset=utf-8"); + }); +}); +``` + +:: + + + + + +Plugins let you hook into Nitro's runtime lifecycle. This example shows a plugin that modifies the `Content-Type` header on every response. Create files in `server/plugins/` and they're automatically loaded at startup. + +## Defining a Plugin + +```ts [server/plugins/test.ts] +import { definePlugin } from "nitro"; +import { useNitroHooks } from "nitro/app"; + +export default definePlugin((nitroApp) => { + const hooks = useNitroHooks(); + hooks.hook("response", (event) => { + event.headers.set("content-type", "html; charset=utf-8"); + }); +}); +``` + +The plugin uses `useNitroHooks()` to access the hooks system, then registers a `response` hook that runs after every request. Here it sets the content type to HTML, but you could log requests, add security headers, or modify responses in any way. + +## Main Handler + +```ts [server.ts] +import { eventHandler } from "h3"; + +export default eventHandler(() => "

Hello Nitro!

"); +``` + +The handler returns HTML without setting a content type. The plugin automatically adds the correct `Content-Type: html; charset=utf-8` header to the response. + + + +## Learn More + +- [Plugins](/docs/plugins) +- [Lifecycle](/docs/lifecycle) diff --git a/docs/4.examples/renderer.md b/docs/4.examples/renderer.md new file mode 100644 index 0000000000..c226ce0f4a --- /dev/null +++ b/docs/4.examples/renderer.md @@ -0,0 +1,127 @@ +--- +category: server side rendering +icon: i-lucide-code +--- + +# Custom Renderer + +> Build a custom HTML renderer in Nitro with server-side data fetching. + + + +::code-tree{defaultValue="renderer.ts" expandAll} + +```ts [nitro.config.ts] +import { defineConfig } from "nitro"; + +export default defineConfig({ + serverDir: "./", + renderer: { handler: "./renderer" }, +}); +``` + +```json [package.json] +{ + "type": "module", + "scripts": { + "dev": "nitro dev", + "build": "nitro build" + }, + "devDependencies": { + "nitro": "latest" + } +} +``` + +```ts [renderer.ts] +import { fetch } from "nitro"; + +export default async function renderer({ url }: { req: Request; url: URL }) { + const apiRes = await fetch("/api/hello").then((res) => res.text()); + return new Response( + /* html */ ` + + + Custom Renderer + + +

Hello from custom renderer!

+

Current path: ${url.pathname}

+

API says: ${apiRes}

+ + `, + { headers: { "content-type": "text/html; charset=utf-8" } } + ); +} +``` + +```json [tsconfig.json] +{ + "extends": "nitro/tsconfig" +} +``` + +```ts [vite.config.ts] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); +``` + +```ts [api/hello.ts] +import { defineHandler } from "nitro"; + +export default defineHandler(() => "Nitro is amazing!"); +``` + +:: + + + + + +Create a custom renderer that generates HTML responses with data from API routes. Use Nitro's internal `fetch` to call routes without network overhead. + +## Renderer + +```ts [renderer.ts] +import { fetch } from "nitro"; + +export default async function renderer({ url }: { req: Request; url: URL }) { + const apiRes = await fetch("/api/hello").then((res) => res.text()); + return new Response( + /* html */ ` + + + Custom Renderer + + +

Hello from custom renderer!

+

Current path: ${url.pathname}

+

API says: ${apiRes}

+ + `, + { headers: { "content-type": "text/html; charset=utf-8" } } + ); +} +``` + +Nitro auto-detects `renderer.ts` in your project root and uses it for all non-API routes. The renderer function receives the request URL and returns a `Response`. + +Use `fetch` from `nitro` to call API routes without network overhead—these requests stay in-process. + +## API Route + +```ts [api/hello.ts] +import { defineHandler } from "nitro"; + +export default defineHandler(() => "Nitro is amazing!"); +``` + +Define API routes in the `api/` directory. When the renderer calls `fetch("/api/hello")`, this handler runs and returns its response. + + + +## Learn More + +- [Renderer](/docs/renderer) diff --git a/docs/4.examples/runtime-config.md b/docs/4.examples/runtime-config.md new file mode 100644 index 0000000000..4e7b6655b1 --- /dev/null +++ b/docs/4.examples/runtime-config.md @@ -0,0 +1,111 @@ +--- +category: config +icon: i-lucide-settings +--- + +# Runtime Config + +> Environment-aware configuration with runtime access. + + + +::code-tree{defaultValue="nitro.config.ts" expandAll} + +```ts [nitro.config.ts] +import { defineConfig } from "nitro"; + +export default defineConfig({ + serverDir: "./", + runtimeConfig: { + apiKey: "", + }, +}); +``` + +```json [package.json] +{ + "type": "module", + "scripts": { + "dev": "nitro dev", + "build": "nitro build" + }, + "devDependencies": { + "nitro": "latest" + } +} +``` + +```ts [server.ts] +import { defineHandler } from "nitro"; +import { useRuntimeConfig } from "nitro/runtime-config"; + +export default defineHandler((event) => { + const runtimeConfig = useRuntimeConfig(); + return { runtimeConfig }; +}); +``` + +```json [tsconfig.json] +{ + "extends": "nitro/tsconfig" +} +``` + +```ts [vite.config.ts] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); +``` + +:: + + + + + +Runtime config lets you define configuration values that can be overridden by environment variables at runtime. + +## Define Config Schema + +Declare your runtime config with default values in `nitro.config.ts`: + +```ts [nitro.config.ts] +import { defineConfig } from "nitro"; + +export default defineConfig({ + serverDir: "./", + runtimeConfig: { + apiKey: "", + }, +}); +``` + +## Access at Runtime + +Use `useRuntimeConfig` to access configuration values in your handlers: + +```ts [server.ts] +import { defineHandler } from "nitro"; +import { useRuntimeConfig } from "nitro/runtime-config"; + +export default defineHandler((event) => { + const runtimeConfig = useRuntimeConfig(); + return { runtimeConfig }; +}); +``` + +## Environment Variables + +Override config values via environment variables prefixed with `NITRO_`: + +```sh [.env] +# NEVER COMMIT SENSITIVE DATA. THIS IS ONLY FOR DEMO PURPOSES. +NITRO_API_KEY=secret-api-key +``` + + + +## Learn More + +- [Configuration](/docs/configuration) diff --git a/docs/4.examples/server-fetch.md b/docs/4.examples/server-fetch.md new file mode 100644 index 0000000000..91325d6019 --- /dev/null +++ b/docs/4.examples/server-fetch.md @@ -0,0 +1,101 @@ +--- +category: features +icon: i-lucide-arrow-right-left +--- + +# Server Fetch + +> Internal server-to-server requests without network overhead. + + + +::code-tree{defaultValue="routes/index.ts" expandAll} + +```ts [nitro.config.ts] +import { defineConfig, serverFetch } from "nitro"; + +export default defineConfig({ + serverDir: "./", + hooks: { + "dev:start": async () => { + const res = await serverFetch("/hello"); + const text = await res.text(); + console.log("Fetched /hello in nitro module:", res.status, text); + }, + }, +}); +``` + +```json [package.json] +{ + "type": "module", + "scripts": { + "dev": "nitro dev", + "build": "nitro build" + }, + "devDependencies": { + "nitro": "latest" + } +} +``` + +```json [tsconfig.json] +{ + "extends": "nitro/tsconfig" +} +``` + +```ts [vite.config.ts] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); +``` + +```ts [routes/hello.ts] +import { defineHandler } from "nitro"; + +export default defineHandler(() => "Hello!"); +``` + +```ts [routes/index.ts] +import { defineHandler } from "nitro"; +import { fetch } from "nitro"; + +export default defineHandler(() => fetch("/hello")); +``` + +:: + + + + + +When you need one route to call another, use Nitro's `fetch` function instead of the global fetch. It makes internal requests that stay in-process, avoiding network round-trips. The request never leaves the server. + +## Main Route + +```ts [routes/index.ts] +import { defineHandler } from "nitro"; +import { fetch } from "nitro"; + +export default defineHandler(() => fetch("/hello")); +``` + +The index route imports `fetch` from `nitro` (not the global fetch) and calls the `/hello` route. This request is handled internally without going through the network stack. + +## Internal API Route + +```ts [routes/hello.ts] +import { defineHandler } from "nitro"; + +export default defineHandler(() => "Hello!"); +``` + +A simple route that returns "Hello!". When the index route calls `fetch("/hello")`, this handler runs and its response is returned directly. + + + +## Learn More + +- [Routing](/docs/routing) diff --git a/docs/4.examples/shiki.md b/docs/4.examples/shiki.md new file mode 100644 index 0000000000..f6b6b35535 --- /dev/null +++ b/docs/4.examples/shiki.md @@ -0,0 +1,212 @@ +--- +category: integrations +icon: i-lucide-highlighter +--- + +# Shiki + +> Server-side syntax highlighting in Nitro with Shiki. + + + +::code-tree{defaultValue="api/highlight.ts" expandAll} + +```html [index.html] + + + + + + Hello World Snippet + + + +
+
JavaScript
+ +
{{{ hl(`console.log("💚 Simple is beautiful!");`) }}}
+
+ + +``` + +```ts [nitro.config.ts] +import { defineConfig } from "nitro"; + +export default defineConfig({ + serverDir: "./", +}); +``` + +```json [package.json] +{ + "type": "module", + "scripts": { + "dev": "vite dev", + "build": "vite build" + }, + "devDependencies": { + "nitro": "latest", + "shiki": "^3.22.0" + } +} +``` + +```css [styles.css] +html, +body { + height: 100%; + margin: 0; +} +body { + display: flex; + align-items: center; + justify-content: center; + background: #f6f8fa; + font-family: + system-ui, + -apple-system, + "Segoe UI", + Roboto, + "Helvetica Neue", + Arial, + "Noto Sans", + "Liberation Sans", + sans-serif; +} +.card { + text-align: left; + background: #0b1220; + color: #e6edf3; + padding: 1rem; + border-radius: 8px; + box-shadow: 0 8px 24px rgba(2, 6, 23, 0.2); + max-width: 90%; + width: 520px; +} +.label { + font-size: 12px; + color: #9aa7b2; + margin-bottom: 8px; +} +pre { + margin: 0; + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, "Courier New", monospace; + font-size: 14px; + background: transparent; + white-space: pre; + overflow: auto; +} +``` + +```json [tsconfig.json] +{ + "extends": "nitro/tsconfig" +} +``` + +```ts [vite.config.ts] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ + plugins: [nitro()], +}); +``` + +```ts [api/highlight.ts] +import { createHighlighterCore } from "shiki/core"; +import { createOnigurumaEngine } from "shiki/engine/oniguruma"; + +const highlighter = await createHighlighterCore({ + engine: createOnigurumaEngine(import("shiki/wasm")), + themes: [await import("shiki/themes/vitesse-dark.mjs")], + langs: [await import("shiki/langs/ts.mjs")], +}); + +export default async ({ req }: { req: Request }) => { + const code = await req.text(); + const html = await highlighter.codeToHtml(code, { + lang: "ts", + theme: "vitesse-dark", + }); + return new Response(html, { + headers: { "Content-Type": "text/html; charset=utf-8" }, + }); +}; +``` + +:: + + + + + +Use Shiki for syntax highlighting with TextMate grammars. This example highlights code on the server using Nitro's server scripts feature, which runs JavaScript inside HTML files before sending the response. + +## API Route + +```ts [api/highlight.ts] +import { createHighlighterCore } from "shiki/core"; +import { createOnigurumaEngine } from "shiki/engine/oniguruma"; + +const highlighter = await createHighlighterCore({ + engine: createOnigurumaEngine(import("shiki/wasm")), + themes: [await import("shiki/themes/vitesse-dark.mjs")], + langs: [await import("shiki/langs/ts.mjs")], +}); + +export default async ({ req }: { req: Request }) => { + const code = await req.text(); + const html = await highlighter.codeToHtml(code, { + lang: "ts", + theme: "vitesse-dark", + }); + return new Response(html, { + headers: { "Content-Type": "text/html; charset=utf-8" }, + }); +}; +``` + +Create a Shiki highlighter with the Vitesse Dark theme and TypeScript language support. When the API receives a POST request, it reads the code from the request body and returns highlighted HTML. + +## Server-Side Rendering + +```html [index.html] + + + + + + Hello World Snippet + + + +
+
JavaScript
+ +
{{{ hl(`console.log("💚 Simple is beautiful!");`) }}}
+
+ + +``` + +The ` + rscStream + ); + + // Browser root component to (re-)render RSC payload as state + function BrowserRoot() { + const [payload, setPayload_] = React.useState(initialPayload); + + React.useEffect(() => { + setPayload = (v) => React.startTransition(() => setPayload_(v)); + }, [setPayload_]); + + // Re-fetch/render on client side navigation + React.useEffect(() => { + return listenNavigation(() => fetchRscPayload()); + }, []); + + return payload.root; + } + + // Re-fetch RSC and trigger re-rendering + async function fetchRscPayload() { + const renderRequest = createRscRenderRequest(globalThis.location.href); + const payload = await createFromFetch(fetch(renderRequest)); + setPayload(payload); + } + + // Register a handler which will be internally called by React + // on server function request after hydration. + setServerCallback(async (id, args) => { + const temporaryReferences = createTemporaryReferenceSet(); + const renderRequest = createRscRenderRequest(globalThis.location.href, { + id, + body: await encodeReply(args, { temporaryReferences }), + }); + const payload = await createFromFetch(fetch(renderRequest), { + temporaryReferences, + }); + setPayload(payload); + const { ok, data } = payload.returnValue!; + if (!ok) throw data; + return data; + }); + + // Hydration + const browserRoot = ( + + + + + + ); + if ("__NO_HYDRATE" in globalThis) { + createRoot(document).render(browserRoot); + } else { + hydrateRoot(document, browserRoot, { + formState: initialPayload.formState, + }); + } + + // Implement server HMR by triggering re-fetch/render of RSC upon server code change + if (import.meta.hot) { + import.meta.hot.on("rsc:update", () => { + fetchRscPayload(); + }); + } +} + +// A little helper to setup events interception for client side navigation +function listenNavigation(onNavigation: () => void) { + globalThis.addEventListener("popstate", onNavigation); + + const oldPushState = globalThis.history.pushState; + globalThis.history.pushState = function (...args) { + const res = oldPushState.apply(this, args); + onNavigation(); + return res; + }; + + const oldReplaceState = globalThis.history.replaceState; + globalThis.history.replaceState = function (...args) { + const res = oldReplaceState.apply(this, args); + onNavigation(); + return res; + }; + + function onClick(e: MouseEvent) { + const link = (e.target as Element).closest("a"); + if ( + link && + link instanceof HTMLAnchorElement && + link.href && + (!link.target || link.target === "_self") && + link.origin === location.origin && + !link.hasAttribute("download") && + e.button === 0 && // left clicks only + !e.metaKey && // open in new tab (mac) + !e.ctrlKey && // open in new tab (windows) + !e.altKey && // download + !e.shiftKey && + !e.defaultPrevented + ) { + e.preventDefault(); + history.pushState(null, "", link.href); + } + } + document.addEventListener("click", onClick); + + return () => { + document.removeEventListener("click", onClick); + globalThis.removeEventListener("popstate", onNavigation); + globalThis.history.pushState = oldPushState; + globalThis.history.replaceState = oldReplaceState; + }; +} + +// eslint-disable-next-line unicorn/prefer-top-level-await +main(); +``` + +```tsx [app/framework/entry.rsc.tsx] +import { + renderToReadableStream, + createTemporaryReferenceSet, + decodeReply, + loadServerAction, + decodeAction, + decodeFormState, +} from "@vitejs/plugin-rsc/rsc"; +import type { ReactFormState } from "react-dom/client"; +import { Root } from "../root.tsx"; +import { parseRenderRequest } from "./request.tsx"; + +// The schema of payload which is serialized into RSC stream on rsc environment +// and deserialized on ssr/client environments. +export type RscPayload = { + // this demo renders/serializes/deserializes entire root html element + // but this mechanism can be changed to render/fetch different parts of components + // based on your own route conventions. + root: React.ReactNode; + + // Server action return value of non-progressive enhancement case + returnValue?: { ok: boolean; data: unknown }; + + // Server action form state (e.g. useActionState) of progressive enhancement case + formState?: ReactFormState; +}; + +// The plugin by default assumes `rsc` entry having default export of request handler. +// however, how server entries are executed can be customized by registering own server handler. +export default async function handler(request: Request): Promise { + // Differentiate RSC, SSR, action, etc. + const renderRequest = parseRenderRequest(request); + request = renderRequest.request; + + // Handle server function request + let returnValue: RscPayload["returnValue"] | undefined; + let formState: ReactFormState | undefined; + let temporaryReferences: unknown | undefined; + let actionStatus: number | undefined; + + if (renderRequest.isAction === true) { + if (renderRequest.actionId) { + // Action is called via `ReactClient.setServerCallback`. + const contentType = request.headers.get("content-type"); + const body = contentType?.startsWith("multipart/form-data") + ? await request.formData() + : await request.text(); + temporaryReferences = createTemporaryReferenceSet(); + const args = await decodeReply(body, { temporaryReferences }); + const action = await loadServerAction(renderRequest.actionId); + try { + // eslint-disable-next-line prefer-spread + const data = await action.apply(null, args); + returnValue = { ok: true, data }; + } catch (error_) { + returnValue = { ok: false, data: error_ }; + actionStatus = 500; + } + } else { + // Otherwise server function is called via `
` + // before hydration (e.g. when JavaScript is disabled). + // aka progressive enhancement. + const formData = await request.formData(); + const decodedAction = await decodeAction(formData); + try { + const result = await decodedAction(); + formState = await decodeFormState(result, formData); + } catch { + // there's no single general obvious way to surface this error, + // so explicitly return classic 500 response. + return new Response("Internal Server Error: server action failed", { + status: 500, + }); + } + } + } + + // Serialization from React VDOM tree to RSC stream. + // We render RSC stream after handling server function request + // so that new render reflects updated state from server function call + // to achieve single round trip to mutate and fetch from server. + const rscPayload: RscPayload = { + root: , + formState, + returnValue, + }; + + const rscOptions = { temporaryReferences }; + const rscStream = renderToReadableStream(rscPayload, rscOptions); + + // Respond RSC stream without HTML rendering as decided by `RenderRequest` + if (renderRequest.isRsc) { + return new Response(rscStream, { + status: actionStatus, + headers: { + "content-type": "text/x-component;charset=utf-8", + }, + }); + } + + // Delegate to SSR environment for HTML rendering. + // The plugin provides `loadModule` helper to allow loading SSR environment entry module + // in RSC environment. however this can be customized by implementing own runtime communication + // e.g. `@cloudflare/vite-plugin`'s service binding. + const ssrEntryModule = await import.meta.viteRsc.loadModule( + "ssr", + "index" + ); + + const ssrResult = await ssrEntryModule.renderHTML(rscStream, { + formState, + // Allow quick simulation of JavaScript disabled browser + debugNoJS: renderRequest.url.searchParams.has("__nojs"), + }); + + // Respond HTML + return new Response(ssrResult.stream, { + status: ssrResult.status, + headers: { + "Content-Type": "text/html", + }, + }); +} + +if (import.meta.hot) { + import.meta.hot.accept(); +} +``` + +```tsx [app/framework/entry.ssr.tsx] +import { createFromReadableStream } from "@vitejs/plugin-rsc/ssr"; +import React from "react"; +import type { ReactFormState } from "react-dom/client"; +import { renderToReadableStream } from "react-dom/server.edge"; +import { injectRSCPayload } from "rsc-html-stream/server"; +import type { RscPayload } from "./entry.rsc"; + +export default { + fetch: async (request: Request) => { + const rscEntryModule = await import.meta.viteRsc.loadModule( + "rsc", + "index" + ); + return rscEntryModule.default(request); + }, +}; + +export async function renderHTML( + rscStream: ReadableStream, + options: { + formState?: ReactFormState; + nonce?: string; + debugNoJS?: boolean; + } +): Promise<{ stream: ReadableStream; status?: number }> { + // Duplicate one RSC stream into two. + // - one for SSR (ReactClient.createFromReadableStream below) + // - another for browser hydration payload by injecting . + const [rscStream1, rscStream2] = rscStream.tee(); + + // Deserialize RSC stream back to React VDOM + let payload: Promise | undefined; + function SsrRoot() { + // Deserialization needs to be kicked off inside ReactDOMServer context + // for ReactDOMServer preinit/preloading to work + payload ??= createFromReadableStream(rscStream1); + return React.use(payload).root; + } + + // Render HTML (traditional SSR) + const bootstrapScriptContent = await import.meta.viteRsc.loadBootstrapScriptContent("index"); + + let htmlStream: ReadableStream; + let status: number | undefined; + + try { + htmlStream = await renderToReadableStream(, { + bootstrapScriptContent: options?.debugNoJS ? undefined : bootstrapScriptContent, + nonce: options?.nonce, + formState: options?.formState, + }); + } catch { + // fallback to render an empty shell and run pure CSR on browser, + // which can replay server component error and trigger error boundary. + status = 500; + htmlStream = await renderToReadableStream( + + + + + , + { + bootstrapScriptContent: + `self.__NO_HYDRATE=1;` + (options?.debugNoJS ? "" : bootstrapScriptContent), + nonce: options?.nonce, + } + ); + } + + let responseStream: ReadableStream = htmlStream; + if (!options?.debugNoJS) { + // Initial RSC stream is injected in HTML stream as + // using utility made by devongovett https://github.com/devongovett/rsc-html-stream + responseStream = responseStream.pipeThrough( + injectRSCPayload(rscStream2, { + nonce: options?.nonce, + }) + ); + } + + return { stream: responseStream, status }; +} +``` + +```tsx [app/framework/error-boundary.tsx] +"use client"; + +import React from "react"; + +// Minimal ErrorBoundary example to handle errors globally on browser +export function GlobalErrorBoundary(props: { children?: React.ReactNode }) { + return {props.children}; +} + +// https://github.com/vercel/next.js/blob/33f8428f7066bf8b2ec61f025427ceb2a54c4bdf/packages/next/src/client/components/error-boundary.tsx +// https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary +class ErrorBoundary extends React.Component<{ + children?: React.ReactNode; + errorComponent: React.FC<{ + error: Error; + reset: () => void; + }>; +}> { + override state: { error?: Error } = {}; + + static getDerivedStateFromError(error: Error) { + return { error }; + } + + reset = () => { + this.setState({ error: null }); + }; + + override render() { + const error = this.state.error; + if (error) { + return ; + } + return this.props.children; + } +} + +// https://github.com/vercel/next.js/blob/677c9b372faef680d17e9ba224743f44e1107661/packages/next/src/build/webpack/loaders/next-app-loader.ts#L73 +// https://github.com/vercel/next.js/blob/677c9b372faef680d17e9ba224743f44e1107661/packages/next/src/client/components/error-boundary.tsx#L145 +function DefaultGlobalErrorPage(props: { error: Error; reset: () => void }) { + return ( + + + Unexpected Error + + +

Caught an unexpected error

+
+          Error:{" "}
+          {import.meta.env.DEV && "message" in props.error ? props.error.message : "(Unknown)"}
+        
+ + + + ); +} +``` + +```tsx [app/framework/request.tsx] +// Framework conventions (arbitrary choices for this demo): +// - Use `_.rsc` URL suffix to differentiate RSC requests from SSR requests +// - Use `x-rsc-action` header to pass server action ID +const URL_POSTFIX = "_.rsc"; +const HEADER_ACTION_ID = "x-rsc-action"; + +// Parsed request information used to route between RSC/SSR rendering and action handling. +// Created by parseRenderRequest() from incoming HTTP requests. +type RenderRequest = { + isRsc: boolean; // true if request should return RSC payload (via _.rsc suffix) + isAction: boolean; // true if this is a server action call (POST request) + actionId?: string; // server action ID from x-rsc-action header + request: Request; // normalized Request with _.rsc suffix removed from URL + url: URL; // normalized URL with _.rsc suffix removed +}; + +export function createRscRenderRequest( + urlString: string, + action?: { id: string; body: BodyInit } +): Request { + const url = new URL(urlString); + url.pathname += URL_POSTFIX; + const headers = new Headers(); + if (action) { + headers.set(HEADER_ACTION_ID, action.id); + } + return new Request(url.toString(), { + method: action ? "POST" : "GET", + headers, + body: action?.body, + }); +} + +export function parseRenderRequest(request: Request): RenderRequest { + const url = new URL(request.url); + const isAction = request.method === "POST"; + if (url.pathname.endsWith(URL_POSTFIX)) { + url.pathname = url.pathname.slice(0, -URL_POSTFIX.length); + const actionId = request.headers.get(HEADER_ACTION_ID) || undefined; + if (request.method === "POST" && !actionId) { + throw new Error("Missing action id header for RSC action request"); + } + return { + isRsc: true, + isAction, + actionId, + request: new Request(url, request), + url, + }; + } else { + return { + isRsc: false, + isAction, + request, + url, + }; + } +} +``` + +:: + + + + + +This example demonstrates React Server Components (RSC) using Vite's experimental RSC plugin with Nitro. It includes server components, client components, server actions, and streaming SSR. + +## Overview + +1. **SSR Entry** handles incoming requests and renders React components to HTML +2. **Root Component** defines the page structure as a server component +3. **Client Components** use the `"use client"` directive for interactive parts + +## 1. SSR Entry + +```tsx [app/framework/entry.ssr.tsx] +import { createFromReadableStream } from "@vitejs/plugin-rsc/ssr"; +import React from "react"; +import type { ReactFormState } from "react-dom/client"; +import { renderToReadableStream } from "react-dom/server.edge"; +import { injectRSCPayload } from "rsc-html-stream/server"; +import type { RscPayload } from "./entry.rsc"; + +export default { + fetch: async (request: Request) => { + const rscEntryModule = await import.meta.viteRsc.loadModule( + "rsc", + "index" + ); + return rscEntryModule.default(request); + }, +}; + +export async function renderHTML( + rscStream: ReadableStream, + options: { + formState?: ReactFormState; + nonce?: string; + debugNoJS?: boolean; + } +): Promise<{ stream: ReadableStream; status?: number }> { + // Duplicate one RSC stream into two. + // - one for SSR (ReactClient.createFromReadableStream below) + // - another for browser hydration payload by injecting . + const [rscStream1, rscStream2] = rscStream.tee(); + + // Deserialize RSC stream back to React VDOM + let payload: Promise | undefined; + function SsrRoot() { + // Deserialization needs to be kicked off inside ReactDOMServer context + // for ReactDOMServer preinit/preloading to work + payload ??= createFromReadableStream(rscStream1); + return React.use(payload).root; + } + + // Render HTML (traditional SSR) + const bootstrapScriptContent = await import.meta.viteRsc.loadBootstrapScriptContent("index"); + + let htmlStream: ReadableStream; + let status: number | undefined; + + try { + htmlStream = await renderToReadableStream(, { + bootstrapScriptContent: options?.debugNoJS ? undefined : bootstrapScriptContent, + nonce: options?.nonce, + formState: options?.formState, + }); + } catch { + // fallback to render an empty shell and run pure CSR on browser, + // which can replay server component error and trigger error boundary. + status = 500; + htmlStream = await renderToReadableStream( + + + + + , + { + bootstrapScriptContent: + `self.__NO_HYDRATE=1;` + (options?.debugNoJS ? "" : bootstrapScriptContent), + nonce: options?.nonce, + } + ); + } + + let responseStream: ReadableStream = htmlStream; + if (!options?.debugNoJS) { + // Initial RSC stream is injected in HTML stream as + // using utility made by devongovett https://github.com/devongovett/rsc-html-stream + responseStream = responseStream.pipeThrough( + injectRSCPayload(rscStream2, { + nonce: options?.nonce, + }) + ); + } + + return { stream: responseStream, status }; +} +``` + +The SSR entry handles the rendering pipeline. It loads the RSC entry module, duplicates the RSC stream (one for SSR, one for hydration), deserializes the stream back to React VDOM, and renders it to HTML. The RSC payload is injected into the HTML for client hydration. + +## 2. Root Server Component + +```tsx [app/root.tsx] +import "./index.css"; // css import is automatically injected in exported server components +import viteLogo from "./assets/vite.svg"; +import { getServerCounter, updateServerCounter } from "./action.tsx"; +import reactLogo from "./assets/react.svg"; +import nitroLogo from "./assets/nitro.svg"; +import { ClientCounter } from "./client.tsx"; + +export function Root(props: { url: URL }) { + return ( + + + {/* eslint-disable-next-line unicorn/text-encoding-identifier-case */} + + + + Nitro + Vite + RSC + + + + + + ); +} + +function App(props: { url: URL }) { + return ( +
+ +

Vite + RSC + Nitro

+
+ +
+
+ + + +
+
Request URL: {props.url?.href}
+
    +
  • + Edit src/client.tsx to test client HMR. +
  • +
  • + Edit src/root.tsx to test server HMR. +
  • +
  • + Visit{" "} + + _.rsc + {" "} + to view RSC stream payload. +
  • +
  • + Visit{" "} + + ?__nojs + {" "} + to test server action without js enabled. +
  • +
+
+ ); +} +``` + +Server components run only on the server. They can import CSS directly, use server-side data, and call server actions. The `ClientCounter` component is imported but runs on the client because it has the `"use client"` directive. + +## 3. Client Component + +```tsx [app/client.tsx] +"use client"; + +import React from "react"; + +export function ClientCounter() { + const [count, setCount] = React.useState(0); + + return ; +} +``` + +The `"use client"` directive marks this as a client component. It hydrates on the browser and handles interactive state. Server components can import and render client components, but client components cannot import server components. + + + +## Learn More + +- [React Server Components](https://react.dev/reference/rsc/server-components) diff --git a/docs/4.examples/vite-ssr-html.md b/docs/4.examples/vite-ssr-html.md new file mode 100644 index 0000000000..cc3209d584 --- /dev/null +++ b/docs/4.examples/vite-ssr-html.md @@ -0,0 +1,233 @@ +--- +category: server side rendering +icon: i-logos-html-5 +--- + +# Vite SSR HTML + +> Server-side rendering with vanilla HTML, Vite, and Nitro. + + + + +::code-tree{defaultValue="app/entry-server.ts" expandAll} + +```html [index.html] + + + + + + Nitro Quotes + + + +
+
+
+ +
+
+ +
+
+ Powered by + Vite + and + Nitro v3. +
+
+ + + + +``` + +```json [package.json] +{ + "type": "module", + "scripts": { + "build": "vite build", + "dev": "vite dev", + "preview": "vite preview" + }, + "devDependencies": { + "@tailwindcss/vite": "^4.1.18", + "nitro": "latest", + "tailwindcss": "^4.1.18", + "vite": "beta" + } +} +``` + +```json [tsconfig.json] +{ + "extends": "nitro/tsconfig" +} +``` + +```ts [vite.config.ts] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +import tailwindcss from "@tailwindcss/vite"; + +export default defineConfig({ + plugins: [ + nitro({ + serverDir: "./", + }), + tailwindcss(), + ], +}); +``` + +```ts [app/entry-server.ts] +import { fetch } from "nitro"; + +export default { + async fetch() { + const quote = (await fetch("/quote").then((res) => res.json())) as { + text: string; + }; + return tokenizedStream(quote.text, 50); + }, +}; + +function tokenizedStream(text: string, delay: number): ReadableStream { + const tokens = text.split(" "); + return new ReadableStream({ + start(controller) { + let index = 0; + function push() { + if (index < tokens.length) { + const word = tokens[index++] + (index < tokens.length ? " " : ""); + controller.enqueue(new TextEncoder().encode(word)); + setTimeout(push, delay); + } else { + controller.close(); + } + } + push(); + }, + }); +} +``` + +```ts [routes/quote.ts] +const QUOTES_URL = + "https://github.com/JamesFT/Database-Quotes-JSON/raw/refs/heads/master/quotes.json"; + +let _quotes: Promise | undefined; + +function getQuotes() { + return (_quotes ??= fetch(QUOTES_URL).then((res) => res.json())) as Promise< + { quoteText: string; quoteAuthor: string }[] + >; +} + +export default async function quotesHandler() { + const quotes = await getQuotes(); + const randomQuote = quotes[Math.floor(Math.random() * quotes.length)]; + return Response.json({ + text: randomQuote.quoteText, + author: randomQuote.quoteAuthor, + }); +} +``` + +:: + + + + + +This example renders an HTML template with server-side data and streams the response word by word. It demonstrates how to use Nitro's Vite SSR integration without a framework. + +## Overview + +1. **Add the Nitro Vite plugin** to enable SSR +2. **Create an HTML template** with a `` comment where server content goes +3. **Create a server entry** that fetches data and returns a stream +4. **Add API routes** for server-side data + +## How It Works + +The `index.html` file contains an `` comment that marks where server-rendered content will be inserted. Nitro replaces this comment with the output from your server entry. + +The server entry exports an object with a `fetch` method. It calls the `/quote` API route using Nitro's internal fetch, then returns a `ReadableStream` that emits the quote text word by word with a 50ms delay between each word. + +The quote route fetches a JSON file of quotes from GitHub, caches the result, and returns a random quote. The server entry calls this route to get content for the page. + + + +## Learn More + +- [Renderer](/docs/renderer) +- [Server Entry](/docs/server-entry) diff --git a/docs/4.examples/vite-ssr-preact.md b/docs/4.examples/vite-ssr-preact.md new file mode 100644 index 0000000000..10cdc9173d --- /dev/null +++ b/docs/4.examples/vite-ssr-preact.md @@ -0,0 +1,262 @@ +--- +category: server side rendering +icon: i-logos-preact +--- + +# SSR with Preact + +> Server-side rendering with Preact in Nitro using Vite. + + + +::code-tree{defaultValue="src/entry-server.tsx" expandAll} + +```json [package.json] +{ + "type": "module", + "scripts": { + "build": "vite build", + "preview": "vite preview", + "dev": "vite dev" + }, + "devDependencies": { + "@preact/preset-vite": "^2.10.3", + "@tailwindcss/vite": "^4.1.18", + "nitro": "latest", + "preact": "^10.28.3", + "preact-render-to-string": "^6.6.5", + "tailwindcss": "^4.1.18", + "vite": "beta" + } +} +``` + +```json [tsconfig.json] +{ + "extends": "nitro/tsconfig", + "compilerOptions": { + "jsx": "react-jsx", + "jsxImportSource": "preact" + } +} +``` + +```js [vite.config.mjs] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; +import preact from "@preact/preset-vite"; + +export default defineConfig({ + plugins: [nitro(), preact()], + environments: { + client: { + build: { + rollupOptions: { + input: "./src/entry-client.tsx", + }, + }, + }, + }, +}); +``` + +```tsx [src/app.tsx] +import { useState } from "preact/hooks"; + +export function App() { + const [count, setCount] = useState(0); + return ; +} +``` + +```tsx [src/entry-client.tsx] +import { hydrate } from "preact"; +import { App } from "./app.tsx"; + +function main() { + hydrate(, document.querySelector("#app")!); +} + +main(); +``` + +```tsx [src/entry-server.tsx] +import "./styles.css"; +import { renderToReadableStream } from "preact-render-to-string/stream"; +import { App } from "./app.jsx"; + +import clientAssets from "./entry-client?assets=client"; +import serverAssets from "./entry-server?assets=ssr"; + +export default { + async fetch(request: Request) { + const url = new URL(request.url); + const htmlStream = renderToReadableStream(); + return new Response(htmlStream, { + headers: { "Content-Type": "text/html;charset=utf-8" }, + }); + }, +}; + +function Root(props: { url: URL }) { + const assets = clientAssets.merge(serverAssets); + return ( + + + + {assets.css.map((attr: any) => ( + + ))} + {assets.js.map((attr: any) => ( + + ))} + + + +``` + +```json [package.json] +{ + "type": "module", + "scripts": { + "build": "vite build", + "dev": "vite dev", + "preview": "vite preview" + }, + "devDependencies": { + "@tanstack/react-router": "^1.158.1", + "@tanstack/react-router-devtools": "^1.158.1", + "@tanstack/router-plugin": "^1.158.1", + "@types/react": "^19.2.13", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^5.1.3", + "nitro": "latest", + "react": "^19.2.4", + "react-dom": "^19.2.4", + "vite": "beta" + } +} +``` + +```json [tsconfig.json] +{ + "extends": "nitro/tsconfig", + "compilerOptions": { + "baseUrl": ".", + "jsx": "react-jsx", + "paths": { + "@/*": ["sec/*"] + } + } +} +``` + +```js [vite.config.mjs] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; +import react from "@vitejs/plugin-react"; +import { tanstackRouter } from "@tanstack/router-plugin/vite"; + +export default defineConfig({ + plugins: [tanstackRouter({ target: "react", autoCodeSplitting: true }), react(), nitro()], +}); +``` + +```tsx [src/main.tsx] +import { StrictMode } from "react"; +import ReactDOM from "react-dom/client"; +import { RouterProvider, createRouter } from "@tanstack/react-router"; + +// Import the generated route tree +import { routeTree } from "./routeTree.gen.ts"; + +// Create a new router instance +const router = createRouter({ routeTree }); + +// Register the router instance for type safety +declare module "@tanstack/react-router" { + interface Register { + router: typeof router; + } +} + +// Render the app +const rootElement = document.querySelector("#root")!; +if (!rootElement.innerHTML) { + const root = ReactDOM.createRoot(rootElement); + root.render( + + + + ); +} +``` + +```ts [src/routeTree.gen.ts] +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +import { Route as rootRouteImport } from './routes/__root' +import { Route as IndexRouteImport } from './routes/index' + +const IndexRoute = IndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => rootRouteImport, +} as any) + +export interface FileRoutesByFullPath { + '/': typeof IndexRoute +} +export interface FileRoutesByTo { + '/': typeof IndexRoute +} +export interface FileRoutesById { + __root__: typeof rootRouteImport + '/': typeof IndexRoute +} +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: '/' + fileRoutesByTo: FileRoutesByTo + to: '/' + id: '__root__' | '/' + fileRoutesById: FileRoutesById +} +export interface RootRouteChildren { + IndexRoute: typeof IndexRoute +} + +declare module '@tanstack/react-router' { + interface FileRoutesByPath { + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof IndexRouteImport + parentRoute: typeof rootRouteImport + } + } +} + +const rootRouteChildren: RootRouteChildren = { + IndexRoute: IndexRoute, +} +export const routeTree = rootRouteImport + ._addFileChildren(rootRouteChildren) + ._addFileTypes() +``` + +```css [src/assets/main.css] +:root { + font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { + font-weight: 500; + color: #ff2056; + text-decoration: inherit; +} +a:hover { + color: #ff637e; +} + +body { + margin: 0; + display: flex; + flex-direction: column; + place-items: center; + justify-content: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; + transition: transform 300ms; +} +.logo:hover { + transform: scale(1.1); +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} +``` + +```tsx [src/routes/__root.tsx] +import { createRootRoute, Link, Outlet } from "@tanstack/react-router"; +import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; + +const RootLayout = () => ( + <> +
+ + Home + +
+
+ + + +); + +export const Route = createRootRoute({ component: RootLayout }); +``` + +```tsx [src/routes/index.tsx] +import { createFileRoute } from "@tanstack/react-router"; + +export const Route = createFileRoute("/")({ + loader: async () => { + const r = await fetch("/api/hello"); + return r.json(); + }, + component: Index, +}); + +function Index() { + const r = Route.useLoaderData(); + + return ( +
+

{JSON.stringify(r)}

+
+ ); +} +``` + +:: + + + + + +Set up TanStack Router with React, Vite, and Nitro. This setup provides file-based routing with type-safe navigation and automatic code splitting. + +## Overview + +1. Add the Nitro Vite plugin to your Vite config +2. Create an HTML template with your app entry +3. Create a main entry that initializes the router +4. Define routes using file-based routing + +## 1. Configure Vite + +Add the Nitro, React, and TanStack Router plugins to your Vite config: + +```js [vite.config.mjs] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; +import react from "@vitejs/plugin-react"; +import { tanstackRouter } from "@tanstack/router-plugin/vite"; + +export default defineConfig({ + plugins: [tanstackRouter({ target: "react", autoCodeSplitting: true }), react(), nitro()], +}); +``` + +The `tanstackRouter` plugin generates a route tree from your `routes/` directory structure. Enable `autoCodeSplitting` to automatically split routes into separate chunks. Place the TanStack Router plugin before the React plugin in the array. + +## 2. Create the HTML Template + +Create an HTML file that serves as your app shell: + +```html [index.html] + + + + + + Nitro + TanStack Router + React + + + +
+ + + +``` + +## 3. Create the App Entry + +Create the main entry that initializes TanStack Router: + +```tsx [src/main.tsx] +import { StrictMode } from "react"; +import ReactDOM from "react-dom/client"; +import { RouterProvider, createRouter } from "@tanstack/react-router"; + +// Import the generated route tree +import { routeTree } from "./routeTree.gen.ts"; + +// Create a new router instance +const router = createRouter({ routeTree }); + +// Register the router instance for type safety +declare module "@tanstack/react-router" { + interface Register { + router: typeof router; + } +} + +// Render the app +const rootElement = document.querySelector("#root")!; +if (!rootElement.innerHTML) { + const root = ReactDOM.createRoot(rootElement); + root.render( + + + + ); +} +``` + +The `routeTree.gen.ts` file is auto-generated from your `routes/` directory structure. The `Register` interface declaration provides full type inference for route paths and params. The `!rootElement.innerHTML` check prevents re-rendering during hot module replacement. + +## 4. Create the Root Route + +The root route (`__root.tsx`) defines your app's layout: + +```tsx [src/routes/__root.tsx] +import { createRootRoute, Link, Outlet } from "@tanstack/react-router"; +import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; + +const RootLayout = () => ( + <> +
+ + Home + +
+
+ + + +); + +export const Route = createRootRoute({ component: RootLayout }); +``` + +Use `Link` for type-safe navigation with active state styling. The `Outlet` component renders child routes. Include `TanStackRouterDevtools` for development tools (automatically removed in production). + +## 5. Create Page Routes + +Page routes use `createFileRoute` and can include loaders: + +```tsx [src/routes/index.tsx] +import { createFileRoute } from "@tanstack/react-router"; + +export const Route = createFileRoute("/")({ + loader: async () => { + const r = await fetch("/api/hello"); + return r.json(); + }, + component: Index, +}); + +function Index() { + const r = Route.useLoaderData(); + + return ( +
+

{JSON.stringify(r)}

+
+ ); +} +``` + +Fetch data before rendering with the `loader` function—data is available via `Route.useLoaderData()`. File paths determine URL paths: `routes/index.tsx` maps to `/`, `routes/about.tsx` to `/about`, and `routes/users/$id.tsx` to `/users/:id`. + + + +## Learn More + +- [TanStack Router Documentation](https://tanstack.com/router) +- [Renderer](/docs/renderer) diff --git a/docs/4.examples/vite-ssr-tss-react.md b/docs/4.examples/vite-ssr-tss-react.md new file mode 100644 index 0000000000..b2dcca36ca --- /dev/null +++ b/docs/4.examples/vite-ssr-tss-react.md @@ -0,0 +1,459 @@ +--- +category: server side rendering +icon: i-simple-icons-tanstack +--- + +# SSR with TanStack Start + +> Full-stack React with TanStack Start in Nitro using Vite. + + + +::code-tree{defaultValue="server.ts" expandAll} + +```json [package.json] +{ + "type": "module", + "scripts": { + "build": "vite build", + "dev": "vite dev", + "start": "node .output/server/index.mjs" + }, + "dependencies": { + "@tanstack/react-router": "^1.158.1", + "@tanstack/react-router-devtools": "^1.158.1", + "@tanstack/react-start": "^1.158.3", + "nitro": "latest", + "react": "^19.2.4", + "react-dom": "^19.2.4", + "tailwind-merge": "^3.4.0", + "zod": "^4.3.6" + }, + "devDependencies": { + "@tailwindcss/vite": "^4.1.18", + "@types/node": "latest", + "@types/react": "^19.2.13", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^5.1.3", + "tailwindcss": "^4.1.18", + "typescript": "^5.9.3", + "vite": "beta", + "vite-tsconfig-paths": "^6.0.5" + } +} +``` + +```ts [server.ts] +import handler, { createServerEntry } from "@tanstack/react-start/server-entry"; + +export default createServerEntry({ + fetch(request) { + return handler.fetch(request); + }, +}); +``` + +```json [tsconfig.json] +{ + "extends": "nitro/tsconfig", + "compilerOptions": { + "baseUrl": ".", + "jsx": "react-jsx", + "paths": { + "~/*": ["./src/*"] + } + } +} +``` + +```js [vite.config.mjs] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; +import { tanstackStart } from "@tanstack/react-start/plugin/vite"; +import viteReact from "@vitejs/plugin-react"; +import viteTsConfigPaths from "vite-tsconfig-paths"; +import tailwindcss from "@tailwindcss/vite"; + +export default defineConfig({ + plugins: [ + viteTsConfigPaths({ projects: ["./tsconfig.json"] }), + tanstackStart(), + viteReact(), + tailwindcss(), + nitro(), + ], + environments: { + ssr: { build: { rollupOptions: { input: "./server.ts" } } }, + }, +}); +``` + +```tsx [src/router.tsx] +import { createRouter } from "@tanstack/react-router"; +import { routeTree } from "./routeTree.gen.ts"; + +export function getRouter() { + const router = createRouter({ + routeTree, + defaultPreload: "intent", + defaultErrorComponent: () =>
Internal Server Error
, + defaultNotFoundComponent: () =>
Not Found
, + scrollRestoration: true, + }); + return router; +} +``` + +```ts [src/routeTree.gen.ts] +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +import { Route as rootRouteImport } from './routes/__root' +import { Route as IndexRouteImport } from './routes/index' +import { Route as ApiTestRouteImport } from './routes/api/test' + +const IndexRoute = IndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => rootRouteImport, +} as any) +const ApiTestRoute = ApiTestRouteImport.update({ + id: '/api/test', + path: '/api/test', + getParentRoute: () => rootRouteImport, +} as any) + +export interface FileRoutesByFullPath { + '/': typeof IndexRoute + '/api/test': typeof ApiTestRoute +} +export interface FileRoutesByTo { + '/': typeof IndexRoute + '/api/test': typeof ApiTestRoute +} +export interface FileRoutesById { + __root__: typeof rootRouteImport + '/': typeof IndexRoute + '/api/test': typeof ApiTestRoute +} +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: '/' | '/api/test' + fileRoutesByTo: FileRoutesByTo + to: '/' | '/api/test' + id: '__root__' | '/' | '/api/test' + fileRoutesById: FileRoutesById +} +export interface RootRouteChildren { + IndexRoute: typeof IndexRoute + ApiTestRoute: typeof ApiTestRoute +} + +declare module '@tanstack/react-router' { + interface FileRoutesByPath { + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof IndexRouteImport + parentRoute: typeof rootRouteImport + } + '/api/test': { + id: '/api/test' + path: '/api/test' + fullPath: '/api/test' + preLoaderRoute: typeof ApiTestRouteImport + parentRoute: typeof rootRouteImport + } + } +} + +const rootRouteChildren: RootRouteChildren = { + IndexRoute: IndexRoute, + ApiTestRoute: ApiTestRoute, +} +export const routeTree = rootRouteImport + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +import type { getRouter } from './router.tsx' +import type { createStart } from '@tanstack/react-start' +declare module '@tanstack/react-start' { + interface Register { + ssr: true + router: Awaited> + } +} +``` + +```tsx [src/routes/__root.tsx] +/// +import { HeadContent, Link, Scripts, createRootRoute } from "@tanstack/react-router"; +import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; +import * as React from "react"; +import appCss from "~/styles/app.css?url"; + +export const Route = createRootRoute({ + head: () => ({ + meta: [ + { charSet: "utf8" }, + { name: "viewport", content: "width=device-width, initial-scale=1" }, + ], + links: [{ rel: "stylesheet", href: appCss }], + scripts: [{ src: "/customScript.js", type: "text/javascript" }], + }), + errorComponent: () =>

500: Internal Server Error

, + notFoundComponent: () =>

404: Page Not Found

, + shellComponent: RootDocument, +}); + +function RootDocument({ children }: { children: React.ReactNode }) { + return ( + + + + + +
+ + Home + {" "} + + 404 + +
+
+ {children} + + + + + ); +} +``` + +```tsx [src/routes/index.tsx] +import { createFileRoute } from "@tanstack/react-router"; + +export const Route = createFileRoute("/")({ component: Home }); + +function Home() { + return ( +
+

Welcome Home!

+ /api/test +
+ ); +} +``` + +```css [src/styles/app.css] +@import "tailwindcss"; + +@layer base { + *, + ::after, + ::before, + ::backdrop, + ::file-selector-button { + border-color: var(--color-gray-200, currentcolor); + } +} + +@layer base { + html { + color-scheme: light dark; + } + + * { + @apply border-gray-200 dark:border-gray-800; + } + + html, + body { + @apply text-gray-900 bg-gray-50 dark:bg-gray-950 dark:text-gray-200; + } + + .using-mouse * { + outline: none !important; + } +} +``` + +:: + + + + + +Set up TanStack Start with Nitro for a full-stack React framework experience with server-side rendering, file-based routing, and integrated API routes. + +## Overview + +1. Add the Nitro Vite plugin to your Vite config +2. Create a server entry using TanStack Start's server handler +3. Configure the router with default components +4. Define routes and API endpoints using file-based routing + +## 1. Configure Vite + +Add the Nitro, React, TanStack Start, and Tailwind plugins to your Vite config: + +```js [vite.config.mjs] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; +import { tanstackStart } from "@tanstack/react-start/plugin/vite"; +import viteReact from "@vitejs/plugin-react"; +import viteTsConfigPaths from "vite-tsconfig-paths"; +import tailwindcss from "@tailwindcss/vite"; + +export default defineConfig({ + plugins: [ + viteTsConfigPaths({ projects: ["./tsconfig.json"] }), + tanstackStart(), + viteReact(), + tailwindcss(), + nitro(), + ], + environments: { + ssr: { build: { rollupOptions: { input: "./server.ts" } } }, + }, +}); +``` + +The `tanstackStart()` plugin provides full SSR integration with automatic client entry handling. Use `viteTsConfigPaths()` to enable path aliases like `~/` from tsconfig. The `environments.ssr` option points to the server entry file. + +## 2. Create the Server Entry + +Create a server entry that uses TanStack Start's handler: + +```ts [server.ts] +import handler, { createServerEntry } from "@tanstack/react-start/server-entry"; + +export default createServerEntry({ + fetch(request) { + return handler.fetch(request); + }, +}); +``` + +TanStack Start handles SSR automatically. The `createServerEntry` wrapper integrates with Nitro's server entry format, and the `handler.fetch` processes all incoming requests. + +## 3. Configure the Router + +Create a router factory function with default error and not-found components: + +```tsx [src/router.tsx] +import { createRouter } from "@tanstack/react-router"; +import { routeTree } from "./routeTree.gen.ts"; + +export function getRouter() { + const router = createRouter({ + routeTree, + defaultPreload: "intent", + defaultErrorComponent: () =>
Internal Server Error
, + defaultNotFoundComponent: () =>
Not Found
, + scrollRestoration: true, + }); + return router; +} +``` + +The router factory configures preloading behavior, scroll restoration, and default error/not-found components. + +## 4. Create the Root Route + +The root route defines your HTML shell with head management and scripts: + +```tsx [src/routes/__root.tsx] +/// +import { HeadContent, Link, Scripts, createRootRoute } from "@tanstack/react-router"; +import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; +import * as React from "react"; +import appCss from "~/styles/app.css?url"; + +export const Route = createRootRoute({ + head: () => ({ + meta: [ + { charSet: "utf8" }, + { name: "viewport", content: "width=device-width, initial-scale=1" }, + ], + links: [{ rel: "stylesheet", href: appCss }], + scripts: [{ src: "/customScript.js", type: "text/javascript" }], + }), + errorComponent: () =>

500: Internal Server Error

, + notFoundComponent: () =>

404: Page Not Found

, + shellComponent: RootDocument, +}); + +function RootDocument({ children }: { children: React.ReactNode }) { + return ( + + + + + +
+ + Home + {" "} + + 404 + +
+
+ {children} + + + + + ); +} +``` + +Define meta tags, stylesheets, and scripts in the `head()` function. The `shellComponent` provides the HTML document shell that wraps all pages. Use `HeadContent` to render the head configuration and `Scripts` to inject the client-side JavaScript for hydration. + +## 5. Create Page Routes + +Page routes define your application pages: + +```tsx [src/routes/index.tsx] +import { createFileRoute } from "@tanstack/react-router"; + +export const Route = createFileRoute("/")({ component: Home }); + +function Home() { + return ( +
+

Welcome Home!

+ /api/test +
+ ); +} +``` + +## API Routes + +TanStack Start supports API routes alongside page routes. Create files in `src/routes/api/` to define server endpoints that Nitro serves automatically. + + + +## Learn More + +- [TanStack Start Documentation](https://tanstack.com/start) +- [Server Entry](/docs/server-entry) diff --git a/docs/4.examples/vite-ssr-vue-router.md b/docs/4.examples/vite-ssr-vue-router.md new file mode 100644 index 0000000000..107f72633b --- /dev/null +++ b/docs/4.examples/vite-ssr-vue-router.md @@ -0,0 +1,631 @@ +--- +category: server side rendering +icon: i-logos-vue +--- + +# SSR with Vue Router + +> Server-side rendering with Vue Router in Nitro using Vite. + + + +::code-tree{defaultValue="app/entry-server.ts" expandAll} + +```json [package.json] +{ + "type": "module", + "scripts": { + "build": "vite build", + "dev": "vite dev", + "preview": "vite preview" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^6.0.4", + "nitro": "latest", + "unhead": "^2.1.3", + "vite": "beta", + "vite-plugin-devtools-json": "^1.0.0", + "vue": "^3.5.27", + "vue-router": "^4.6.4" + } +} +``` + +```json [tsconfig.json] +{ + "extends": "nitro/tsconfig" +} +``` + +```js [vite.config.mjs] +import vue from "@vitejs/plugin-vue"; +import { defineConfig } from "vite"; +import devtoolsJson from "vite-plugin-devtools-json"; +import { nitro } from "nitro/vite"; + +export default defineConfig((_env) => ({ + plugins: [patchVueExclude(vue(), /\?assets/), devtoolsJson(), nitro()], + environments: { + client: { build: { rollupOptions: { input: "./app/entry-client.ts" } } }, + ssr: { build: { rollupOptions: { input: "./app/entry-server.ts" } } }, + }, +})); + +// Workaround https://github.com/vitejs/vite-plugin-vue/issues/677 +function patchVueExclude(plugin, exclude) { + const original = plugin.transform.handler; + plugin.transform.handler = function (...args) { + if (exclude.test(args[1])) return; + return original.call(this, ...args); + }; + return plugin; +} +``` + +```vue [app/app.vue] + + + + + +``` + +```ts [app/entry-client.ts] +import { createSSRApp } from "vue"; +import { RouterView, createRouter, createWebHistory } from "vue-router"; +import { routes } from "./routes.ts"; + +async function main() { + const app = createSSRApp(RouterView); + const router = createRouter({ history: createWebHistory(), routes }); + app.use(router); + + await router.isReady(); + app.mount("#root"); +} + +// eslint-disable-next-line unicorn/prefer-top-level-await +main(); +``` + +```ts [app/entry-server.ts] +import { createSSRApp } from "vue"; +import { renderToString } from "vue/server-renderer"; +import { RouterView, createMemoryHistory, createRouter } from "vue-router"; +import { createHead, transformHtmlTemplate } from "unhead/server"; + +import { routes } from "./routes.ts"; + +import clientAssets from "./entry-client.ts?assets=client"; + +async function handler(request: Request): Promise { + const app = createSSRApp(RouterView); + const router = createRouter({ history: createMemoryHistory(), routes }); + app.use(router); + + const url = new URL(request.url); + const href = url.href.slice(url.origin.length); + + await router.push(href); + await router.isReady(); + + const assets = clientAssets.merge( + ...(await Promise.all( + router.currentRoute.value.matched + .map((to) => to.meta.assets) + .filter(Boolean) + .map((fn) => (fn as any)().then((m: any) => m.default)) + )) + ); + + const head = createHead(); + + head.push({ + link: [ + ...assets.css.map((attrs: any) => ({ rel: "stylesheet", ...attrs })), + ...assets.js.map((attrs: any) => ({ rel: "modulepreload", ...attrs })), + ], + script: [{ type: "module", src: clientAssets.entry }], + }); + + const renderedApp = await renderToString(app); + + const html = await transformHtmlTemplate(head, htmlTemplate(renderedApp)); + + return new Response(html, { + headers: { "Content-Type": "text/html;charset=utf-8" }, + }); +} + +function htmlTemplate(body: string): string { + return /* html */ ` + + + + + Vue Router Custom Framework + + +
${body}
+ +`; +} + +export default { + fetch: handler, +}; +``` + +```ts [app/routes.ts] +import type { RouteRecordRaw } from "vue-router"; + +export const routes: RouteRecordRaw[] = [ + { + path: "/", + name: "app", + component: () => import("./app.vue"), + meta: { + assets: () => import("./app.vue?assets"), + }, + children: [ + { + path: "/", + name: "home", + component: () => import("./pages/index.vue"), + meta: { + assets: () => import("./pages/index.vue?assets"), + }, + }, + { + path: "/about", + name: "about", + component: () => import("./pages/about.vue"), + meta: { + assets: () => import("./pages/about.vue?assets"), + }, + }, + { + path: "/:catchAll(.*)", + name: "not-found", + component: () => import("./pages/not-found.vue"), + meta: { + assets: () => import("./pages/not-found.vue?assets"), + }, + }, + ], + }, +]; +``` + +```ts [app/shims.d.ts] +declare module "*.vue" { + import type { DefineComponent } from "vue"; + const component: DefineComponent<{}, {}, any>; + export default component; +} +``` + +```css [app/styles.css] +* { + box-sizing: border-box; +} + +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + background: #f5f5f5; + color: #333; +} + +main { + max-width: 800px; + margin: 0 auto; + padding: 2rem; +} + +h1 { + font-size: 2.5rem; + margin-bottom: 0.5rem; +} + +.card { + background: white; + border-radius: 8px; + padding: 2rem; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + margin: 2rem 0; +} + +button { + background: rgb(83, 91, 242); + color: white; + border: none; + padding: 0.5rem 1rem; + border-radius: 4px; + font-size: 1rem; + cursor: pointer; +} + +button:hover { + background: #535bf2; +} + +.subtitle { + color: #666; + font-size: 1.1rem; + margin-bottom: 2rem; +} +``` + +```vue [app/pages/about.vue] + +``` + +```vue [app/pages/index.vue] + + + + + +``` + +```vue [app/pages/not-found.vue] + +``` + +:: + + + + + +Set up server-side rendering (SSR) with Vue, Vue Router, Vite, and Nitro. This setup enables per-route code splitting, head management with unhead, and client hydration. + +## Overview + +1. Add the Nitro Vite plugin to your Vite config +2. Define routes with lazy-loaded components +3. Create a server entry that renders your app with router support +4. Create a client entry that hydrates and takes over routing +5. Create page components + +## 1. Configure Vite + +Add the Nitro and Vue plugins to your Vite config. Define both `client` and `ssr` environments: + +```js [vite.config.mjs] +import vue from "@vitejs/plugin-vue"; +import { defineConfig } from "vite"; +import devtoolsJson from "vite-plugin-devtools-json"; +import { nitro } from "nitro/vite"; + +export default defineConfig((_env) => ({ + plugins: [patchVueExclude(vue(), /\?assets/), devtoolsJson(), nitro()], + environments: { + client: { build: { rollupOptions: { input: "./app/entry-client.ts" } } }, + ssr: { build: { rollupOptions: { input: "./app/entry-server.ts" } } }, + }, +})); + +// Workaround https://github.com/vitejs/vite-plugin-vue/issues/677 +function patchVueExclude(plugin, exclude) { + const original = plugin.transform.handler; + plugin.transform.handler = function (...args) { + if (exclude.test(args[1])) return; + return original.call(this, ...args); + }; + return plugin; +} +``` + +The `patchVueExclude` helper prevents the Vue plugin from processing asset imports (files with `?assets` query parameter). + +## 2. Define Routes + +Create route definitions with lazy-loaded components and asset metadata: + +```ts [app/routes.ts] +import type { RouteRecordRaw } from "vue-router"; + +export const routes: RouteRecordRaw[] = [ + { + path: "/", + name: "app", + component: () => import("./app.vue"), + meta: { + assets: () => import("./app.vue?assets"), + }, + children: [ + { + path: "/", + name: "home", + component: () => import("./pages/index.vue"), + meta: { + assets: () => import("./pages/index.vue?assets"), + }, + }, + { + path: "/about", + name: "about", + component: () => import("./pages/about.vue"), + meta: { + assets: () => import("./pages/about.vue?assets"), + }, + }, + { + path: "/:catchAll(.*)", + name: "not-found", + component: () => import("./pages/not-found.vue"), + meta: { + assets: () => import("./pages/not-found.vue?assets"), + }, + }, + ], + }, +]; +``` + +Use dynamic imports for lazy-loaded components to enable code splitting. The `meta.assets` function loads route-specific CSS and JS chunks. Define child routes under a root layout component for nested routing. + +## 3. Create the Server Entry + +The server entry renders your Vue app with router support and head management: + +```ts [app/entry-server.ts] +import { createSSRApp } from "vue"; +import { renderToString } from "vue/server-renderer"; +import { RouterView, createMemoryHistory, createRouter } from "vue-router"; +import { createHead, transformHtmlTemplate } from "unhead/server"; + +import { routes } from "./routes.ts"; + +import clientAssets from "./entry-client.ts?assets=client"; + +async function handler(request: Request): Promise { + const app = createSSRApp(RouterView); + const router = createRouter({ history: createMemoryHistory(), routes }); + app.use(router); + + const url = new URL(request.url); + const href = url.href.slice(url.origin.length); + + await router.push(href); + await router.isReady(); + + const assets = clientAssets.merge( + ...(await Promise.all( + router.currentRoute.value.matched + .map((to) => to.meta.assets) + .filter(Boolean) + .map((fn) => (fn as any)().then((m: any) => m.default)) + )) + ); + + const head = createHead(); + + head.push({ + link: [ + ...assets.css.map((attrs: any) => ({ rel: "stylesheet", ...attrs })), + ...assets.js.map((attrs: any) => ({ rel: "modulepreload", ...attrs })), + ], + script: [{ type: "module", src: clientAssets.entry }], + }); + + const renderedApp = await renderToString(app); + + const html = await transformHtmlTemplate(head, htmlTemplate(renderedApp)); + + return new Response(html, { + headers: { "Content-Type": "text/html;charset=utf-8" }, + }); +} + +function htmlTemplate(body: string): string { + return /* html */ ` + + + + + Vue Router Custom Framework + + +
${body}
+ +`; +} + +export default { + fetch: handler, +}; +``` + +The server uses `createMemoryHistory()` since there's no browser URL bar—the router navigates to the requested URL before rendering. Assets are loaded dynamically based on matched routes, ensuring only the CSS and JS needed for the current page are included. The `unhead` library manages `` elements, injecting stylesheets and scripts via `transformHtmlTemplate`. + +## 4. Create the Client Entry + +The client entry hydrates the server-rendered HTML and takes over routing: + +```ts [app/entry-client.ts] +import { createSSRApp } from "vue"; +import { RouterView, createRouter, createWebHistory } from "vue-router"; +import { routes } from "./routes.ts"; + +async function main() { + const app = createSSRApp(RouterView); + const router = createRouter({ history: createWebHistory(), routes }); + app.use(router); + + await router.isReady(); + app.mount("#root"); +} + +// eslint-disable-next-line unicorn/prefer-top-level-await +main(); +``` + +The client entry creates a Vue app with `createWebHistory()` for browser-based routing. After the router is ready, it mounts to the `#root` element and hydrates the server-rendered HTML. + +## 5. Create the Root Component + +The root component provides navigation and renders child routes: + +```vue [app/app.vue] + + + + + +``` + + + +## Learn More + +- [Vue Router Documentation](https://router.vuejs.org/) +- [Unhead Documentation](https://unhead.unjs.io/) +- [Renderer](/docs/renderer) +- [Server Entry](/docs/server-entry) diff --git a/docs/4.examples/vite-trpc.md b/docs/4.examples/vite-trpc.md new file mode 100644 index 0000000000..93079ef194 --- /dev/null +++ b/docs/4.examples/vite-trpc.md @@ -0,0 +1,350 @@ +--- +category: vite +icon: i-simple-icons-trpc +--- + +# Vite + tRPC + +> End-to-end typesafe APIs with tRPC in Nitro using Vite. + + + +::code-tree{defaultValue="server/trpc.ts" expandAll} + +```html [index.html] + + + + + tRPC Counter + + + +
+
Counter
+
+ +
+ +
+ + + + +``` + +```json [package.json] +{ + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "devDependencies": { + "@trpc/client": "^11.9.0", + "@trpc/server": "^11.9.0", + "nitro": "latest", + "vite": "beta", + "zod": "^4.3.6" + } +} +``` + +```json [tsconfig.json] +{ + "extends": "nitro/tsconfig", + "compilerOptions": {} +} +``` + +```ts [vite.config.ts] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ + plugins: [ + nitro({ + routes: { + "/trpc/**": "./server/trpc.ts", + }, + }), + ], +}); +``` + +```ts [server/trpc.ts] +import { initTRPC } from "@trpc/server"; +import { fetchRequestHandler } from "@trpc/server/adapters/fetch"; + +let counter = 0; + +const t = initTRPC.create(); + +export const appRouter = t.router({ + get: t.procedure.query(() => { + return { value: counter }; + }), + + inc: t.procedure.mutation(() => { + counter++; + return { value: counter }; + }), +}); + +export type AppRouter = typeof appRouter; + +export default { + async fetch(request: Request): Promise { + return fetchRequestHandler({ + endpoint: "/trpc", + req: request, + router: appRouter, + }); + }, +}; +``` + +:: + + + + + +Set up tRPC with Vite and Nitro for end-to-end typesafe APIs without code generation. This example builds a counter with server-side rendering for the initial value and client-side updates. + +## Overview + +1. Configure Vite with the Nitro plugin and route tRPC requests +2. Create a tRPC router with procedures +3. Create an HTML page with server-side rendering and client interactivity + +## 1. Configure Vite + +Add the Nitro plugin and configure the `/trpc/**` route to point to your tRPC handler: + +```ts [vite.config.ts] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ + plugins: [ + nitro({ + routes: { + "/trpc/**": "./server/trpc.ts", + }, + }), + ], +}); +``` + +The `routes` option maps URL patterns to handler files. All requests to `/trpc/*` are handled by the tRPC router. + +## 2. Create the tRPC Router + +Define your tRPC router with procedures and export it as a fetch handler: + +```ts [server/trpc.ts] +import { initTRPC } from "@trpc/server"; +import { fetchRequestHandler } from "@trpc/server/adapters/fetch"; + +let counter = 0; + +const t = initTRPC.create(); + +export const appRouter = t.router({ + get: t.procedure.query(() => { + return { value: counter }; + }), + + inc: t.procedure.mutation(() => { + counter++; + return { value: counter }; + }), +}); + +export type AppRouter = typeof appRouter; + +export default { + async fetch(request: Request): Promise { + return fetchRequestHandler({ + endpoint: "/trpc", + req: request, + router: appRouter, + }); + }, +}; +``` + +Define procedures using `t.procedure.query()` for read operations and `t.procedure.mutation()` for write operations. Export the `AppRouter` type so clients get full type inference. The default export uses tRPC's fetch adapter to handle incoming requests. + +## 3. Create the HTML Page + +Create an HTML page with server-side rendering and client-side interactivity: + +```html [index.html] + + + + + tRPC Counter + + + +
+
Counter
+
+ +
+ +
+ + + + +``` + +The ` + + + + +
+ +
+
+
+

{{ message.user }}

+
+ Avatar +
+

+

{{ message.text }}

+
+
+

{{ message.date }}

+
+
+
+ + +
+
+ +
+
+ + + + +
+
+
+ + +` +``` + +```ts [nitro.config.ts] +import { defineConfig } from "nitro"; + +export default defineConfig({ + serverDir: "./", + renderer: { static: true }, + features: { websocket: true }, +}); +``` + +```json [package.json] +{ + "type": "module", + "scripts": { + "dev": "nitro dev", + "build": "nitro build" + }, + "devDependencies": { + "nitro": "latest" + } +} +``` + +```json [tsconfig.json] +{ + "extends": "nitro/tsconfig" +} +``` + +```ts [vite.config.ts] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); +``` + +```ts [routes/_ws.ts] +import { defineWebSocketHandler } from "nitro"; + +export default defineWebSocketHandler({ + open(peer) { + peer.send({ user: "server", message: `Welcome ${peer}!` }); + peer.publish("chat", { user: "server", message: `${peer} joined!` }); + peer.subscribe("chat"); + }, + message(peer, message) { + if (message.text().includes("ping")) { + peer.send({ user: "server", message: "pong" }); + } else { + const msg = { + user: peer.toString(), + message: message.toString(), + }; + peer.send(msg); // echo + peer.publish("chat", msg); + } + }, + close(peer) { + peer.publish("chat", { user: "server", message: `${peer} left!` }); + }, +}); +``` + +:: + + + + + +This example implements a simple chat room using WebSockets. Clients connect, send messages, and receive messages from other users in real-time. The server broadcasts messages to all connected clients using pub/sub channels. + +## WebSocket Handler + +Create a WebSocket route using `defineWebSocketHandler`. + +```ts [routes/_ws.ts] +import { defineWebSocketHandler } from "nitro"; + +export default defineWebSocketHandler({ + open(peer) { + peer.send({ user: "server", message: `Welcome ${peer}!` }); + peer.publish("chat", { user: "server", message: `${peer} joined!` }); + peer.subscribe("chat"); + }, + message(peer, message) { + if (message.text().includes("ping")) { + peer.send({ user: "server", message: "pong" }); + } else { + const msg = { + user: peer.toString(), + message: message.toString(), + }; + peer.send(msg); // echo + peer.publish("chat", msg); + } + }, + close(peer) { + peer.publish("chat", { user: "server", message: `${peer} left!` }); + }, +}); +``` + +Different hooks are exposed by `defineWebSocketHandler()` to integrate with different parts of the websocket lifecycle. + + + +## Learn More + +- [Routing](/docs/routing) +- [crossws Documentation](https://crossws.h3.dev/guide/hooks) diff --git a/docs/9.blog/1.v3-beta.md b/docs/9.blog/1.v3-beta.md new file mode 100644 index 0000000000..94650dbac8 --- /dev/null +++ b/docs/9.blog/1.v3-beta.md @@ -0,0 +1,224 @@ +--- +date: 2026-03-11 +category: release +authors: + - name: Pooya Parsa + github: pi0 +--- + +# Nitro v3 Beta is here! + +> Nitro v3 is now available as a public beta — a ground-up evolution of the server framework, built around web standards, Rolldown, Vite v8, and the same deploy-anywhere promise. + + + +## A Brief History + +Nitro started as the server engine for [Nuxt 3](https://nuxt.com), designed to solve a specific problem: deployment-agnostic servers. +Over time, Nitro grew beyond Nuxt. It became the foundation for many meta-frameworks and a toolkit for building standalone servers. + +With Nitro v3, we took the opportunity to rethink the fundamentals. leaner APIs, Web standards, first-class [Rolldown](https://rolldown.rs/) and [Vite v8](https://vite.dev/) integration, and a better experience for both humans and agents (more on that later!) + +Since we quietly announced v3 [alpha.0](https://github.com/nitrojs/nitro/releases/tag/v3.0.1-alpha.0) (11 Oct 2025) at the first [Vite Conf](https://viteconf.amsterdam/), Nitro v3 has been adopted by many users ([~280k](https://npmtrends.com/nitro-vs-nitro-nightly) weekly downloads!) and refined through amazing contributions and feedback. including [Tanstack Start](https://tanstack.com/start/latest/docs/framework/react/guide/hosting#nitro), [Vercel Workflows](https://useworkflow.dev/docs/getting-started), and production apps like [T3Chat](https://t3.chat/). + +A huge thanks to the VoidZero (Vite and Rolldown), Nuxt ([v5 is coming!](#nuxt-v5)) and TanStack Start teams and every contributor who helped bring Nitro v3 to this milestone. ❤️ + +## Why Build Servers? + +We don't ship raw source files to the browser. We use build tools because they solve real problems: **HMR** for instant feedback, **code splitting** to load only what a route needs, **tree shaking** to eliminate dead code, and **minification** for smaller payloads. Tools like Webpack and then [Vite](https://vite.dev/) transformed frontend development from painful to productive. + +But frontend apps don't exist in isolation, they need APIs, databases, authentication, real-time data. They need a server. + +With the rise of serverless and edge computing, the server side now faces the same constraints the frontend solved years ago. **Cold starts** mean every millisecond of startup matters. **Memory limits** are strict — bloated dependencies can push you over. **Bundle size** directly impacts deploy speed and boot time. And your code needs to run everywhere: Node.js, Deno, Bun, Cloudflare Workers, Vercel, etc. Yet most server frameworks still ship unoptimized, unbundled code, assuming a long-running process where none of this matters. + +Nitro brings the build-tool philosophy to the backend. The same great DX you expect from frontend tooling: HMR for fast iteration and optimized builds powered by Rolldown with tree-shaken production output that performs as close to bare-metal as possible. **One codebase, any runtime, any platform.** + +## ⚡ First-Class Vite Integration + +Nitro now has a native [Vite](https://vite.dev) plugin to build full stack apps. + +```ts [vite.config.ts] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ + plugins: [nitro()], +}); +``` + +Adding `nitro()` to your Vite apps gives you: + +- **API routes** via filesystem routing +- **Server-side rendering** integrated with your frontend build +- **A production server** — a single `vite build` produces an optimized `.output/` folder with both frontend and backend, ready to deploy + +This means you can add a full backend to any Vite project — See [examples](/examples) with [React](/examples/vite-ssr-react), [Vue](/examples/vite-ssr-vue-router) and [Solid.js](/examples/vite-ssr-solid). + +## 🚀 Performance by Default, Zero Bloat + +Nitro compiles your routes at build time. There is no runtime router — each route loads on demand. Only the code needed to handle a specific request is loaded and executed. + +Minimal server bundle built with the `standard` preset is less than `10kB`, can be served with [srvx](https://srvx.h3.dev/) at close to native speeds, and includes all the good features from [H3](https://h3.dev/). + +We have also significantly reduced the number of dependencies, down to [less than 20](https://npmgraph.js.org/?q=nitro-nightly) from [321 dependencies](https://npmgraph.js.org/?q=nitropack). + +## 🖌️ New Identity: `nitro` + +Nitro v3 ships under a new NPM package: [`nitro`](https://npmx.dev/package/nitro), replacing the legacy `nitropack`. + +All imports now use clean `nitro/*` subpaths: + +```ts +import { defineNitroConfig } from "nitro/config"; +import { defineHandler } from "nitro"; +import { useStorage } from "nitro/storage"; +import { useDatabase } from "nitro/database"; +``` + +No more deep `nitropack/runtime/*` paths, plus, you can import nitro subpaths outside of builder useful for unit testing. + +## 🔧 Bring Your Own Framework + +Nitro v3 is not opinionated about your HTTP layer. You can use the built-in filesystem routing, or take full control with a `server.ts` entry file and bring any framework you prefer: + +```ts [server.ts] +import { Hono } from "hono"; + +const app = new Hono(); +app.get("/", (c) => c.text("Hello from Hono!")); + +export default app; +``` + +## 🌐 H3 (v2) with Web Standards + +Nitro v3 upgrades to [H3 v2](https://h3.dev), which has been fully rewritten around web standard primitives — [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request), [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response), [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers), and [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL). + +The result is cleaner, more portable server code: + +```ts [routes/hello.ts] +import { defineHandler } from "nitro"; + +export default defineHandler((event) => { + const ua = event.req.headers.get("user-agent"); + return { message: "Hello Nitro v3!", ua }; +}); +``` + +Reading request bodies uses native APIs: + +```ts [routes/submit.ts] +import { defineHandler } from "nitro"; + +export default defineHandler(async (event) => { + const body = await event.req.json(); + return { received: body }; +}); +``` + +No wrappers, no abstractions for things the platform already provides. If you know the Web API, you know H3 v2. + +[Elysia](https://elysiajs.com/), [h3](https://h3.dev), [Hono](https://hono.dev) — anything that speaks web standards works with Nitro. + +## 🗄️ Built-in Primitives + +Nitro ships with powerful but small and **fully opt-in** agnostic server primitives that work across every runtime. + +::note +When not used, nothing extra will be added to the server bundle. You can still use native platform primitives alongside Nitro's built-in ones. +We are also bringing first class emulation for platform-specific primitives for dev See [env-runner](https://github.com/unjs/env-runner) and [nitrojs/nitro#4088](https://github.com/nitrojs/nitro/pull/4088) for more details. +:: + +### Storage + +A runtime-agnostic key-value layer with 20+ drivers — FS, Redis, S3, Cloudflare KV, Vercel Blob and [more](https://unstorage.unjs.io/drivers). Attach drivers to namespaces and swap them without changing your application code. + +```ts +import { useStorage } from "nitro/storage"; + +const storage = useStorage(); +await storage.setItem("user:1", { name: "Nitro" }); +``` + +:read-more{to="/docs/storage"} + +### Caching + +Cache server routes and functions, backed by the storage layer. Supports stale-while-revalidate, TTL, and custom cache keys out of the box. + +```ts +import { defineCachedHandler } from "nitro/cache"; + +export default defineCachedHandler((event) => { + return "I am cached for an hour"; +}, { maxAge: 60 * 60 }); +``` + +:read-more{to="/docs/cache"} + +### Database + +A built-in SQL database that defaults to SQLite for development and can connect to Postgres, MySQL, and [more](https://db0.unjs.io/connectors) using the same API. + +```ts +import { useDatabase } from "nitro/database"; + +const db = useDatabase(); +const users = await db.sql`SELECT * FROM users`; +``` + +:read-more{to="/docs/database"} + +## 🌍 Deploy Anywhere + +Build your server into an optimized `.output/` folder compatible with: + +- **Runtimes**: Node.js, Bun, Deno +- **Platforms**: Cloudflare Workers, Netlify, Vercel, AWS Lambda, Azure, Firebase, Deno Deploy, and more + +No configuration needed — Nitro auto-detects your deployment target. Take advantage of platform features like ISR, SWR, and edge rendering without changing a single line of code. + +## 🎨 Server-Side Rendering + +Render HTML with your favorite templating engine, or use component libraries like React, Vue, or Svelte directly on the server. Go full universal rendering with client-side hydration. + +Nitro provides the foundation and a progressive approach — start with API routes, add rendering when you need it, and scale to full SSR at your own pace. + +:read-more{to="/docs/renderer"} + +## 🟢 Nuxt v5 + +Nitro v3 will power the next major version of [Nuxt](https://nuxt.com). + +[Nuxt v5](https://nuxt.com/blog/roadmap-v4) will ship with Nitro v3 and H3 v2 at its core, bringing web-standard request handling, Rolldown-powered builds, and the Vite Environment API to the Nuxt ecosystem. + +If you're a Nuxt user, you can already start preparing by familiarizing yourself with Nitro v3's new APIs, which will carry directly into Nuxt 5, and you can [follow progress](https://github.com/nuxt/nuxt/discussions/34504) on adopting Nitro v3 in Nuxt + +## 🏁 Getting Started + +### Create a New Project + +:pm-x{command="create-nitro-app"} + +See the [quick start guide](/docs/quick-start) for a full step-by-step walkthrough. + +## 🔄 Migrating from v2 + +Nitro v3 introduces intentional breaking changes to set a cleaner foundation. Here are the key ones: + +- `nitropack` → `nitro` (package rename) +- `nitropack/runtime/*` → `nitro/*` (clean subpath imports) +- `eventHandler` → `defineHandler` (H3 v2) +- `createError` → `HTTPError` (H3 v2) +- Web standard `event.req` headers and body APIs +- Node.js minimum version: **20** +- Preset renames and consolidation (e.g., `cloudflare` → `cloudflare_module`) + +For a complete list, see the [migration guide](/docs/migration). + +--- + +Thank you to everyone who has contributed to Nitro over the years. We can't wait to see what you build with the new Nitro! ❤️ + +- [GitHub](https://github.com/nitrojs/nitro) — Issues and discussions +- [Discord](https://discord.nitro.build) — Chat with the community diff --git a/docs/9.blog/index.md b/docs/9.blog/index.md new file mode 100644 index 0000000000..9304925deb --- /dev/null +++ b/docs/9.blog/index.md @@ -0,0 +1,3 @@ +# Blog + +Nitro blog posts. diff --git a/docs/bun.lockb b/docs/bun.lockb deleted file mode 100755 index b7962e7f4f..0000000000 Binary files a/docs/bun.lockb and /dev/null differ diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000000..74881fa6aa --- /dev/null +++ b/docs/index.md @@ -0,0 +1,245 @@ +--- +seo: + title: Build Full-Stack Servers + description: Nitro extends your Vite application with a production-ready server, compatible with any runtime. Add server routes to your application and deploy many hosting platform with a zero-config experience. +--- + +::u-page-hero +--- +orientation: horizontal +--- +::code-group + :::prose-pre + --- + filename: vite.config.ts + --- + ```ts + import { defineConfig } from 'vite' + import { nitro } from 'nitro/vite' + + export default defineConfig({ + plugins: [nitro()], + nitro: { + serverDir: "./server" + } + }) + ``` + ::: + :::prose-pre + --- + filename: nitro.config.ts + --- + ```ts + import { defineConfig } from 'nitro' + + export default defineConfig({ + preset: "node", + serverDir: "./server", + routeRules: { + "/api/**": { cache: true } + } + }) + ``` + ::: +:: + +:hero-background + +#title +Build [/Servers]{.text-primary} + +#description +Nitro extends your Vite application with a production-ready server, compatible with any runtime. Add server routes to your application and deploy many hosting platform with a zero-config experience. + +#links +:app-hero-links +:: + +::hero-features +--- +features: + - title: Fast + description: Enjoy the fast Vite 8 (rolldown powered) development experience with HMR on the server and optimized for production. + icon: i-lucide-zap + color: text-amber-500 + bgColor: bg-amber-500/10 + borderColor: "group-hover:border-amber-500/30" + - title: Agnostic + description: Deploy the same codebase to any deployment provider with zero config and locked-in. + icon: i-lucide-globe + color: text-sky-500 + bgColor: bg-sky-500/10 + borderColor: "group-hover:border-sky-500/30" + - title: Minimal + description: Nitro adds no overhead to runtime. Build your servers with any modern tool you like. + icon: i-lucide-feather + color: text-emerald-500 + bgColor: bg-emerald-500/10 + borderColor: "group-hover:border-emerald-500/30" +--- +:: + +::performance-showcase +--- +metrics: + - label: Bare metal perf + value: "~Native" + unit: RPS + description: Using compile router, and fast paths for request handling. + icon: i-lucide-gauge + color: text-emerald-500 + bgColor: bg-emerald-500/10 + barWidth: "95%" + barColor: bg-emerald-500 + - label: Minimum install Size + value: Tiny + unit: deps + description: Minimal dependencies. No bloated node_modules. + icon: i-lucide-package + color: text-sky-500 + bgColor: bg-sky-500/10 + barWidth: "15%" + barColor: bg-sky-500 + - label: Small and portable output + value: "‹ 10" + unit: kB + description: Standard server builds produce ultra-small output bundles. + icon: i-lucide-file-output + color: text-violet-500 + bgColor: bg-violet-500/10 + barWidth: "10%" + barColor: bg-violet-500 + - label: FAST builds + value: "‹ 1" + unit: sec + description: Cold production builds complete in seconds, not minutes. + icon: i-lucide-timer + color: text-amber-500 + bgColor: bg-amber-500/10 + barWidth: "12%" + barColor: bg-amber-500 +--- +:: + +::landing-features +#body + :::feature-card + --- + headline: Routing + link: /docs/routing + link-label: Routing docs + --- + #title + File-system routing + + #description + Create server routes in the routes/ folder and they are automatically registered. Or bring your own framework — H3, Hono, Elysia, Express — via a server.ts entry. + ::: + + :::feature-card + --- + headline: Versatile + link: /deploy + link-label: Explore deploy targets + --- + #title + Deploy everywhere + + #description + The same codebase deploys to Node.js, Cloudflare Workers, Deno, Bun, AWS Lambda, Vercel, Netlify, and more — zero config, no vendor lock-in. + ::: + + :::feature-card + --- + headline: Storage + link: /docs/storage + link-label: Storage docs + --- + #title + Universal storage + + #description + Built-in key-value storage abstraction powered by unstorage. Works with filesystem, Redis, Cloudflare KV, and more — same API everywhere. + ::: + + :::feature-card + --- + headline: Caching + link: /docs/cache + link-label: Caching docs + --- + #title + Built-in caching + + #description + Cache route handlers and arbitrary functions with a simple API. Supports multiple storage backends and stale-while-revalidate patterns. + ::: + + :::feature-card + --- + headline: Server Entry + link: /docs/server-entry + link-label: Server entry docs + --- + #title + Web standard server + + #description + Go full Web standard and pick the library of your choice. Use H3, Hono, Elysia, Express, or the raw fetch API — Nitro handles the rest. + ::: + + :::feature-card + --- + headline: Renderer + link: /docs/renderer + link-label: Renderer docs + --- + #title + Universal renderer + + #description + Use any frontend framework as your renderer. Nitro provides the server layer while your framework handles the UI. + ::: + + :::feature-card + --- + headline: Plugins + link: /docs/plugins + link-label: Plugins docs + --- + #title + Server plugins + + #description + Extend Nitro's runtime behavior with plugins. Hook into lifecycle events, register custom logic, and auto-load from the plugins/ directory. + ::: + + :::feature-card + --- + headline: Database + link: /docs/database + link-label: Database docs + --- + #title + Built-in database + + #description + Lightweight SQL database layer powered by db0. Pre-configured with SQLite out of the box, with support for PostgreSQL, MySQL, and Cloudflare D1. + ::: + + :::feature-card + --- + headline: Assets + link: /docs/assets + link-label: Assets docs + --- + #title + Static & server assets + + #description + Serve public assets directly to clients or bundle server assets for programmatic access. Works seamlessly across all deployment targets. + ::: +:: + + +::page-sponsors diff --git a/docs/package.json b/docs/package.json index 782b6581cc..92bd41f33f 100644 --- a/docs/package.json +++ b/docs/package.json @@ -5,6 +5,11 @@ "build": "undocs build" }, "devDependencies": { - "undocs": "^0.2.30" + "automd": "^0.4.3", + "geist": "^1.7.0", + "motion-v": "^2.0.0", + "shaders": "^2.3.75", + "undocs": "npm:undocs-nightly@0.4.17-20260310-213525-c3c295a", + "zod": "^4.3.6" } } diff --git a/docs/pnpm-lock.yaml b/docs/pnpm-lock.yaml new file mode 100644 index 0000000000..4338d4045f --- /dev/null +++ b/docs/pnpm-lock.yaml @@ -0,0 +1,12519 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + automd: + specifier: ^0.4.3 + version: 0.4.3(magicast@0.5.2) + geist: + specifier: ^1.7.0 + version: 1.7.0(next@16.1.6(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + motion-v: + specifier: ^2.0.0 + version: 2.0.0(@vueuse/core@14.2.1(vue@3.5.30(typescript@5.9.3)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vue@3.5.30(typescript@5.9.3)) + shaders: + specifier: ^2.3.75 + version: 2.3.75(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vue@3.5.30(typescript@5.9.3)) + undocs: + specifier: npm:undocs-nightly@0.4.17-20260310-213525-c3c295a + version: undocs-nightly@0.4.17-20260310-213525-c3c295a(@parcel/watcher@2.5.6)(@tiptap/extensions@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))(@tiptap/y-tiptap@3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29))(@vue/compiler-sfc@3.5.30)(@vueuse/core@14.2.1(vue@3.5.30(typescript@5.9.3)))(cac@6.7.14)(chokidar@5.0.0)(db0@0.3.4)(dotenv@17.3.1)(embla-carousel@8.6.0)(giget@3.1.2)(ioredis@5.10.0)(jiti@2.6.1)(lightningcss@1.32.0)(magicast@0.5.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2))(vue-router@4.6.4(vue@3.5.30(typescript@5.9.3)))(yaml@2.8.2)(yjs@13.6.29)(zod@4.3.6) + zod: + specifier: ^4.3.6 + version: 4.3.6 + +packages: + + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + '@antfu/install-pkg@1.1.0': + resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} + + '@apidevtools/json-schema-ref-parser@11.9.3': + resolution: {integrity: sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ==} + engines: {node: '>= 16'} + + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.0': + resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-annotate-as-pure@7.27.3': + resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.28.6': + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-create-class-features-plugin@7.28.6': + resolution: {integrity: sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-member-expression-to-functions@7.28.5': + resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-optimise-call-expression@7.27.1': + resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-plugin-utils@7.28.6': + resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} + engines: {node: '>=6.9.0'} + + '@babel/helper-replace-supers@7.28.6': + resolution: {integrity: sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.28.6': + resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.0': + resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-syntax-jsx@7.28.6': + resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.28.6': + resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-typescript@7.28.6': + resolution: {integrity: sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/runtime@7.28.6': + resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} + + '@bomb.sh/tab@0.0.12': + resolution: {integrity: sha512-dYRwg4MqfHR5/BcTy285XOGRhjQFmNpaJBZ0tl2oU+RY595MQ5ApTF6j3OvauPAooHL6cfoOZMySQrOQztT8RQ==} + hasBin: true + peerDependencies: + cac: ^6.7.14 + citty: ^0.1.6 + commander: ^13.1.0 + peerDependenciesMeta: + cac: + optional: true + citty: + optional: true + commander: + optional: true + + '@braintree/sanitize-url@7.1.2': + resolution: {integrity: sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==} + + '@capsizecss/unpack@4.0.0': + resolution: {integrity: sha512-VERIM64vtTP1C4mxQ5thVT9fK0apjPFobqybMtA1UdUujWka24ERHbRHFGmpbbhp73MhV+KSsHQH9C6uOTdEQA==} + engines: {node: '>=18'} + + '@chevrotain/cst-dts-gen@11.1.2': + resolution: {integrity: sha512-XTsjvDVB5nDZBQB8o0o/0ozNelQtn2KrUVteIHSlPd2VAV2utEb6JzyCJaJ8tGxACR4RiBNWy5uYUHX2eji88Q==} + + '@chevrotain/gast@11.1.2': + resolution: {integrity: sha512-Z9zfXR5jNZb1Hlsd/p+4XWeUFugrHirq36bKzPWDSIacV+GPSVXdk+ahVWZTwjhNwofAWg/sZg58fyucKSQx5g==} + + '@chevrotain/regexp-to-ast@11.1.2': + resolution: {integrity: sha512-nMU3Uj8naWer7xpZTYJdxbAs6RIv/dxYzkYU8GSwgUtcAAlzjcPfX1w+RKRcYG8POlzMeayOQ/znfwxEGo5ulw==} + + '@chevrotain/types@11.1.2': + resolution: {integrity: sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==} + + '@chevrotain/utils@11.1.2': + resolution: {integrity: sha512-4mudFAQ6H+MqBTfqLmU7G1ZwRzCLfJEooL/fsF6rCX5eePMbGhoy5n4g+G4vlh2muDcsCTJtL+uKbOzWxs5LHA==} + + '@clack/core@1.1.0': + resolution: {integrity: sha512-SVcm4Dqm2ukn64/8Gub2wnlA5nS2iWJyCkdNHcvNHPIeBTGojpdJ+9cZKwLfmqy7irD4N5qLteSilJlE0WLAtA==} + + '@clack/prompts@1.1.0': + resolution: {integrity: sha512-pkqbPGtohJAvm4Dphs2M8xE29ggupihHdy1x84HNojZuMtFsHiUlRvqD24tM2+XmI+61LlfNceM3Wr7U5QES5g==} + + '@cloudflare/kv-asset-handler@0.4.2': + resolution: {integrity: sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ==} + engines: {node: '>=18.0.0'} + + '@dxup/nuxt@0.3.2': + resolution: {integrity: sha512-2f2usP4oLNsIGjPprvABe3f3GWuIhIDp0169pGLFxTDRI5A4d4sBbGpR+tD9bGZCT+1Btb6Q2GKlyv3LkDCW5g==} + + '@dxup/unimport@0.1.2': + resolution: {integrity: sha512-/B8YJGPzaYq1NbsQmwgP8EZqg40NpTw4ZB3suuI0TplbxKHeK94jeaawLmVhCv+YwUnOpiWEz9U6SeThku/8JQ==} + + '@emnapi/core@1.8.1': + resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} + + '@emnapi/runtime@1.8.1': + resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} + + '@emnapi/wasi-threads@1.1.0': + resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + + '@esbuild/aix-ppc64@0.27.3': + resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.27.3': + resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.27.3': + resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.27.3': + resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.27.3': + resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.3': + resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.27.3': + resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.3': + resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.27.3': + resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.27.3': + resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.27.3': + resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.27.3': + resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.27.3': + resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.27.3': + resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.3': + resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.27.3': + resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.27.3': + resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.27.3': + resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.3': + resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.27.3': + resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.3': + resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.3': + resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.27.3': + resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.27.3': + resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.27.3': + resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.27.3': + resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@floating-ui/core@1.7.5': + resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} + + '@floating-ui/dom@1.7.6': + resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} + + '@floating-ui/utils@0.2.11': + resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} + + '@floating-ui/vue@1.1.11': + resolution: {integrity: sha512-HzHKCNVxnGS35r9fCHBc3+uCnjw9IWIlCPL683cGgM9Kgj2BiAl8x1mS7vtvP6F9S/e/q4O6MApwSHj8hNLGfw==} + + '@headlessui/vue@1.7.23': + resolution: {integrity: sha512-JzdCNqurrtuu0YW6QaDtR2PIYCKPUWq28csDyMvN4zmGccmE7lz40Is6hc3LA4HFeCI7sekZ/PQMTNmn9I/4Wg==} + engines: {node: '>=10'} + peerDependencies: + vue: ^3.2.0 + + '@iconify/collections@1.0.659': + resolution: {integrity: sha512-gD9i7zfQpr3ZAv1BywaEri8o008KQT9iYaMw5EY4Y/y0qeEZB12FJMMyJGS3NvSeG80udu4kx8aZZLRsAdcANw==} + + '@iconify/types@2.0.0': + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + + '@iconify/utils@3.1.0': + resolution: {integrity: sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==} + + '@iconify/vue@5.0.0': + resolution: {integrity: sha512-C+KuEWIF5nSBrobFJhT//JS87OZ++QDORB6f2q2Wm6fl2mueSTpFBeBsveK0KW9hWiZ4mNiPjsh6Zs4jjdROSg==} + peerDependencies: + vue: '>=3' + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@internationalized/date@3.12.0': + resolution: {integrity: sha512-/PyIMzK29jtXaGU23qTvNZxvBXRtKbNnGDFD+PY6CZw/Y8Ex8pFUzkuCJCG9aOqmShjqhS9mPqP6Dk5onQY8rQ==} + + '@internationalized/number@3.6.5': + resolution: {integrity: sha512-6hY4Kl4HPBvtfS62asS/R22JzNNy8vi/Ssev7x6EobfCp+9QIB2hKvI2EtbdJ0VSQacxVNtqhE/NmF/NZ0gm6g==} + + '@ioredis/commands@1.5.1': + resolution: {integrity: sha512-JH8ZL/ywcJyR9MmJ5BNqZllXNZQqQbnVZOqpPQqE1vHiFgAw4NHbvE0FOduNU8IX9babitBT46571OnPTT0Zcw==} + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@jsdevtools/ono@7.1.3': + resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} + + '@kwsites/file-exists@1.1.1': + resolution: {integrity: sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==} + + '@kwsites/promise-deferred@1.1.1': + resolution: {integrity: sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==} + + '@mapbox/node-pre-gyp@2.0.3': + resolution: {integrity: sha512-uwPAhccfFJlsfCxMYTwOdVfOz3xqyj8xYL3zJj8f0pb30tLohnnFPhLuqp4/qoEz8sNxe4SESZedcBojRefIzg==} + engines: {node: '>=18'} + hasBin: true + + '@mermaid-js/parser@1.0.1': + resolution: {integrity: sha512-opmV19kN1JsK0T6HhhokHpcVkqKpF+x2pPDKKM2ThHtZAB5F4PROopk0amuVYK5qMrIA4erzpNm8gmPNJgMDxQ==} + + '@napi-rs/wasm-runtime@1.1.1': + resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} + + '@next/env@16.1.6': + resolution: {integrity: sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==} + + '@next/swc-darwin-arm64@16.1.6': + resolution: {integrity: sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@next/swc-darwin-x64@16.1.6': + resolution: {integrity: sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@next/swc-linux-arm64-gnu@16.1.6': + resolution: {integrity: sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-arm64-musl@16.1.6': + resolution: {integrity: sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@next/swc-linux-x64-gnu@16.1.6': + resolution: {integrity: sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-x64-musl@16.1.6': + resolution: {integrity: sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@next/swc-win32-arm64-msvc@16.1.6': + resolution: {integrity: sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@next/swc-win32-x64-msvc@16.1.6': + resolution: {integrity: sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@nuxt/cli@3.33.1': + resolution: {integrity: sha512-/sCrcI0WemING9zASaXPgPDY7PrQTPlRyCXlSgGx8VwRAkWbxGaPhIc3kZQikgLwVAwy+muWVV4Wks8OTtW5Tw==} + engines: {node: ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + '@nuxt/schema': ^4.3.0 + peerDependenciesMeta: + '@nuxt/schema': + optional: true + + '@nuxt/content@3.12.0': + resolution: {integrity: sha512-Uh1HuAOAFZVdnBSLarqJAsvx6OduD8bOGh35llnE0iM/JHZUJc4N4POB5yVADAx7lXzlFyoNlTdmCAglJrbE9Q==} + engines: {node: '>= 20.19.0'} + peerDependencies: + '@electric-sql/pglite': '*' + '@libsql/client': '*' + '@valibot/to-json-schema': ^1.5.0 + better-sqlite3: ^12.5.0 + sqlite3: '*' + valibot: ^1.2.0 + peerDependenciesMeta: + '@electric-sql/pglite': + optional: true + '@libsql/client': + optional: true + '@valibot/to-json-schema': + optional: true + better-sqlite3: + optional: true + sqlite3: + optional: true + valibot: + optional: true + + '@nuxt/devalue@2.0.2': + resolution: {integrity: sha512-GBzP8zOc7CGWyFQS6dv1lQz8VVpz5C2yRszbXufwG/9zhStTIH50EtD87NmWbTMwXDvZLNg8GIpb1UFdH93JCA==} + + '@nuxt/devtools-kit@3.2.3': + resolution: {integrity: sha512-5zj7Xx5CDI6P84kMalXoxGLd470buF6ncsRhiEPq8UlwdpVeR7bwi8QnparZNFBdG79bZ5KUkfi5YDXpLYPoIA==} + peerDependencies: + vite: '>=6.0' + + '@nuxt/devtools-wizard@3.2.3': + resolution: {integrity: sha512-VXSxWlv476Mhg2RkWMkjslOXcbf0trsp/FDHZTjg9nPDGROGV88xNuvgIF4eClP7zesjETOUow0te6s8504w9A==} + hasBin: true + + '@nuxt/devtools@3.2.3': + resolution: {integrity: sha512-UfbCHJDQ2DK0D787G6/QhuS2aYCDFTKMgtvE6OBBM1qYpR6pYEu5LRClQr9TFN4TIqJvgluQormGcYr1lsTKTw==} + hasBin: true + peerDependencies: + '@vitejs/devtools': '*' + vite: '>=6.0' + peerDependenciesMeta: + '@vitejs/devtools': + optional: true + + '@nuxt/fonts@0.14.0': + resolution: {integrity: sha512-4uXQl9fa5F4ibdgU8zomoOcyMdnwgdem+Pi8JEqeDYI5yPR32Kam6HnuRr47dTb97CstaepAvXPWQUUHMtjsFQ==} + + '@nuxt/icon@2.2.1': + resolution: {integrity: sha512-GI840yYGuvHI0BGDQ63d6rAxGzG96jQcWrnaWIQKlyQo/7sx9PjXkSHckXUXyX1MCr9zY6U25Td6OatfY6Hklw==} + + '@nuxt/kit@3.21.1': + resolution: {integrity: sha512-QORZRjcuTKgo++XP1Pc2c2gqwRydkaExrIRfRI9vFsPA3AzuHVn5Gfmbv1ic8y34e78mr5DMBvJlelUaeOuajg==} + engines: {node: '>=18.12.0'} + + '@nuxt/kit@4.3.1': + resolution: {integrity: sha512-UjBFt72dnpc+83BV3OIbCT0YHLevJtgJCHpxMX0YRKWLDhhbcDdUse87GtsQBrjvOzK7WUNUYLDS/hQLYev5rA==} + engines: {node: '>=18.12.0'} + + '@nuxt/nitro-server@4.3.1': + resolution: {integrity: sha512-4aNiM69Re02gI1ywnDND0m6QdVKXhWzDdtvl/16veytdHZj3FSq57ZCwOClNJ7HQkEMqXgS+bi6S2HmJX+et+g==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + nuxt: ^4.3.1 + + '@nuxt/schema@4.3.1': + resolution: {integrity: sha512-S+wHJdYDuyk9I43Ej27y5BeWMZgi7R/UVql3b3qtT35d0fbpXW7fUenzhLRCCDC6O10sjguc6fcMcR9sMKvV8g==} + engines: {node: ^14.18.0 || >=16.10.0} + + '@nuxt/telemetry@2.7.0': + resolution: {integrity: sha512-mrKC3NjAlBOooLLVTYcIUie1meipoYq5vkoESoVTEWTB34T3a0QJzOfOPch+HYlUR+5Lqy1zLMv6epHFgYAKLA==} + engines: {node: '>=18.12.0'} + hasBin: true + peerDependencies: + '@nuxt/kit': '>=3.0.0' + + '@nuxt/ui@4.5.1': + resolution: {integrity: sha512-5hWgreVPX6EsNCZNoOd2o7m9fTA3fwUMDw+zeYTSAjhSKtAuvkZrBtmez4MUeTv+LO1gknesgvErdIvlUnElTg==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@inertiajs/vue3': ^2.0.7 + '@nuxt/content': ^3.0.0 + joi: ^18.0.0 + superstruct: ^2.0.0 + tailwindcss: ^4.0.0 + typescript: ^5.9.3 + valibot: ^1.0.0 + vue-router: ^4.5.0 + yup: ^1.7.0 + zod: ^3.24.0 || ^4.0.0 + peerDependenciesMeta: + '@inertiajs/vue3': + optional: true + '@nuxt/content': + optional: true + joi: + optional: true + superstruct: + optional: true + valibot: + optional: true + vue-router: + optional: true + yup: + optional: true + zod: + optional: true + + '@nuxt/vite-builder@4.3.1': + resolution: {integrity: sha512-LndnxPJzDUDbWAB8q5gZZN1mSOLHEyMOoj4T3pTdPydGf31QZdMR0V1fQ1fdRgtgNtWB3WLP0d1ZfaAOITsUpw==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + nuxt: 4.3.1 + rolldown: ^1.0.0-beta.38 + vue: ^3.3.4 + peerDependenciesMeta: + rolldown: + optional: true + + '@nuxtjs/color-mode@3.5.2': + resolution: {integrity: sha512-cC6RfgZh3guHBMLLjrBB2Uti5eUoGM9KyauOaYS9ETmxNWBMTvpgjvSiSJp1OFljIXPIqVTJ3xtJpSNZiO3ZaA==} + + '@nuxtjs/mdc@0.20.2': + resolution: {integrity: sha512-afAJKnXKdvDtoNOGARQMpZoGprL1T3OGnj+K9edJjX+WdhCwvVabBijhi8BAlpx+YzA/DpcZx8bDFZk/aoSJmA==} + + '@nuxtjs/plausible@3.0.2': + resolution: {integrity: sha512-6z01a7XbggSmI4CTWCkDDmLHQNm7wob2dx1QnvpIoo+YEV19298+GsuvlBclXVxXSk7op8r8qJpw25xKo8mzQQ==} + + '@oxc-minify/binding-android-arm-eabi@0.112.0': + resolution: {integrity: sha512-m7TGBR2hjsBJIN9UJ909KBoKsuogo6CuLsHKvUIBXdjI0JVHP8g4ZHeB+BJpGn5LJdeSGDfz9MWiuXrZDRzunw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@oxc-minify/binding-android-arm64@0.112.0': + resolution: {integrity: sha512-RvxOOkzvP5NeeoraBtgNJSBqO+XzlS7DooxST/drAXCfO52GsmxVB1N7QmifrsTYtH8GC2z3DTFjZQ1w/AJOWg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@oxc-minify/binding-darwin-arm64@0.112.0': + resolution: {integrity: sha512-hDslO3uVHza3kB9zkcsi25JzN65Gj5ZYty0OvylS11Mhg9ydCYxAzfQ/tISHW/YmV1NRUJX8+GGqM1cKmrHaTA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@oxc-minify/binding-darwin-x64@0.112.0': + resolution: {integrity: sha512-mWA2Y5bUyNoGM+gSGGHesgtQ3LDWgpRe4zDGkBDovxNIiDLBXqu/7QcuS+G918w8oG9VYm1q1iinILer/2pD1Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@oxc-minify/binding-freebsd-x64@0.112.0': + resolution: {integrity: sha512-T7fsegxcy82xS0jWPXkz/BMhrkb3D7YOCiV0R9pDksjaov+iIFoNEWAoBsaC5NtpdzkX+bmffwDpu336EIfEeg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@oxc-minify/binding-linux-arm-gnueabihf@0.112.0': + resolution: {integrity: sha512-yePavbIilAcpVYc8vRsDCn3xJxHMXDZIiamyH9fuLosAHNELcLib4/JR4fhDk4NmHVagQH3kRhsnm5Q9cm3pAw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxc-minify/binding-linux-arm-musleabihf@0.112.0': + resolution: {integrity: sha512-lmPWLXtW6FspERhy97iP0hwbmLtL66xI29QQ9GpHmTiE4k+zv/FaefuV/Qw+LuHnmFSYzUNrLcxh4ulOZTIP2g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxc-minify/binding-linux-arm64-gnu@0.112.0': + resolution: {integrity: sha512-gySS5XqU5MKs/oCjsTlVm8zb8lqcNKHEANsaRmhW2qvGKJoeGwFb6Fbq6TLCZMRuk143mLbncbverBCa1c3dog==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@oxc-minify/binding-linux-arm64-musl@0.112.0': + resolution: {integrity: sha512-IRFMZX589lr3rjG0jc8N261/7wqFq2Vl0OMrJWeFls5BF8HiB+fRYuf0Zy2CyRH6NCY2vbdDdp+QCAavQGVsGw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@oxc-minify/binding-linux-ppc64-gnu@0.112.0': + resolution: {integrity: sha512-V/69XqIW9hCUceDpcZh79oDg+F4ptEgIfKRENzYs41LRbSoJ7sNjjcW4zifqyviTvzcnXLgK4uoTyoymmNZBMQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@oxc-minify/binding-linux-riscv64-gnu@0.112.0': + resolution: {integrity: sha512-zghvexySyGXGNW+MutjZN7UGTyOQl56RWMlPe1gb+knBm/+0hf9qjk7Q6ofm2tSte+vQolPfQttifGl0dP9uvQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@oxc-minify/binding-linux-riscv64-musl@0.112.0': + resolution: {integrity: sha512-E4a8VUFDJPb2mPcc7J4NQQPi1ssHKF7/g4r6KD2+SBVERIaEEd3cGNqR7SG3g82/BLGV2UDoQe/WvZCkt5M/bQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@oxc-minify/binding-linux-s390x-gnu@0.112.0': + resolution: {integrity: sha512-2Hx87sK3y6jBV364Mvv0zyxiITIuy26Ixenv6pK7e+4an3HgNdhAj8nk3aLoLTTSvLik5/MaGhcZGEu9tYV1aA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@oxc-minify/binding-linux-x64-gnu@0.112.0': + resolution: {integrity: sha512-2MSCnEPLk9ddSouMhJo78Xy2/JbYC80OYzWdR4yWTGSULsgH3d1VXg73DSwFL8vU7Ad9oK10DioBY2ww7sQTEg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@oxc-minify/binding-linux-x64-musl@0.112.0': + resolution: {integrity: sha512-HAPfmQKlkVi97/zRonVE9t/kKUG3ni+mOuU1Euw+3s37KwUuOJjmcwXdclVgXKBlTkCGO0FajPwW5dAJeIXCCw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@oxc-minify/binding-openharmony-arm64@0.112.0': + resolution: {integrity: sha512-bLnMojcPadYzMNpB6IAqMiTOag4etc0zbs8On73JsotO1W5c5/j/ncplpSokpEpNasKRUpHVRXpmq0KRXprNhw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@oxc-minify/binding-wasm32-wasi@0.112.0': + resolution: {integrity: sha512-tv7PmHYq/8QBlqMaDjsy51GF5KQkG17Yc/PsgB5OVndU34kwbQuebBIic7UfK9ygzidI8moYq3ztnu3za/rqHw==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@oxc-minify/binding-win32-arm64-msvc@0.112.0': + resolution: {integrity: sha512-d+jes2jwRkcBSpcaZC6cL8GBi56Br6uAorn9dfquhWLczWL+hHSvvVrRgT1i5/6dkf5UWx2zdoEsAMiJ11w78A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@oxc-minify/binding-win32-ia32-msvc@0.112.0': + resolution: {integrity: sha512-TV1C3qDwj7//jNIi5tnNRhReSUgtaRQKi5KobDE6zVAc5gjeuBA8G2qizS9ziXlf/I0dlelrGmGMMDJmH9ekWg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] + + '@oxc-minify/binding-win32-x64-msvc@0.112.0': + resolution: {integrity: sha512-LML2Gld6VY8/+7a3VH4k1qngsBXvTkXgbmYgSYwaElqtiQiYaAcXfi0XKOUGe3k3GbBK4juAGixC31CrdFHAQw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@oxc-parser/binding-android-arm-eabi@0.112.0': + resolution: {integrity: sha512-retxBzJ39Da7Lh/eZTn9+HJgTeDUxZIpuI0urOsmcFsBKXAth3lc1jIvwseQ9qbAI/VrsoFOXiGIzgclARbAHg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@oxc-parser/binding-android-arm64@0.112.0': + resolution: {integrity: sha512-pRkbBRbuIIsufUWpOJ+JHWfJFNupkidy4sbjfcm37e6xwYrn9LSKMLubPHvNaL1Zf92ZRhGiwaYkEcmaFg2VcA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@oxc-parser/binding-darwin-arm64@0.112.0': + resolution: {integrity: sha512-fh6/KQL/cbH5DukT3VkdCqnULLuvVnszVKySD5IgSE0WZb32YZo/cPsPdEv052kk6w3N4agu+NTiMnZjcvhUIg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@oxc-parser/binding-darwin-x64@0.112.0': + resolution: {integrity: sha512-vUBOOY1E30vlu/DoTGDoT1UbLlwu5Yv9tqeBabAwRzwNDz8Skho16VKhsBDUiyqddtpsR3//v6vNk38w4c+6IA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@oxc-parser/binding-freebsd-x64@0.112.0': + resolution: {integrity: sha512-hnEtO/9AVnYWzrgnp6L+oPs/6UqlFeteUL6n7magkd2tttgmx1C01hyNNh6nTpZfLzEVJSNJ0S+4NTsK2q2CxA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@oxc-parser/binding-linux-arm-gnueabihf@0.112.0': + resolution: {integrity: sha512-WxJrUz3pcIc2hp4lvJbvt/sTL33oX9NPvkD3vDDybE6tc0V++rS+hNOJxwXdD2FDIFPkHs/IEn5asEZFVH+VKw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxc-parser/binding-linux-arm-musleabihf@0.112.0': + resolution: {integrity: sha512-jj8A8WWySaJQqM9XKAIG8U2Q3qxhFQKrXPWv98d1oC35at+L1h+C+V4M3l8BAKhpHKCu3dYlloaAbHd5q1Hw6A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxc-parser/binding-linux-arm64-gnu@0.112.0': + resolution: {integrity: sha512-G2F8H6FcAExVK5vvhpSh61tqWx5QoaXXUnSsj5FyuDiFT/K7AMMVSQVqnZREDc+YxhrjB0vnKjCcuobXK63kIw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@oxc-parser/binding-linux-arm64-musl@0.112.0': + resolution: {integrity: sha512-3R0iqjM3xYOZCnwgcxOQXH7hrz64/USDIuLbNTM1kZqQzRqaR4w7SwoWKU934zABo8d0op2oSwOp+CV3hZnM7A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@oxc-parser/binding-linux-ppc64-gnu@0.112.0': + resolution: {integrity: sha512-lAQf8PQxfgy7h0bmcfSVE3hg3qMueshPYULFsCrHM+8KefGZ9W+ZMvRyU33gLrB4w1O3Fz1orR0hmKMCRxXNrQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@oxc-parser/binding-linux-riscv64-gnu@0.112.0': + resolution: {integrity: sha512-2QlvQBUhHuAE3ezD4X3CAEKMXdfgInggQ5Bj/7gb5NcYP3GyfLTj7c+mMu+BRwfC9B3AXBNyqHWbqEuuUvZyRQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@oxc-parser/binding-linux-riscv64-musl@0.112.0': + resolution: {integrity: sha512-v06iu0osHszgqJ1dLQRb6leWFU1sjG/UQk4MoVBtE6ZPewgfTkby6G9II1SpEAf2onnAuQceVYxQH9iuU3NJqw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@oxc-parser/binding-linux-s390x-gnu@0.112.0': + resolution: {integrity: sha512-+5HhNHtxsdcd7+ljXFnn9FOoCNXJX3UPgIfIE6vdwS1HqdGNH6eAcVobuqGOp54l8pvcxDQA6F4cPswCgLrQfQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@oxc-parser/binding-linux-x64-gnu@0.112.0': + resolution: {integrity: sha512-jKwO7ZLNkjxwg7FoCLw+fJszooL9yXRZsDN0AQ1AQUTWq1l8GH/2e44k68N3fcP19jl8O8jGpqLAZcQTYk6skA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@oxc-parser/binding-linux-x64-musl@0.112.0': + resolution: {integrity: sha512-TYqnuKV/p3eOc+N61E0961nA7DC+gaCeJ3+V2LcjJdTwFMdikqWL6uVk1jlrpUCBrozHDATVUKDZYH7r4FQYjQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@oxc-parser/binding-openharmony-arm64@0.112.0': + resolution: {integrity: sha512-ZhrVmWFifVEFQX4XPwLoVFDHw9tAWH9p9vHsHFH+5uCKdfVR+jje4WxVo6YrokWCboGckoOzHq5KKMOcPZfkRg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@oxc-parser/binding-wasm32-wasi@0.112.0': + resolution: {integrity: sha512-Gr8X2PUU3hX1g3F5oLWIZB8DhzDmjr5TfOrmn5tlBOo9l8ojPGdKjnIBfObM7X15928vza8QRKW25RTR7jfivg==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@oxc-parser/binding-win32-arm64-msvc@0.112.0': + resolution: {integrity: sha512-t5CDLbU70Ea88bGRhvU/dLJTc/Wcrtf2Jp534E8P3cgjAvHDjdKsfDDqBZrhybJ8Jv9v9vW5ngE40EK51BluDA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@oxc-parser/binding-win32-ia32-msvc@0.112.0': + resolution: {integrity: sha512-rZH0JynCCwnhe2HfRoyNOl/Kfd9pudoWxgpC5OZhj7j77pMK0UOAa35hYDfrtSOUk2HLzrikV5dPUOY2DpSBSA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] + + '@oxc-parser/binding-win32-x64-msvc@0.112.0': + resolution: {integrity: sha512-oGHluohzmVFAuQrkEnl1OXAxMz2aYmimxUqIgKXpBgbr7PvFv0doELB273sX+5V3fKeggohKg1A2Qq21W9Z9cQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@oxc-project/types@0.112.0': + resolution: {integrity: sha512-m6RebKHIRsax2iCwVpYW2ErQwa4ywHJrE4sCK3/8JK8ZZAWOKXaRJFl/uP51gaVyyXlaS4+chU1nSCdzYf6QqQ==} + + '@oxc-transform/binding-android-arm-eabi@0.112.0': + resolution: {integrity: sha512-r4LuBaPnOAi0eUOBNi880Fm2tO2omH7N1FRrL6+nyz/AjQ+QPPLtoyZJva0O+sKi1buyN/7IzM5p9m+5ANSDbg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@oxc-transform/binding-android-arm64@0.112.0': + resolution: {integrity: sha512-ve46vQcQrY8eGe8990VSlS9gkD+AogJqbtfOkeua+5sQGQTDgeIRRxOm7ktCo19uZc2bEBwXRJITgosd+NRVmQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@oxc-transform/binding-darwin-arm64@0.112.0': + resolution: {integrity: sha512-ddbmLU3Tr+i7MOynfwAXxUXud3SjJKlv7XNjaq08qiI8Av/QvhXVGc2bMhXkWQSMSBUeTDoiughKjK+Zsb6y/A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@oxc-transform/binding-darwin-x64@0.112.0': + resolution: {integrity: sha512-TKvmNw96jQZPqYb4pRrzLFDailNB3YS14KNn+x2hwRbqc6CqY96S9PYwyOpVpYdxfoRjYO9WgX9SoS+62a1DPA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@oxc-transform/binding-freebsd-x64@0.112.0': + resolution: {integrity: sha512-YPMkSCDaelO8HHYRMYjm+Q+IfkfIbdtQzwPuasItYkq8UUkNeHNPheNh2JkvQa3c+io3E9ePOgHQ2yihpk7o/Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@oxc-transform/binding-linux-arm-gnueabihf@0.112.0': + resolution: {integrity: sha512-nA7kzQGNEpuTRknst/IJ3l8hqmDmEda3aun6jkXgp7gKxESjuHeaNH04mKISxvJ7fIacvP2g/wtTSnm4u5jL8Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxc-transform/binding-linux-arm-musleabihf@0.112.0': + resolution: {integrity: sha512-w8GuLmckKlGc3YujaZKhtbFxziCcosvM2l9GnQjCb/yENWLGDiyQOy0BTAgPGdJwpYTiOeJblEXSuXYvlE1Ong==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxc-transform/binding-linux-arm64-gnu@0.112.0': + resolution: {integrity: sha512-9LwwGnJ8+WT0rXcrI8M0RJtDNt91eMqcDPPEvJxhRFHIMcHTy5D5xT+fOl3Us0yMqKo3HUWkbfUYqAp4GoZ3Jw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@oxc-transform/binding-linux-arm64-musl@0.112.0': + resolution: {integrity: sha512-Lg6VOuSd3oXv7J0eGywgqh/086h+qQzIBOD+47pYKMTTJcbDe+f3h/RgGoMKJE5HhiwT5sH1aGEJfIfaYUiVSw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@oxc-transform/binding-linux-ppc64-gnu@0.112.0': + resolution: {integrity: sha512-PXzmj82o1moA4IGphYImTRgc2youTi4VRfyFX3CHwLjxPcQ5JtcsgbDt4QUdOzXZ+zC07s5jf2ZzhRapEOlj2w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@oxc-transform/binding-linux-riscv64-gnu@0.112.0': + resolution: {integrity: sha512-vhJsMsVH/6xwa3bt1LGts33FXUkGjaEGDwsRyp4lIfOjSfQVWMtCmWMFNaA0dW9FVWdD2Gt2fSFBSZ+azDxlpg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@oxc-transform/binding-linux-riscv64-musl@0.112.0': + resolution: {integrity: sha512-cXWFb7z+2IjFUEcXtRwluq9oEG5qnyFCjiu3SWrgYNcWwPdHusv3I/7K5/CTbbi4StoZ5txbi7/iSfDHNyWuRw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@oxc-transform/binding-linux-s390x-gnu@0.112.0': + resolution: {integrity: sha512-eEFu4SRqJTJ20/88KRWmp+jpHKAw0Y1DsnSgpEeXyBIIcsOaLIUMU/TfYWUmqRbvbMV9rmOmI3kp5xWYUq6kSQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@oxc-transform/binding-linux-x64-gnu@0.112.0': + resolution: {integrity: sha512-ST1MDT+TlOyZ1c5btrGinRSUW2Jf4Pa+0gdKwsyjDSOC3dxy2ZNkN3mosTf4ywc3J+mxfYKqtjs7zSwHz03ILA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@oxc-transform/binding-linux-x64-musl@0.112.0': + resolution: {integrity: sha512-ISQoA3pD4cyTGpf9sXXeerH6pL2L6EIpdy6oAy2ttkswyVFDyQNVOVIGIdLZDgbpmqGljxZnWqt/J/N68pQaig==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@oxc-transform/binding-openharmony-arm64@0.112.0': + resolution: {integrity: sha512-UOGVrGIv7yLJovyEXEyUTADuLq98vd/cbMHFLJweRXD+11I8Tn4jASi4WzdsN8C3BVYGRHrXH2NlSBmhz33a4g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@oxc-transform/binding-wasm32-wasi@0.112.0': + resolution: {integrity: sha512-XIX7Gpq9koAvzBVHDlVFHM79r5uOVK6kTEsdsN4qaajpjkgtv4tdsAOKIYK6l7fUbsbE6xS+6w1+yRFrDeC1kg==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@oxc-transform/binding-win32-arm64-msvc@0.112.0': + resolution: {integrity: sha512-EgXef9kOne9BNsbYBbuRqxk2hteT0xsAGcx/VbtCBMJYNj8fANFhT271DUSOgfa4DAgrQQmsyt/Kr1aV9mpU9w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@oxc-transform/binding-win32-ia32-msvc@0.112.0': + resolution: {integrity: sha512-6QaB0qjNaou2YR+blncHdw7j0e26IOwOIjLbhVGDeuf9+4rjJeiqRXJ2hOtCcS4zblnao/MjdgQuZ3fM0nl+Kw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] + + '@oxc-transform/binding-win32-x64-msvc@0.112.0': + resolution: {integrity: sha512-FRKYlY959QeqRPx9kXs0HjU2xuXPT1cdF+vvA200D9uAX/KLcC34MwRqUKTYml4kCc2Vf/P2pBR9cQuBm3zECQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@parcel/watcher-android-arm64@2.5.6': + resolution: {integrity: sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] + + '@parcel/watcher-darwin-arm64@2.5.6': + resolution: {integrity: sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] + + '@parcel/watcher-darwin-x64@2.5.6': + resolution: {integrity: sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] + + '@parcel/watcher-freebsd-x64@2.5.6': + resolution: {integrity: sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] + + '@parcel/watcher-linux-arm-glibc@2.5.6': + resolution: {integrity: sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@parcel/watcher-linux-arm-musl@2.5.6': + resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + libc: [musl] + + '@parcel/watcher-linux-arm64-glibc@2.5.6': + resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@parcel/watcher-linux-arm64-musl@2.5.6': + resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@parcel/watcher-linux-x64-glibc@2.5.6': + resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@parcel/watcher-linux-x64-musl@2.5.6': + resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@parcel/watcher-wasm@2.5.6': + resolution: {integrity: sha512-byAiBZ1t3tXQvc8dMD/eoyE7lTXYorhn+6uVW5AC+JGI1KtJC/LvDche5cfUE+qiefH+Ybq0bUCJU0aB1cSHUA==} + engines: {node: '>= 10.0.0'} + bundledDependencies: + - napi-wasm + + '@parcel/watcher-win32-arm64@2.5.6': + resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] + + '@parcel/watcher-win32-ia32@2.5.6': + resolution: {integrity: sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==} + engines: {node: '>= 10.0.0'} + cpu: [ia32] + os: [win32] + + '@parcel/watcher-win32-x64@2.5.6': + resolution: {integrity: sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] + + '@parcel/watcher@2.5.6': + resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==} + engines: {node: '>= 10.0.0'} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@plausible-analytics/tracker@0.4.4': + resolution: {integrity: sha512-fz0NOYUEYXtg1TBaPEEvtcBq3FfmLFuTe1VZw4M8sTWX129br5dguu3M15+plOQnc181ShYe67RfwhKgK89VnA==} + + '@polka/url@1.0.0-next.29': + resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} + + '@poppinss/colors@4.1.6': + resolution: {integrity: sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==} + + '@poppinss/dumper@0.7.0': + resolution: {integrity: sha512-0UTYalzk2t6S4rA2uHOz5bSSW2CHdv4vggJI6Alg90yvl0UgXs6XSXpH96OH+bRkX4J/06djv29pqXJ0lq5Kag==} + + '@poppinss/exception@1.2.3': + resolution: {integrity: sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==} + + '@remirror/core-constants@3.0.0': + resolution: {integrity: sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==} + + '@resvg/resvg-wasm@2.6.2': + resolution: {integrity: sha512-FqALmHI8D4o6lk/LRWDnhw95z5eO+eAa6ORjVg09YRR7BkcM6oPHU9uyC0gtQG5vpFLvgpeU4+zEAz2H8APHNw==} + engines: {node: '>= 10'} + + '@rolldown/pluginutils@1.0.0-rc.2': + resolution: {integrity: sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==} + + '@rolldown/pluginutils@1.0.0-rc.8': + resolution: {integrity: sha512-wzJwL82/arVfeSP3BLr1oTy40XddjtEdrdgtJ4lLRBu06mP3q/8HGM6K0JRlQuTA3XB0pNJx2so/nmpY4xyOew==} + + '@rollup/plugin-alias@6.0.0': + resolution: {integrity: sha512-tPCzJOtS7uuVZd+xPhoy5W4vThe6KWXNmsFCNktaAh5RTqcLiSfT4huPQIXkgJ6YCOjJHvecOAzQxLFhPxKr+g==} + engines: {node: '>=20.19.0'} + peerDependencies: + rollup: '>=4.0.0' + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-commonjs@29.0.2': + resolution: {integrity: sha512-S/ggWH1LU7jTyi9DxZOKyxpVd4hF/OZ0JrEbeLjXk/DFXwRny0tjD2c992zOUYQobLrVkRVMDdmHP16HKP7GRg==} + engines: {node: '>=16.0.0 || 14 >= 14.17'} + peerDependencies: + rollup: ^2.68.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-inject@5.0.5': + resolution: {integrity: sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-json@6.1.0': + resolution: {integrity: sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-node-resolve@16.0.3': + resolution: {integrity: sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.78.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-replace@6.0.3': + resolution: {integrity: sha512-J4RZarRvQAm5IF0/LwUUg+obsm+xZhYnbMXmXROyoSE1ATJe3oXSb9L5MMppdxP2ylNSjv6zFBwKYjcKMucVfA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-terser@0.4.4': + resolution: {integrity: sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/pluginutils@5.3.0': + resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/rollup-android-arm-eabi@4.59.0': + resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.59.0': + resolution: {integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.59.0': + resolution: {integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.59.0': + resolution: {integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.59.0': + resolution: {integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.59.0': + resolution: {integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.59.0': + resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm-musleabihf@4.59.0': + resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-arm64-gnu@4.59.0': + resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.59.0': + resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loong64-gnu@4.59.0': + resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-loong64-musl@4.59.0': + resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-ppc64-gnu@4.59.0': + resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-ppc64-musl@4.59.0': + resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==} + cpu: [ppc64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-riscv64-gnu@4.59.0': + resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-musl@4.59.0': + resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-s390x-gnu@4.59.0': + resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.59.0': + resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.59.0': + resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-openbsd-x64@4.59.0': + resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.59.0': + resolution: {integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.59.0': + resolution: {integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.59.0': + resolution: {integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.59.0': + resolution: {integrity: sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.59.0': + resolution: {integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==} + cpu: [x64] + os: [win32] + + '@shikijs/core@3.23.0': + resolution: {integrity: sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==} + + '@shikijs/core@4.0.2': + resolution: {integrity: sha512-hxT0YF4ExEqB8G/qFdtJvpmHXBYJ2lWW7qTHDarVkIudPFE6iCIrqdgWxGn5s+ppkGXI0aEGlibI0PAyzP3zlw==} + engines: {node: '>=20'} + + '@shikijs/engine-javascript@3.23.0': + resolution: {integrity: sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA==} + + '@shikijs/engine-javascript@4.0.2': + resolution: {integrity: sha512-7PW0Nm49DcoUIQEXlJhNNBHyoGMjalRETTCcjMqEaMoJRLljy1Bi/EGV3/qLBgLKQejdspiiYuHGQW6dX94Nag==} + engines: {node: '>=20'} + + '@shikijs/engine-oniguruma@3.23.0': + resolution: {integrity: sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==} + + '@shikijs/engine-oniguruma@4.0.2': + resolution: {integrity: sha512-UpCB9Y2sUKlS9z8juFSKz7ZtysmeXCgnRF0dlhXBkmQnek7lAToPte8DkxmEYGNTMii72zU/lyXiCB6StuZeJg==} + engines: {node: '>=20'} + + '@shikijs/langs@3.23.0': + resolution: {integrity: sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==} + + '@shikijs/langs@4.0.2': + resolution: {integrity: sha512-KaXby5dvoeuZzN0rYQiPMjFoUrz4hgwIE+D6Du9owcHcl6/g16/yT5BQxSW5cGt2MZBz6Hl0YuRqf12omRfUUg==} + engines: {node: '>=20'} + + '@shikijs/primitive@4.0.2': + resolution: {integrity: sha512-M6UMPrSa3fN5ayeJwFVl9qWofl273wtK1VG8ySDZ1mQBfhCpdd8nEx7nPZ/tk7k+TYcpqBZzj/AnwxT9lO+HJw==} + engines: {node: '>=20'} + + '@shikijs/themes@3.23.0': + resolution: {integrity: sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==} + + '@shikijs/themes@4.0.2': + resolution: {integrity: sha512-mjCafwt8lJJaVSsQvNVrJumbnnj1RI8jbUKrPKgE6E3OvQKxnuRoBaYC51H4IGHePsGN/QtALglWBU7DoKDFnA==} + engines: {node: '>=20'} + + '@shikijs/transformers@3.23.0': + resolution: {integrity: sha512-F9msZVxdF+krQNSdQ4V+Ja5QemeAoTQ2jxt7nJCwhDsdF1JWS3KxIQXA3lQbyKwS3J61oHRUSv4jYWv3CkaKTQ==} + + '@shikijs/types@3.23.0': + resolution: {integrity: sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==} + + '@shikijs/types@4.0.2': + resolution: {integrity: sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg==} + engines: {node: '>=20'} + + '@shikijs/vscode-textmate@10.0.2': + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + + '@sindresorhus/is@4.6.0': + resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} + engines: {node: '>=10'} + + '@sindresorhus/is@7.2.0': + resolution: {integrity: sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==} + engines: {node: '>=18'} + + '@sindresorhus/merge-streams@4.0.0': + resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} + engines: {node: '>=18'} + + '@socket.io/component-emitter@3.1.2': + resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} + + '@speed-highlight/core@1.2.14': + resolution: {integrity: sha512-G4ewlBNhUtlLvrJTb88d2mdy2KRijzs4UhnlrOSRT4bmjh/IqNElZa3zkrZ+TC47TwtlDWzVLFADljF1Ijp5hA==} + + '@sqlite.org/sqlite-wasm@3.50.4-build1': + resolution: {integrity: sha512-Qig2Wso7gPkU1PtXwFzndh+CTRzrIFxVGqv6eCetjU7YqxlHItj+GvQYwYTppCRgAPawtRN/4AJcEgB9xDHGug==} + hasBin: true + + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + + '@swc/helpers@0.5.19': + resolution: {integrity: sha512-QamiFeIK3txNjgUTNppE6MiG3p7TdninpZu0E0PbqVh1a9FNLT2FRhisaa4NcaX52XVhA5l7Pk58Ft7Sqi/2sA==} + + '@tailwindcss/node@4.2.1': + resolution: {integrity: sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==} + + '@tailwindcss/oxide-android-arm64@4.2.1': + resolution: {integrity: sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.2.1': + resolution: {integrity: sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.2.1': + resolution: {integrity: sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.2.1': + resolution: {integrity: sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1': + resolution: {integrity: sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.2.1': + resolution: {integrity: sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-arm64-musl@4.2.1': + resolution: {integrity: sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-linux-x64-gnu@4.2.1': + resolution: {integrity: sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-x64-musl@4.2.1': + resolution: {integrity: sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-wasm32-wasi@4.2.1': + resolution: {integrity: sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.2.1': + resolution: {integrity: sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.2.1': + resolution: {integrity: sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.2.1': + resolution: {integrity: sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==} + engines: {node: '>= 20'} + + '@tailwindcss/postcss@4.2.1': + resolution: {integrity: sha512-OEwGIBnXnj7zJeonOh6ZG9woofIjGrd2BORfvE5p9USYKDCZoQmfqLcfNiRWoJlRWLdNPn2IgVZuWAOM4iTYMw==} + + '@tailwindcss/vite@4.2.1': + resolution: {integrity: sha512-TBf2sJjYeb28jD2U/OhwdW0bbOsxkWPwQ7SrqGf9sVcoYwZj7rkXljroBO9wKBut9XnmQLXanuDUeqQK0lGg/w==} + peerDependencies: + vite: ^5.2.0 || ^6 || ^7 + + '@tanstack/table-core@8.21.3': + resolution: {integrity: sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==} + engines: {node: '>=12'} + + '@tanstack/virtual-core@3.13.21': + resolution: {integrity: sha512-ww+fmLHyCbPSf7JNbWZP3g7wl6SdNo3ah5Aiw+0e9FDErkVHLKprYUrwTm7dF646FtEkN/KkAKPYezxpmvOjxw==} + + '@tanstack/vue-table@8.21.3': + resolution: {integrity: sha512-rusRyd77c5tDPloPskctMyPLFEQUeBzxdQ+2Eow4F7gDPlPOB1UnnhzfpdvqZ8ZyX2rRNGmqNnQWm87OI2OQPw==} + engines: {node: '>=12'} + peerDependencies: + vue: '>=3.2' + + '@tanstack/vue-virtual@3.13.21': + resolution: {integrity: sha512-zneUNdQTcUhoDl6+ek+/O4S9gSZRAc2q7VLscZ4WZnFfZcHc3M7OyVCfSDC3hGuwFqzfL8Cx5bZF6zbGCYwXmw==} + peerDependencies: + vue: ^2.7.0 || ^3.0.0 + + '@tiptap/core@3.20.1': + resolution: {integrity: sha512-SwkPEWIfaDEZjC8SEIi4kZjqIYUbRgLUHUuQezo5GbphUNC8kM1pi3C3EtoOPtxXrEbY6e4pWEzW54Pcrd+rVA==} + peerDependencies: + '@tiptap/pm': ^3.20.1 + + '@tiptap/extension-blockquote@3.20.1': + resolution: {integrity: sha512-WzNXk/63PQI2fav4Ta6P0GmYRyu8Gap1pV3VUqaVK829iJ6Zt1T21xayATHEHWMK27VT1GLPJkx9Ycr2jfDyQw==} + peerDependencies: + '@tiptap/core': ^3.20.1 + + '@tiptap/extension-bold@3.20.1': + resolution: {integrity: sha512-fz++Qv6Rk/Hov0IYG/r7TJ1Y4zWkuGONe0UN5g0KY32NIMg3HeOHicbi4xsNWTm9uAOl3eawWDkezEMrleObMw==} + peerDependencies: + '@tiptap/core': ^3.20.1 + + '@tiptap/extension-bubble-menu@3.20.1': + resolution: {integrity: sha512-XaPvO6aCoWdFnCBus0s88lnj17NR/OopV79i8Qhgz3WMR0vrsL5zsd45l0lZuu9pSvm5VW47SoxakkJiZC1suw==} + peerDependencies: + '@tiptap/core': ^3.20.1 + '@tiptap/pm': ^3.20.1 + + '@tiptap/extension-bullet-list@3.20.1': + resolution: {integrity: sha512-mbrlvOZo5OF3vLhp+3fk9KuL/6J/wsN0QxF6ZFRAHzQ9NkJdtdfARcBeBnkWXGN8inB6YxbTGY1/E4lmBkOpOw==} + peerDependencies: + '@tiptap/extension-list': ^3.20.1 + + '@tiptap/extension-code-block@3.20.1': + resolution: {integrity: sha512-vKejwBq+Nlj4Ybd3qOyDxIQKzYymdNH+8eXkKwGShk2nfLJIxq69DCyGvmuHgipIO1qcYPJ149UNpGN+YGcdmA==} + peerDependencies: + '@tiptap/core': ^3.20.1 + '@tiptap/pm': ^3.20.1 + + '@tiptap/extension-code@3.20.1': + resolution: {integrity: sha512-509DHINIA/Gg+eTG7TEkfsS8RUiPLH5xZNyLRT0A1oaoaJmECKfrV6aAm05IdfTyqDqz6LW5pbnX6DdUC4keug==} + peerDependencies: + '@tiptap/core': ^3.20.1 + + '@tiptap/extension-collaboration@3.20.1': + resolution: {integrity: sha512-JnwLvyzrutBffHp6YPnf0XyTnhAgqZ9D8JSUKFp0edvai+dxsb+UMlawesBrgAuoQXw3B8YZUo2VFDVdKas1xQ==} + peerDependencies: + '@tiptap/core': ^3.20.1 + '@tiptap/pm': ^3.20.1 + '@tiptap/y-tiptap': ^3.0.2 + yjs: ^13 + + '@tiptap/extension-document@3.20.1': + resolution: {integrity: sha512-9vrqdGmRV7bQCSY3NLgu7UhIwgOCDp4sKqMNsoNRX0aZ021QQMTvBQDPkiRkCf7MNsnWrNNnr52PVnULEn3vFQ==} + peerDependencies: + '@tiptap/core': ^3.20.1 + + '@tiptap/extension-drag-handle-vue-3@3.20.1': + resolution: {integrity: sha512-FJonOxcj/I7uBpJBSqfEfU+Fqem5aanEj+EsqG5ZQnxhp7cxbUYZkGH0tBBR7jeIIkt2Jk+1LoCAlYzCWbDLcQ==} + peerDependencies: + '@tiptap/extension-drag-handle': ^3.20.1 + '@tiptap/pm': ^3.20.1 + '@tiptap/vue-3': ^3.20.1 + vue: ^3.0.0 + + '@tiptap/extension-drag-handle@3.20.1': + resolution: {integrity: sha512-sIfu5Gt1aZVAagvzr+3Qx+8GE294eU3G6/pYjqNHvf71sDCpdN2gFpeI7WF05foVsCGsH6ieu8x/kTXf5GbNZA==} + peerDependencies: + '@tiptap/core': ^3.20.1 + '@tiptap/extension-collaboration': ^3.20.1 + '@tiptap/extension-node-range': ^3.20.1 + '@tiptap/pm': ^3.20.1 + '@tiptap/y-tiptap': ^3.0.2 + + '@tiptap/extension-dropcursor@3.20.1': + resolution: {integrity: sha512-K18L9FX4znn+ViPSIbTLOGcIaXMx/gLNwAPE8wPLwswbHhQqdiY1zzdBw6drgOc1Hicvebo2dIoUlSXOZsOEcw==} + peerDependencies: + '@tiptap/extensions': ^3.20.1 + + '@tiptap/extension-floating-menu@3.20.1': + resolution: {integrity: sha512-BeDC6nfOesIMn5pFuUnkEjOxGv80sOJ8uk1mdt9/3Fkvra8cB9NIYYCVtd6PU8oQFmJ8vFqPrRkUWrG5tbqnOg==} + peerDependencies: + '@floating-ui/dom': ^1.0.0 + '@tiptap/core': ^3.20.1 + '@tiptap/pm': ^3.20.1 + + '@tiptap/extension-gapcursor@3.20.1': + resolution: {integrity: sha512-kZOtttV6Ai8VUAgEng3h4WKFbtdSNJ6ps7r0cRPY+FctWhVmgNb/JJwwyC+vSilR7nRENAhrA/Cv/RxVlvLw+g==} + peerDependencies: + '@tiptap/extensions': ^3.20.1 + + '@tiptap/extension-hard-break@3.20.1': + resolution: {integrity: sha512-9sKpmg/IIdlLXimYWUZ3PplIRcehv4Oc7V1miTqlnAthMzjMqigDkjjgte4JZV67RdnDJTQkRw8TklCAU28Emg==} + peerDependencies: + '@tiptap/core': ^3.20.1 + + '@tiptap/extension-heading@3.20.1': + resolution: {integrity: sha512-unudyfQP6FxnyWinxvPqe/51DG91J6AaJm666RnAubgYMCgym+33kBftx4j4A6qf+ddWYbD00thMNKOnVLjAEQ==} + peerDependencies: + '@tiptap/core': ^3.20.1 + + '@tiptap/extension-horizontal-rule@3.20.1': + resolution: {integrity: sha512-rjFKFXNntdl0jay8oIGFvvykHlpyQTLmrH3Ag2fj3i8yh6MVvqhtaDomYQbw5sxECd5hBkL+T4n2d2DRuVw/QQ==} + peerDependencies: + '@tiptap/core': ^3.20.1 + '@tiptap/pm': ^3.20.1 + + '@tiptap/extension-image@3.20.1': + resolution: {integrity: sha512-/GPFSLNdYSZQ0E6VBXSAk0UFtDdn98HT1Aa2tO+STELqc5jAdFB42dfFnTC6KQzTvcUOUYkE2S1Q22YC5H2XNQ==} + peerDependencies: + '@tiptap/core': ^3.20.1 + + '@tiptap/extension-italic@3.20.1': + resolution: {integrity: sha512-ZYRX13Kt8tR8JOzSXirH3pRpi8x30o7LHxZY58uXBdUvr3tFzOkh03qbN523+diidSVeHP/aMd/+IrplHRkQug==} + peerDependencies: + '@tiptap/core': ^3.20.1 + + '@tiptap/extension-link@3.20.1': + resolution: {integrity: sha512-oYTTIgsQMqpkSnJAuAc+UtIKMuI4lv9e1y4LfI1iYm6NkEUHhONppU59smhxHLzb3Ww7YpDffbp5IgDTAiJztA==} + peerDependencies: + '@tiptap/core': ^3.20.1 + '@tiptap/pm': ^3.20.1 + + '@tiptap/extension-list-item@3.20.1': + resolution: {integrity: sha512-tzgnyTW82lYJkUnadYbatwkI9dLz/OWRSWuFpQPRje/ItmFMWuQ9c9NDD8qLbXPdEYnvrgSAA+ipCD/1G0qA0Q==} + peerDependencies: + '@tiptap/extension-list': ^3.20.1 + + '@tiptap/extension-list-keymap@3.20.1': + resolution: {integrity: sha512-Dr0xsQKx0XPOgDg7xqoWwfv7FFwZ3WeF3eOjqh3rDXlNHMj1v+UW5cj1HLphrsAZHTrVTn2C+VWPJkMZrSbpvQ==} + peerDependencies: + '@tiptap/extension-list': ^3.20.1 + + '@tiptap/extension-list@3.20.1': + resolution: {integrity: sha512-euBRAn0mkV7R2VEE+AuOt3R0j9RHEMFXamPFmtvTo8IInxDClusrm6mJoDjS8gCGAXsQCRiAe1SCQBPgGbOOwg==} + peerDependencies: + '@tiptap/core': ^3.20.1 + '@tiptap/pm': ^3.20.1 + + '@tiptap/extension-mention@3.20.1': + resolution: {integrity: sha512-KOGokj7oH1QpcM8P02V+o6wHsVE0g7XEtdIy2vtq2vlFE3npNNNFkMa8F8VWX6qyC+VeVrNU6SIzS5MFY2TORA==} + peerDependencies: + '@tiptap/core': ^3.20.1 + '@tiptap/pm': ^3.20.1 + '@tiptap/suggestion': ^3.20.1 + + '@tiptap/extension-node-range@3.20.1': + resolution: {integrity: sha512-+W/mQJxlkXMcwldWUqwdoR0eniJ1S9cVJoAy2Lkis0NhILZDWVNGKl9J4WFoCOXn8Myr17IllIxRYvAXJJ4FHQ==} + peerDependencies: + '@tiptap/core': ^3.20.1 + '@tiptap/pm': ^3.20.1 + + '@tiptap/extension-ordered-list@3.20.1': + resolution: {integrity: sha512-Y+3Ad7OwAdagqdYwCnbqf7/to5ypD4NnUNHA0TXRCs7cAHRA8AdgPoIcGFpaaSpV86oosNU3yfeJouYeroffog==} + peerDependencies: + '@tiptap/extension-list': ^3.20.1 + + '@tiptap/extension-paragraph@3.20.1': + resolution: {integrity: sha512-QFrAtXNyv7JSnomMQc1nx5AnG9mMznfbYJAbdOQYVdbLtAzTfiTuNPNbQrufy5ZGtGaHxDCoaygu2QEfzaKG+Q==} + peerDependencies: + '@tiptap/core': ^3.20.1 + + '@tiptap/extension-placeholder@3.20.1': + resolution: {integrity: sha512-k+jfbCugYGuIFBdojukgEopGazIMOgHrw46FnyN2X/6ICOIjQP2rh2ObslrsUOsJYoEevxCsNF9hZl1HvWX66g==} + peerDependencies: + '@tiptap/extensions': ^3.20.1 + + '@tiptap/extension-strike@3.20.1': + resolution: {integrity: sha512-EYgyma10lpsY+rwbVQL9u+gA7hBlKLSMFH7Zgd37FSxukOjr+HE8iKPQQ+SwbGejyDsPlLT8Z5Jnuxo5Ng90Pg==} + peerDependencies: + '@tiptap/core': ^3.20.1 + + '@tiptap/extension-text@3.20.1': + resolution: {integrity: sha512-7PlIbYW8UenV6NPOXHmv8IcmPGlGx6HFq66RmkJAOJRPXPkTLAiX0N8rQtzUJ6jDEHqoJpaHFEHJw0xzW1yF+A==} + peerDependencies: + '@tiptap/core': ^3.20.1 + + '@tiptap/extension-underline@3.20.1': + resolution: {integrity: sha512-fmHvDKzwCgnZUwRreq8tYkb1YyEwgzZ6QQkAQ0CsCRtvRMqzerr3Duz0Als4i8voZTuGDEL3VR6nAJbLAb/wPg==} + peerDependencies: + '@tiptap/core': ^3.20.1 + + '@tiptap/extensions@3.20.1': + resolution: {integrity: sha512-JRc/v+OBH0qLTdvQ7HvHWTxGJH73QOf1MC0R8NhOX2QnAbg2mPFv1h+FjGa2gfLGuCXBdWQomjekWkUKbC4e5A==} + peerDependencies: + '@tiptap/core': ^3.20.1 + '@tiptap/pm': ^3.20.1 + + '@tiptap/markdown@3.20.1': + resolution: {integrity: sha512-dNrtP7kmabDomgjv9G/6+JSFL6WraPaFbmKh1eHSYKdDGvIwBfJnVPTV2VS3bP1OuYJEDJN/2ydtiCHyOTrQsQ==} + peerDependencies: + '@tiptap/core': ^3.20.1 + '@tiptap/pm': ^3.20.1 + + '@tiptap/pm@3.20.1': + resolution: {integrity: sha512-6kCiGLvpES4AxcEuOhb7HR7/xIeJWMjZlb6J7e8zpiIh5BoQc7NoRdctsnmFEjZvC19bIasccshHQ7H2zchWqw==} + + '@tiptap/starter-kit@3.20.1': + resolution: {integrity: sha512-opqWxL/4OTEiqmVC0wsU4o3JhAf6LycJ2G/gRIZVAIFLljI9uHfpPMTFGxZ5w9IVVJaP5PJysfwW/635kKqkrw==} + + '@tiptap/suggestion@3.20.1': + resolution: {integrity: sha512-ng7olbzgZhWvPJVJygNQK5153CjquR2eJXpkLq7bRjHlahvt4TH4tGFYvGdYZcXuzbe2g9RoqT7NaPGL9CUq9w==} + peerDependencies: + '@tiptap/core': ^3.20.1 + '@tiptap/pm': ^3.20.1 + + '@tiptap/vue-3@3.20.1': + resolution: {integrity: sha512-06IsNzIkAC0HPHNSdXf4AgtExnr02BHBLXmUiNrjjhgHdxXDKIB0Yq3hEWEfbWNPr3lr7jK6EaFu2IKFMhoUtQ==} + peerDependencies: + '@floating-ui/dom': ^1.0.0 + '@tiptap/core': ^3.20.1 + '@tiptap/pm': ^3.20.1 + vue: ^3.0.0 + + '@tiptap/y-tiptap@3.0.2': + resolution: {integrity: sha512-flMn/YW6zTbc6cvDaUPh/NfLRTXDIqgpBUkYzM74KA1snqQwhOMjnRcnpu4hDFrTnPO6QGzr99vRyXEA7M44WA==} + engines: {node: '>=16.0.0', npm: '>=8.0.0'} + peerDependencies: + prosemirror-model: ^1.7.1 + prosemirror-state: ^1.2.3 + prosemirror-view: ^1.9.10 + y-protocols: ^1.0.1 + yjs: ^13.5.38 + + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + + '@types/d3-array@3.2.2': + resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} + + '@types/d3-axis@3.0.6': + resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} + + '@types/d3-brush@3.0.6': + resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} + + '@types/d3-chord@3.0.6': + resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-contour@3.0.6': + resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} + + '@types/d3-delaunay@6.0.4': + resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} + + '@types/d3-dispatch@3.0.7': + resolution: {integrity: sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==} + + '@types/d3-drag@3.0.7': + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + + '@types/d3-dsv@3.0.7': + resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} + + '@types/d3-ease@3.0.2': + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + + '@types/d3-fetch@3.0.7': + resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} + + '@types/d3-force@3.0.10': + resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} + + '@types/d3-format@3.0.4': + resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} + + '@types/d3-geo@3.1.0': + resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} + + '@types/d3-hierarchy@3.1.7': + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-path@3.1.1': + resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + + '@types/d3-polygon@3.0.2': + resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} + + '@types/d3-quadtree@3.0.6': + resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} + + '@types/d3-random@3.0.3': + resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==} + + '@types/d3-scale-chromatic@3.1.0': + resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} + + '@types/d3-scale@4.0.9': + resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} + + '@types/d3-selection@3.0.11': + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + + '@types/d3-shape@3.1.8': + resolution: {integrity: sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==} + + '@types/d3-time-format@4.0.3': + resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} + + '@types/d3-time@3.0.4': + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + + '@types/d3-timer@3.0.2': + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + + '@types/d3-transition@3.0.9': + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + + '@types/d3-zoom@3.0.8': + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + + '@types/d3@7.4.3': + resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} + + '@types/debug@4.1.12': + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/geojson@7946.0.16': + resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} + + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/linkify-it@5.0.0': + resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} + + '@types/lodash@4.17.24': + resolution: {integrity: sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==} + + '@types/markdown-it@14.1.2': + resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/mdurl@2.0.0': + resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/parse-path@7.1.0': + resolution: {integrity: sha512-EULJ8LApcVEPbrfND0cRQqutIOdiIgJ1Mgrhpy755r14xMohPTEpkV/k28SJvuOs9bHRFW8x+KeDAEPiGQPB9Q==} + deprecated: This is a stub types definition. parse-path provides its own type definitions, so you do not need this installed. + + '@types/resolve@1.20.2': + resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} + + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@types/web-bluetooth@0.0.20': + resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} + + '@types/web-bluetooth@0.0.21': + resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} + + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + + '@unhead/vue@2.1.12': + resolution: {integrity: sha512-zEWqg0nZM8acpuTZE40wkeUl8AhIe0tU0OkilVi1D4fmVjACrwoh5HP6aNqJ8kUnKsoy6D+R3Vi/O+fmdNGO7g==} + peerDependencies: + vue: '>=3.5.18' + + '@upsetjs/venn.js@2.0.0': + resolution: {integrity: sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==} + + '@vercel/nft@1.3.2': + resolution: {integrity: sha512-HC8venRc4Ya7vNeBsJneKHHMDDWpQie7VaKhAIOst3MKO+DES+Y/SbzSp8mFkD7OzwAE2HhHkeSuSmwS20mz3A==} + engines: {node: '>=20'} + hasBin: true + + '@vitejs/plugin-vue-jsx@5.1.4': + resolution: {integrity: sha512-70LmoVk9riR7qc4W2CpjsbNMWTPnuZb9dpFKX1emru0yP57nsc9k8nhLA6U93ngQapv5VDIUq2JatNfLbBIkrA==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + vue: ^3.0.0 + + '@vitejs/plugin-vue@6.0.4': + resolution: {integrity: sha512-uM5iXipgYIn13UUQCZNdWkYk+sysBeA97d5mHsAoAt1u/wpN3+zxOmsVJWosuzX+IMGRzeYUNytztrYznboIkQ==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + vue: ^3.2.25 + + '@volar/language-core@2.4.28': + resolution: {integrity: sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==} + + '@volar/source-map@2.4.28': + resolution: {integrity: sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==} + + '@volar/typescript@2.4.28': + resolution: {integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==} + + '@vue-macros/common@3.1.2': + resolution: {integrity: sha512-h9t4ArDdniO9ekYHAD95t9AZcAbb19lEGK+26iAjUODOIJKmObDNBSe4+6ELQAA3vtYiFPPBtHh7+cQCKi3Dng==} + engines: {node: '>=20.19.0'} + peerDependencies: + vue: ^2.7.0 || ^3.2.25 + peerDependenciesMeta: + vue: + optional: true + + '@vue/babel-helper-vue-transform-on@2.0.1': + resolution: {integrity: sha512-uZ66EaFbnnZSYqYEyplWvn46GhZ1KuYSThdT68p+am7MgBNbQ3hphTL9L+xSIsWkdktwhPYLwPgVWqo96jDdRA==} + + '@vue/babel-plugin-jsx@2.0.1': + resolution: {integrity: sha512-a8CaLQjD/s4PVdhrLD/zT574ZNPnZBOY+IhdtKWRB4HRZ0I2tXBi5ne7d9eCfaYwp5gU5+4KIyFTV1W1YL9xZA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + peerDependenciesMeta: + '@babel/core': + optional: true + + '@vue/babel-plugin-resolve-type@2.0.1': + resolution: {integrity: sha512-ybwgIuRGRRBhOU37GImDoWQoz+TlSqap65qVI6iwg/J7FfLTLmMf97TS7xQH9I7Qtr/gp161kYVdhr1ZMraSYQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@vue/compiler-core@3.5.30': + resolution: {integrity: sha512-s3DfdZkcu/qExZ+td75015ljzHc6vE+30cFMGRPROYjqkroYI5NV2X1yAMX9UeyBNWB9MxCfPcsjpLS11nzkkw==} + + '@vue/compiler-dom@3.5.30': + resolution: {integrity: sha512-eCFYESUEVYHhiMuK4SQTldO3RYxyMR/UQL4KdGD1Yrkfdx4m/HYuZ9jSfPdA+nWJY34VWndiYdW/wZXyiPEB9g==} + + '@vue/compiler-sfc@3.5.30': + resolution: {integrity: sha512-LqmFPDn89dtU9vI3wHJnwaV6GfTRD87AjWpTWpyrdVOObVtjIuSeZr181z5C4PmVx/V3j2p+0f7edFKGRMpQ5A==} + + '@vue/compiler-ssr@3.5.30': + resolution: {integrity: sha512-NsYK6OMTnx109PSL2IAyf62JP6EUdk4Dmj6AkWcJGBvN0dQoMYtVekAmdqgTtWQgEJo+Okstbf/1p7qZr5H+bA==} + + '@vue/devtools-api@6.6.4': + resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} + + '@vue/devtools-core@8.0.7': + resolution: {integrity: sha512-PmpiPxvg3Of80ODHVvyckxwEW1Z02VIAvARIZS1xegINn3VuNQLm9iHUmKD+o6cLkMNWV8OG8x7zo0kgydZgdg==} + peerDependencies: + vue: ^3.0.0 + + '@vue/devtools-kit@8.0.7': + resolution: {integrity: sha512-H6esJGHGl5q0E9iV3m2EoBQHJ+V83WMW83A0/+Fn95eZ2iIvdsq4+UCS6yT/Fdd4cGZSchx/MdWDreM3WqMsDw==} + + '@vue/devtools-shared@8.0.7': + resolution: {integrity: sha512-CgAb9oJH5NUmbQRdYDj/1zMiaICYSLtm+B1kxcP72LBrifGAjUmt8bx52dDH1gWRPlQgxGPqpAMKavzVirAEhA==} + + '@vue/language-core@3.2.5': + resolution: {integrity: sha512-d3OIxN/+KRedeM5wQ6H6NIpwS3P5gC9nmyaHgBk+rO6dIsjY+tOh4UlPpiZbAh3YtLdCGEX4M16RmsBqPmJV+g==} + + '@vue/reactivity@3.5.30': + resolution: {integrity: sha512-179YNgKATuwj9gB+66snskRDOitDiuOZqkYia7mHKJaidOMo/WJxHKF8DuGc4V4XbYTJANlfEKb0yxTQotnx4Q==} + + '@vue/runtime-core@3.5.30': + resolution: {integrity: sha512-e0Z+8PQsUTdwV8TtEsLzUM7SzC7lQwYKePydb7K2ZnmS6jjND+WJXkmmfh/swYzRyfP1EY3fpdesyYoymCzYfg==} + + '@vue/runtime-dom@3.5.30': + resolution: {integrity: sha512-2UIGakjU4WSQ0T4iwDEW0W7vQj6n7AFn7taqZ9Cvm0Q/RA2FFOziLESrDL4GmtI1wV3jXg5nMoJSYO66egDUBw==} + + '@vue/server-renderer@3.5.30': + resolution: {integrity: sha512-v+R34icapydRwbZRD0sXwtHqrQJv38JuMB4JxbOxd8NEpGLny7cncMp53W9UH/zo4j8eDHjQ1dEJXwzFQknjtQ==} + peerDependencies: + vue: 3.5.30 + + '@vue/shared@3.5.30': + resolution: {integrity: sha512-YXgQ7JjaO18NeK2K9VTbDHaFy62WrObMa6XERNfNOkAhD1F1oDSf3ZJ7K6GqabZ0BvSDHajp8qfS5Sa2I9n8uQ==} + + '@vueuse/core@10.11.1': + resolution: {integrity: sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==} + + '@vueuse/core@14.2.1': + resolution: {integrity: sha512-3vwDzV+GDUNpdegRY6kzpLm4Igptq+GA0QkJ3W61Iv27YWwW/ufSlOfgQIpN6FZRMG0mkaz4gglJRtq5SeJyIQ==} + peerDependencies: + vue: ^3.5.0 + + '@vueuse/integrations@14.2.1': + resolution: {integrity: sha512-2LIUpBi/67PoXJGqSDQUF0pgQWpNHh7beiA+KG2AbybcNm+pTGWT6oPGlBgUoDWmYwfeQqM/uzOHqcILpKL7nA==} + peerDependencies: + async-validator: ^4 + axios: ^1 + change-case: ^5 + drauu: ^0.4 + focus-trap: ^7 || ^8 + fuse.js: ^7 + idb-keyval: ^6 + jwt-decode: ^4 + nprogress: ^0.2 + qrcode: ^1.5 + sortablejs: ^1 + universal-cookie: ^7 || ^8 + vue: ^3.5.0 + peerDependenciesMeta: + async-validator: + optional: true + axios: + optional: true + change-case: + optional: true + drauu: + optional: true + focus-trap: + optional: true + fuse.js: + optional: true + idb-keyval: + optional: true + jwt-decode: + optional: true + nprogress: + optional: true + qrcode: + optional: true + sortablejs: + optional: true + universal-cookie: + optional: true + + '@vueuse/metadata@10.11.1': + resolution: {integrity: sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==} + + '@vueuse/metadata@14.2.1': + resolution: {integrity: sha512-1ButlVtj5Sb/HDtIy1HFr1VqCP4G6Ypqt5MAo0lCgjokrk2mvQKsK2uuy0vqu/Ks+sHfuHo0B9Y9jn9xKdjZsw==} + + '@vueuse/shared@10.11.1': + resolution: {integrity: sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==} + + '@vueuse/shared@14.2.1': + resolution: {integrity: sha512-shTJncjV9JTI4oVNyF1FQonetYAiTBd+Qj7cY89SWbXSkx7gyhrgtEdF2ZAVWS1S3SHlaROO6F2IesJxQEkZBw==} + peerDependencies: + vue: ^3.5.0 + + '@webcontainer/env@1.1.1': + resolution: {integrity: sha512-6aN99yL695Hi9SuIk1oC88l9o0gmxL1nGWWQ/kNy81HigJ0FoaoTXpytCj6ItzgyCEwA9kF1wixsTuv5cjsgng==} + + abbrev@3.0.1: + resolution: {integrity: sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==} + engines: {node: ^18.17.0 || >=20.5.0} + + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + + acorn-import-attributes@1.9.5: + resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} + peerDependencies: + acorn: ^8 + + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + + alien-signals@3.1.2: + resolution: {integrity: sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + + ansis@4.2.0: + resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} + engines: {node: '>=14'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + archiver-utils@5.0.2: + resolution: {integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==} + engines: {node: '>= 14'} + + archiver@7.0.1: + resolution: {integrity: sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==} + engines: {node: '>= 14'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + + ast-kit@2.2.0: + resolution: {integrity: sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==} + engines: {node: '>=20.19.0'} + + ast-walker-scope@0.8.3: + resolution: {integrity: sha512-cbdCP0PGOBq0ASG+sjnKIoYkWMKhhz+F/h9pRexUdX2Hd38+WOlBkRKlqkGOSm0YQpcFMQBJeK4WspUAkwsEdg==} + engines: {node: '>=20.19.0'} + + async-lock@1.4.1: + resolution: {integrity: sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ==} + + async-sema@3.1.1: + resolution: {integrity: sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==} + + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + + automd@0.4.3: + resolution: {integrity: sha512-5WJNEiaNpFm8h0OmQzhnESthadUQhJwQfka/TmmJpMudZ8qU9MZao9p0G1g7WYA9pVTz6FMMOSvxnfQ9g8q9vQ==} + hasBin: true + + autoprefixer@10.4.27: + resolution: {integrity: sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + b4a@1.8.0: + resolution: {integrity: sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==} + peerDependencies: + react-native-b4a: '*' + peerDependenciesMeta: + react-native-b4a: + optional: true + + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + bare-events@2.8.2: + resolution: {integrity: sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==} + peerDependencies: + bare-abort-controller: '*' + peerDependenciesMeta: + bare-abort-controller: + optional: true + + bare-fs@4.5.5: + resolution: {integrity: sha512-XvwYM6VZqKoqDll8BmSww5luA5eflDzY0uEFfBJtFKe4PAAtxBjU3YIxzIBzhyaEQBy1VXEQBto4cpN5RZJw+w==} + engines: {bare: '>=1.16.0'} + peerDependencies: + bare-buffer: '*' + peerDependenciesMeta: + bare-buffer: + optional: true + + bare-os@3.7.1: + resolution: {integrity: sha512-ebvMaS5BgZKmJlvuWh14dg9rbUI84QeV3WlWn6Ph6lFI8jJoh7ADtVTyD2c93euwbe+zgi0DVrl4YmqXeM9aIA==} + engines: {bare: '>=1.14.0'} + + bare-path@3.0.0: + resolution: {integrity: sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==} + + bare-stream@2.8.1: + resolution: {integrity: sha512-bSeR8RfvbRwDpD7HWZvn8M3uYNDrk7m9DQjYOFkENZlXW8Ju/MPaqUPQq5LqJ3kyjEm07siTaAQ7wBKCU59oHg==} + peerDependencies: + bare-buffer: '*' + bare-events: '*' + peerDependenciesMeta: + bare-buffer: + optional: true + bare-events: + optional: true + + bare-url@2.3.2: + resolution: {integrity: sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + baseline-browser-mapping@2.10.0: + resolution: {integrity: sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==} + engines: {node: '>=6.0.0'} + hasBin: true + + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + + birpc@2.9.0: + resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==} + + birpc@4.0.0: + resolution: {integrity: sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==} + + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + brace-expansion@5.0.4: + resolution: {integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==} + engines: {node: 18 || 20 || >=22} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.28.1: + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + buffer-crc32@1.0.0: + resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} + engines: {node: '>=8.0.0'} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + + bundle-name@4.1.0: + resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} + engines: {node: '>=18'} + + c12@3.3.3: + resolution: {integrity: sha512-750hTRvgBy5kcMNPdh95Qo+XUBeGo8C7nsKSmedDmaQI+E0r82DwHeM6vBewDe4rGFbnxoa4V9pw+sPh5+Iz8Q==} + peerDependencies: + magicast: '*' + peerDependenciesMeta: + magicast: + optional: true + + c12@4.0.0-beta.3: + resolution: {integrity: sha512-15pHxeM4kKKnF1zPgvXq/ETPhf9DRLGg0Id3GAyQhQqYxt8WkUCbo0NipHjQUUNC5VPP8TQA32pGPDUZmAi/3g==} + peerDependencies: + chokidar: ^5 + dotenv: '*' + giget: '*' + jiti: '*' + magicast: '*' + peerDependenciesMeta: + chokidar: + optional: true + dotenv: + optional: true + giget: + optional: true + jiti: + optional: true + magicast: + optional: true + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + cac@7.0.0: + resolution: {integrity: sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==} + engines: {node: '>=20.19.0'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + caniuse-api@3.0.0: + resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} + + caniuse-lite@1.0.30001777: + resolution: {integrity: sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + + chevrotain-allstar@0.3.1: + resolution: {integrity: sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==} + peerDependencies: + chevrotain: ^11.0.0 + + chevrotain@11.1.2: + resolution: {integrity: sha512-opLQzEVriiH1uUQ4Kctsd49bRoFDXGGSC4GUqj7pGyxM3RehRhvTlZJc1FL/Flew2p5uwxa1tUDWKzI4wNM8pg==} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} + + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + + citty@0.1.6: + resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} + + citty@0.2.1: + resolution: {integrity: sha512-kEV95lFBhQgtogAPlQfJJ0WGVSokvLr/UEoFPiKKOXF7pl98HfUVUD0ejsuTCld/9xH9vogSywZ5KqHzXrZpqg==} + + clean-git-ref@2.0.1: + resolution: {integrity: sha512-bLSptAy2P0s6hU4PzuIMKmMJJSE6gLXGH1cntDu7bWJUksvuM+7ReOK61mozULErYvP6a15rnYl0zFDef+pyPw==} + + client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + + clipboardy@4.0.0: + resolution: {integrity: sha512-5mOlNS0mhX0707P2I0aZ2V/cmHUEO/fL7VFLqszkhUsxt7RwnmrInf/eEQKlf5GzvYeHIjT+Ov1HRfNmymlG0w==} + engines: {node: '>=18'} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + cluster-key-slot@1.1.2: + resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} + engines: {node: '>=0.10.0'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + colord@2.9.3: + resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} + + colortranslator@5.0.0: + resolution: {integrity: sha512-Z3UPUKasUVDFCDYAjP2fmlVRf1jFHJv1izAmPjiOa0OCIw1W7iC8PZ2GsoDa8uZv+mKyWopxxStT9q05+27h7w==} + + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + + commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + + commondir@1.0.1: + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + + compatx@0.2.0: + resolution: {integrity: sha512-6gLRNt4ygsi5NyMVhceOCFv14CIdDFN7fQjX1U4+47qVE/+kjPoXMK65KWK+dWxmFzMTuKazoQ9sch6pM0p5oA==} + + compress-commons@6.0.2: + resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==} + engines: {node: '>= 14'} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + confbox@0.2.4: + resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} + + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cookie-es@1.2.2: + resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==} + + cookie-es@2.0.0: + resolution: {integrity: sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==} + + copy-paste@2.2.0: + resolution: {integrity: sha512-jqSL4r9DSeiIvJZStLzY/sMLt9ToTM7RsK237lYOTG+KcbQJHGala3R1TUpa8h1p9adswVgIdV4qGbseVhL4lg==} + + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + cose-base@1.0.3: + resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} + + cose-base@2.2.0: + resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==} + + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + + crc32-stream@6.0.0: + resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==} + engines: {node: '>= 14'} + + crelt@1.0.6: + resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} + + croner@9.1.0: + resolution: {integrity: sha512-p9nwwR4qyT5W996vBZhdvBCnMhicY5ytZkR4D1Xj0wuTDEiMnjwR57Q3RXYY/s0EpX6Ay3vgIcfaR+ewGHsi+g==} + engines: {node: '>=18.0'} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + crossws@0.3.5: + resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==} + + css-declaration-sorter@7.3.1: + resolution: {integrity: sha512-gz6x+KkgNCjxq3Var03pRYLhyNfwhkKF1g/yoLgDNtFvVu0/fOLV9C8fFEZRjACp/XQLumjAYo7JVjzH3wLbxA==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + postcss: ^8.0.9 + + css-select@5.2.2: + resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} + + css-tree@2.2.1: + resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + + css-tree@3.2.1: + resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + + css-what@6.2.2: + resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} + engines: {node: '>= 6'} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + cssnano-preset-default@7.0.11: + resolution: {integrity: sha512-waWlAMuCakP7//UCY+JPrQS1z0OSLeOXk2sKWJximKWGupVxre50bzPlvpbUwZIDylhf/ptf0Pk+Yf7C+hoa3g==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + cssnano-utils@5.0.1: + resolution: {integrity: sha512-ZIP71eQgG9JwjVZsTPSqhc6GHgEr53uJ7tK5///VfyWj6Xp2DBmixWHqJgPno+PqATzn48pL42ww9x5SSGmhZg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + cssnano@7.1.3: + resolution: {integrity: sha512-mLFHQAzyapMVFLiJIn7Ef4C2UCEvtlTlbyILR6B5ZsUAV3D/Pa761R5uC1YPhyBkRd3eqaDm2ncaNrD7R4mTRg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + csso@5.0.5: + resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + cytoscape-cose-bilkent@4.1.0: + resolution: {integrity: sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape-fcose@2.2.0: + resolution: {integrity: sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape@3.33.1: + resolution: {integrity: sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==} + engines: {node: '>=0.10'} + + d3-array@2.12.1: + resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==} + + d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + + d3-axis@3.0.0: + resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} + engines: {node: '>=12'} + + d3-brush@3.0.0: + resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} + engines: {node: '>=12'} + + d3-chord@3.0.1: + resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} + engines: {node: '>=12'} + + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-contour@4.0.2: + resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} + engines: {node: '>=12'} + + d3-delaunay@6.0.4: + resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-dsv@3.0.1: + resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} + engines: {node: '>=12'} + hasBin: true + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-fetch@3.0.1: + resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} + engines: {node: '>=12'} + + d3-force@3.0.0: + resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + engines: {node: '>=12'} + + d3-format@3.1.2: + resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==} + engines: {node: '>=12'} + + d3-geo@3.1.1: + resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} + engines: {node: '>=12'} + + d3-hierarchy@3.1.2: + resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-path@1.0.9: + resolution: {integrity: sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==} + + d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + + d3-polygon@3.0.1: + resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} + engines: {node: '>=12'} + + d3-quadtree@3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + + d3-random@3.0.1: + resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} + engines: {node: '>=12'} + + d3-sankey@0.12.3: + resolution: {integrity: sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==} + + d3-scale-chromatic@3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + + d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-shape@1.3.7: + resolution: {integrity: sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==} + + d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + + d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + + d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + + d3@7.9.0: + resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} + engines: {node: '>=12'} + + dagre-d3-es@7.0.14: + resolution: {integrity: sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==} + + dayjs@1.11.19: + resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} + + db0@0.3.4: + resolution: {integrity: sha512-RiXXi4WaNzPTHEOu8UPQKMooIbqOEyqA1t7Z6MsdxSCeb8iUC9ko3LcmsLmeUt2SM5bctfArZKkRQggKZz7JNw==} + peerDependencies: + '@electric-sql/pglite': '*' + '@libsql/client': '*' + better-sqlite3: '*' + drizzle-orm: '*' + mysql2: '*' + sqlite3: '*' + peerDependenciesMeta: + '@electric-sql/pglite': + optional: true + '@libsql/client': + optional: true + better-sqlite3: + optional: true + drizzle-orm: + optional: true + mysql2: + optional: true + sqlite3: + optional: true + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} + + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + default-browser-id@5.0.1: + resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} + engines: {node: '>=18'} + + default-browser@5.5.0: + resolution: {integrity: sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==} + engines: {node: '>=18'} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-lazy-prop@2.0.0: + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} + engines: {node: '>=8'} + + define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + + defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + + delaunator@5.0.1: + resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} + + denque@2.1.0: + resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} + engines: {node: '>=0.10'} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + destr@2.0.5: + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + + detab@3.0.2: + resolution: {integrity: sha512-7Bp16Bk8sk0Y6gdXiCtnpGbghn8atnTJdd/82aWvS5ESnlcNvgUc10U2NYS0PAiDSGjWiI8qs/Cv1b2uSGdQ8w==} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + devalue@5.6.3: + resolution: {integrity: sha512-nc7XjUU/2Lb+SvEFVGcWLiKkzfw8+qHI7zn8WYXKkLMgfGSHbgCEaR6bJpev8Cm6Rmrb19Gfd/tZvGqx9is3wg==} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + didyoumean2@7.0.4: + resolution: {integrity: sha512-+yW4SNY7W2DOWe2Jx5H4c2qMTFbLGM6wIyoDPkAPy66X+sD1KfYjBPAIWPVsYqMxelflaMQCloZDudELIPhLqA==} + engines: {node: ^18.12.0 || >=20.9.0} + + diff3@0.0.3: + resolution: {integrity: sha512-iSq8ngPOt0K53A6eVr4d5Kn6GNrM2nQZtC740pzIriHtn4pOQ2lyzEXQMBeVcWERN0ye7fhBsk9PbLLQOnUx/g==} + + diff@8.0.3: + resolution: {integrity: sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==} + engines: {node: '>=0.3.1'} + + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + + dompurify@3.3.2: + resolution: {integrity: sha512-6obghkliLdmKa56xdbLOpUZ43pAR6xFy1uOrxBaIDjT+yaRuuybLjGS9eVBoSR/UPU5fq3OXClEHLJNGvbxKpQ==} + engines: {node: '>=20'} + + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + + dot-prop@10.1.0: + resolution: {integrity: sha512-MVUtAugQMOff5RnBy2d9N31iG0lNwg1qAoAOn7pOK5wf94WIaE3My2p3uwTQuvS2AcqchkcR3bHByjaM0mmi7Q==} + engines: {node: '>=20'} + + dotenv@17.3.1: + resolution: {integrity: sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==} + engines: {node: '>=12'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + duplexer@0.1.2: + resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + electron-to-chromium@1.5.307: + resolution: {integrity: sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==} + + embla-carousel-auto-height@8.6.0: + resolution: {integrity: sha512-/HrJQOEM6aol/oF33gd2QlINcXy3e19fJWvHDuHWp2bpyTa+2dm9tVVJak30m2Qy6QyQ6Fc8DkImtv7pxWOJUQ==} + peerDependencies: + embla-carousel: 8.6.0 + + embla-carousel-auto-scroll@8.6.0: + resolution: {integrity: sha512-WT9fWhNXFpbQ6kP+aS07oF5IHYLZ1Dx4DkwgCY8Hv2ZyYd2KMCPfMV1q/cA3wFGuLO7GMgKiySLX90/pQkcOdQ==} + peerDependencies: + embla-carousel: 8.6.0 + + embla-carousel-autoplay@8.6.0: + resolution: {integrity: sha512-OBu5G3nwaSXkZCo1A6LTaFMZ8EpkYbwIaH+bPqdBnDGQ2fh4+NbzjXjs2SktoPNKCtflfVMc75njaDHOYXcrsA==} + peerDependencies: + embla-carousel: 8.6.0 + + embla-carousel-class-names@8.6.0: + resolution: {integrity: sha512-l1hm1+7GxQ+zwdU2sea/LhD946on7XO2qk3Xq2XWSwBaWfdgchXdK567yzLtYSHn4sWYdiX+x4nnaj+saKnJkw==} + peerDependencies: + embla-carousel: 8.6.0 + + embla-carousel-fade@8.6.0: + resolution: {integrity: sha512-qaYsx5mwCz72ZrjlsXgs1nKejSrW+UhkbOMwLgfRT7w2LtdEB03nPRI06GHuHv5ac2USvbEiX2/nAHctcDwvpg==} + peerDependencies: + embla-carousel: 8.6.0 + + embla-carousel-reactive-utils@8.6.0: + resolution: {integrity: sha512-fMVUDUEx0/uIEDM0Mz3dHznDhfX+znCCDCeIophYb1QGVM7YThSWX+wz11zlYwWFOr74b4QLGg0hrGPJeG2s4A==} + peerDependencies: + embla-carousel: 8.6.0 + + embla-carousel-vue@8.6.0: + resolution: {integrity: sha512-v8UO5UsyLocZnu/LbfQA7Dn2QHuZKurJY93VUmZYP//QRWoCWOsionmvLLAlibkET3pGPs7++03VhJKbWD7vhQ==} + peerDependencies: + vue: ^3.2.37 + + embla-carousel-wheel-gestures@8.1.0: + resolution: {integrity: sha512-J68jkYrxbWDmXOm2n2YHl+uMEXzkGSKjWmjaEgL9xVvPb3HqVmg6rJSKfI3sqIDVvm7mkeTy87wtG/5263XqHQ==} + engines: {node: '>=10'} + peerDependencies: + embla-carousel: ^8.0.0 || ~8.0.0-rc03 + + embla-carousel@8.6.0: + resolution: {integrity: sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + emojilib@2.4.0: + resolution: {integrity: sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==} + + emoticon@4.1.0: + resolution: {integrity: sha512-VWZfnxqwNcc51hIy/sbOdEem6D+cVtpPzEEtVAFdaas30+1dgkyaOQ4sQ6Bp0tOMqWO1v+HQfYaoodOkdhK6SQ==} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + engine.io-client@6.6.4: + resolution: {integrity: sha512-+kjUJnZGwzewFDw951CDWcwj35vMNf2fcj7xQWOctq1F2i1jkDdVvdFG9kM/BEChymCH36KgjnW0NsL58JYRxw==} + + engine.io-parser@5.2.3: + resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==} + engines: {node: '>=10.0.0'} + + enhanced-resolve@5.20.0: + resolution: {integrity: sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==} + engines: {node: '>=10.13.0'} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} + engines: {node: '>=0.12'} + + error-stack-parser-es@1.0.5: + resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} + + errx@0.1.0: + resolution: {integrity: sha512-fZmsRiDNv07K6s2KkKFTiD2aIvECa7++PKyD5NC32tpRw46qZA3sOz+aM+/V9V0GDHxVTKLziveV4JhzBHDp9Q==} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-module-lexer@2.0.0: + resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + esbuild@0.27.3: + resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + + events-universal@1.0.1: + resolution: {integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==} + + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + + exsolve@1.0.8: + resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + fast-fifo@1.3.2: + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-npm-meta@1.4.2: + resolution: {integrity: sha512-XXyd9d3ie/JeIIjm6WeKalvapGGFI4ShAjPJM78vgUFYzoEsuNSjvvVTuht0XZcwbVdOnEEGzhxwguRbxkIcDg==} + hasBin: true + + fastest-levenshtein@1.0.16: + resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} + engines: {node: '>= 4.9.1'} + + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + flat@6.0.1: + resolution: {integrity: sha512-/3FfIa8mbrg3xE7+wAhWeV+bd7L2Mof+xtZb5dRDKZ+wDvYJK4WDYeIOuOhre5Yv5aQObZrlbRmk3RTSiuQBtw==} + engines: {node: '>=18'} + hasBin: true + + fontaine@0.8.0: + resolution: {integrity: sha512-eek1GbzOdWIj9FyQH/emqW1aEdfC3lYRCHepzwlFCm5T77fBSRSyNRKE6/antF1/B1M+SfJXVRQTY9GAr7lnDg==} + engines: {node: '>=18.12.0'} + + fontkitten@1.0.3: + resolution: {integrity: sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw==} + engines: {node: '>=20'} + + fontless@0.2.1: + resolution: {integrity: sha512-mUWZ8w91/mw2KEcZ6gHNoNNmsAq9Wiw2IypIux5lM03nhXm+WSloXGUNuRETNTLqZexMgpt7Aj/v63qqrsWraQ==} + engines: {node: '>=18.12.0'} + peerDependencies: + vite: '*' + peerDependenciesMeta: + vite: + optional: true + + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + fraction.js@5.3.4: + resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} + + framer-motion@12.35.2: + resolution: {integrity: sha512-dhfuEMaNo0hc+AEqyHiIfiJRNb9U9UQutE9FoKm5pjf7CMitp9xPEF1iWZihR1q86LBmo6EJ7S8cN8QXEy49AA==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + fuse.js@7.1.0: + resolution: {integrity: sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==} + engines: {node: '>=10'} + + fzf@0.5.2: + resolution: {integrity: sha512-Tt4kuxLXFKHy8KT40zwsUPUkg1CrsgY25FxA2U/j/0WgEDCk3ddc/zLTCCcbSHX9FcKtLuVaDGtGE/STWC+j3Q==} + + geist@1.7.0: + resolution: {integrity: sha512-ZaoiZwkSf0DwwB1ncdLKp+ggAldqxl5L1+SXaNIBGkPAqcu+xjVJLxlf3/S8vLt9UHx1xu5fz3lbzKCj5iOVdQ==} + peerDependencies: + next: '>=13.2.0' + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-port-please@3.2.0: + resolution: {integrity: sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + + giget@2.0.0: + resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} + hasBin: true + + giget@3.1.2: + resolution: {integrity: sha512-T2qUpKBHeUTwHcIhydgnJzhL0Hj785ms+JkxaaWQH9SDM/llXeewnOkfJcFShAHjWI+26hOChwUfCoupaXLm8g==} + hasBin: true + + git-up@8.1.1: + resolution: {integrity: sha512-FDenSF3fVqBYSaJoYy1KSc2wosx0gCvKP+c+PRBht7cAaiCeQlBtfBDX9vgnNOHmdePlSFITVcn4pFfcgNvx3g==} + + git-url-parse@16.1.0: + resolution: {integrity: sha512-cPLz4HuK86wClEW7iDdeAKcCVlWXmrLpb2L+G9goW0Z1dtpNS6BXXSOckUTlJT/LDQViE1QZKstNORzHsLnobw==} + + github-slugger@2.0.0: + resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob@10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + hasBin: true + + glob@13.0.6: + resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} + engines: {node: 18 || 20 || >=22} + + global-directory@4.0.1: + resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==} + engines: {node: '>=18'} + + globby@16.1.1: + resolution: {integrity: sha512-dW7vl+yiAJSp6aCekaVnVJxurRv7DCOLyXqEG3RYMYUg7AuJ2jCqPkZTA8ooqC2vtnkaMcV5WfFBMuEnTu1OQg==} + engines: {node: '>=20'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + gzip-size@7.0.0: + resolution: {integrity: sha512-O1Ld7Dr+nqPnmGpdhzLmMTQ4vAsD+rHwMm1NLUmoUFFymBOMKxCCrtDxqdBRYXdeEPEi3SyoR4TizJLQrnKBNA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + h3@1.15.6: + resolution: {integrity: sha512-oi15ESLW5LRthZ+qPCi5GNasY/gvynSKUQxgiovrY63bPAtG59wtM+LSrlcwvOHAXzGrXVLnI97brbkdPF9WoQ==} + + hachure-fill@0.5.2: + resolution: {integrity: sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + hast-util-embedded@3.0.0: + resolution: {integrity: sha512-naH8sld4Pe2ep03qqULEtvYr7EjrLK2QHY8KJR6RJkTUjPGObe1vnx585uzem2hGra+s1q08DZZpfgDVYRbaXA==} + + hast-util-format@1.1.0: + resolution: {integrity: sha512-yY1UDz6bC9rDvCWHpx12aIBGRG7krurX0p0Fm6pT547LwDIZZiNr8a+IHDogorAdreULSEzP82Nlv5SZkHZcjA==} + + hast-util-from-parse5@8.0.3: + resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} + + hast-util-has-property@3.0.0: + resolution: {integrity: sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==} + + hast-util-heading-rank@3.0.0: + resolution: {integrity: sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==} + + hast-util-is-body-ok-link@3.0.1: + resolution: {integrity: sha512-0qpnzOBLztXHbHQenVB8uNuxTnm/QBFUOmdOSsEn7GnBtyY07+ENTWVFBAnXd/zEgd9/SUG3lRY7hSIBWRgGpQ==} + + hast-util-is-element@3.0.0: + resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} + + hast-util-minify-whitespace@1.0.1: + resolution: {integrity: sha512-L96fPOVpnclQE0xzdWb/D12VT5FabA7SnZOUMtL1DbXmYiHJMXZvFkIZfiMmTCNJHUeO2K9UYNXoVyfz+QHuOw==} + + hast-util-parse-selector@4.0.0: + resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} + + hast-util-phrasing@3.0.1: + resolution: {integrity: sha512-6h60VfI3uBQUxHqTyMymMZnEbNl1XmEGtOxxKYL7stY2o601COo62AWAYBQR9lZbYXYSBoxag8UpPRXK+9fqSQ==} + + hast-util-raw@9.1.0: + resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==} + + hast-util-to-html@9.0.5: + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} + + hast-util-to-mdast@10.1.2: + resolution: {integrity: sha512-FiCRI7NmOvM4y+f5w32jPRzcxDIz+PUqDwEqn1A+1q2cdp3B8Gx7aVrXORdOKjMNDQsD1ogOr896+0jJHW1EFQ==} + + hast-util-to-parse5@8.0.1: + resolution: {integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==} + + hast-util-to-string@3.0.1: + resolution: {integrity: sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==} + + hast-util-to-text@4.0.2: + resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + + hastscript@9.0.1: + resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} + + hey-listen@1.0.8: + resolution: {integrity: sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==} + + hookable@5.5.3: + resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + + hookable@6.0.1: + resolution: {integrity: sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw==} + + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + + html-whitespace-sensitive-tag-names@3.0.1: + resolution: {integrity: sha512-q+310vW8zmymYHALr1da4HyXUQ0zgiIwIicEfotYPWGN0OJVEN/58IJ3A4GBYcEq3LGAZqKb+ugvP0GNB9CEAA==} + + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + + http-shutdown@1.2.2: + resolution: {integrity: sha512-S9wWkJ/VSY9/k4qcjG318bqJNruzE4HySUhFYknwmu6LBP97KLLfwNf+n4V1BHurvFNkSKLFnK/RsuUnRTf9Vw==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + httpxy@0.1.7: + resolution: {integrity: sha512-pXNx8gnANKAndgga5ahefxc++tJvNL87CXoRwxn1cJE2ZkWEojF3tNfQIEhZX/vfpt+wzeAzpUI4qkediX1MLQ==} + + human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + + iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + image-meta@0.2.2: + resolution: {integrity: sha512-3MOLanc3sb3LNGWQl1RlQlNWURE5g32aUphrDyFeCsxBTk08iE3VNe4CwsUZ0Qs1X+EfX0+r29Sxdpza4B+yRA==} + + impound@1.1.5: + resolution: {integrity: sha512-5AUn+QE0UofqNHu5f2Skf6Svukdg4ehOIq8O0EtqIx4jta0CDZYBPqpIHt0zrlUTiFVYlLpeH39DoikXBjPKpA==} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ini@4.1.1: + resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + internmap@1.0.1: + resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==} + + internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + + ioredis@5.10.0: + resolution: {integrity: sha512-HVBe9OFuqs+Z6n64q09PQvP1/R4Bm+30PAyyD4wIEqssh3v9L21QjCVk4kRLucMBcDokJTcLjsGeVRlq/nH6DA==} + engines: {node: '>=12.22.0'} + + iron-webcrypto@1.2.1: + resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} + + is-absolute-url@4.0.1: + resolution: {integrity: sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + + is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + + is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + + is-installed-globally@1.0.0: + resolution: {integrity: sha512-K55T22lfpQ63N4KEN57jZUAaAYqYHEe8veb/TycJRk9DdSCLLcovXz/mL6mOnhQaZsQGwPhuFopdQIlqGSEjiQ==} + engines: {node: '>=18'} + + is-module@1.0.0: + resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-path-inside@4.0.0: + resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==} + engines: {node: '>=12'} + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + is-reference@1.2.1: + resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} + + is-ssh@1.4.1: + resolution: {integrity: sha512-JNeu1wQsHjyHgn9NcWTaXq6zWSR6hqE0++zhfZlkFBbScNkyvxCdeV8sRkSBaeLKxmbpR21brail63ACNxJ0Tg==} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + + is-wsl@3.1.1: + resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} + engines: {node: '>=16'} + + is64bit@2.0.0: + resolution: {integrity: sha512-jv+8jaWCl0g2lSBkNSVXdzfBA0npK1HGC2KtWM9FumFRoGS94g3NbCCLVnCYHLjp4GrW2KZeeSTMo5ddtznmGw==} + engines: {node: '>=18'} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + isexe@3.1.5: + resolution: {integrity: sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==} + engines: {node: '>=18'} + + isomorphic-git@1.37.2: + resolution: {integrity: sha512-HCQBBKmXIMPdHgYGstSBNp6MNmVcMQBbUqJF8xfywFmlpNseO4KKex59YlXqNxhRxmv3fUZwvNWvMyOdc1VvhA==} + engines: {node: '>=14.17'} + hasBin: true + + isomorphic.js@0.2.5: + resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-tokens@9.0.1: + resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-schema-to-typescript@15.0.4: + resolution: {integrity: sha512-Su9oK8DR4xCmDsLlyvadkXzX6+GGXJpbhwoLtOGArAG61dvbW4YQmSEno2y66ahpIdmLMg6YUf/QHLgiwvkrHQ==} + engines: {node: '>=16.0.0'} + hasBin: true + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + katex@0.16.38: + resolution: {integrity: sha512-cjHooZUmIAUmDsHBN+1n8LaZdpmbj03LtYeYPyuYB7OuloiaeaV6N4LcfjcnHVzGWjVQmKrxxTrpDcmSzEZQwQ==} + hasBin: true + + khroma@2.1.0: + resolution: {integrity: sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==} + + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + + klona@2.0.6: + resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} + engines: {node: '>= 8'} + + knitwork@1.3.0: + resolution: {integrity: sha512-4LqMNoONzR43B1W0ek0fhXMsDNW/zxa1NdFAVMY+k28pgZLovR4G3PB5MrpTxCy1QaZCqNoiaKPr5w5qZHfSNw==} + + langium@4.2.1: + resolution: {integrity: sha512-zu9QWmjpzJcomzdJQAHgDVhLGq5bLosVak1KVa40NzQHXfqr4eAHupvnPOVXEoLkg6Ocefvf/93d//SB7du4YQ==} + engines: {node: '>=20.10.0', npm: '>=10.2.3'} + + launch-editor@2.13.1: + resolution: {integrity: sha512-lPSddlAAluRKJ7/cjRFoXUFzaX7q/YKI7yPHuEvSJVqoXvFnJov1/Ud87Aa4zULIbA9Nja4mSPK8l0z/7eV2wA==} + + layout-base@1.0.2: + resolution: {integrity: sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==} + + layout-base@2.0.1: + resolution: {integrity: sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==} + + lazystream@1.0.1: + resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} + engines: {node: '>= 0.6.3'} + + lib0@0.2.117: + resolution: {integrity: sha512-DeXj9X5xDCjgKLU/7RR+/HQEVzuuEUiwldwOGsHK/sfAfELGWEyTcf0x+uOvCvK3O2zPmZePXWL85vtia6GyZw==} + engines: {node: '>=16'} + hasBin: true + + lightningcss-android-arm64@1.31.1: + resolution: {integrity: sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.31.1: + resolution: {integrity: sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.31.1: + resolution: {integrity: sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.31.1: + resolution: {integrity: sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.31.1: + resolution: {integrity: sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.31.1: + resolution: {integrity: sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.31.1: + resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.31.1: + resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.31.1: + resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.31.1: + resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.31.1: + resolution: {integrity: sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.31.1: + resolution: {integrity: sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==} + engines: {node: '>= 12.0.0'} + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + linkify-it@5.0.0: + resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + + linkifyjs@4.3.2: + resolution: {integrity: sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA==} + + listhen@1.9.0: + resolution: {integrity: sha512-I8oW2+QL5KJo8zXNWX046M134WchxsXC7SawLPvRQpogCbkyQIaFxPE89A2HiwR7vAK2Dm2ERBAmyjTYGYEpBg==} + hasBin: true + + local-pkg@1.1.2: + resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==} + engines: {node: '>=14'} + + lodash-es@4.17.23: + resolution: {integrity: sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==} + + lodash.deburr@4.1.0: + resolution: {integrity: sha512-m/M1U1f3ddMCs6Hq2tAsYThTBDaAKFDX3dwDo97GEYzamXi9SqUpjWi/Rrj/gf3X2n8ktwgZrlP1z6E3v/IExQ==} + + lodash.defaults@4.2.0: + resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + + lodash.isarguments@3.1.0: + resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==} + + lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + + lodash.uniq@4.5.0: + resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} + + lodash@4.17.23: + resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==} + + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lru-cache@11.2.6: + resolution: {integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==} + engines: {node: 20 || >=22} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + magic-regexp@0.10.0: + resolution: {integrity: sha512-Uly1Bu4lO1hwHUW0CQeSWuRtzCMNO00CmXtS8N6fyvB3B979GOEEeAkiTUDsmbYLAbvpUS/Kt5c4ibosAzVyVg==} + + magic-string-ast@1.0.3: + resolution: {integrity: sha512-CvkkH1i81zl7mmb94DsRiFeG9V2fR2JeuK8yDgS8oiZSFa++wWLEgZ5ufEOyLHbvSbD1gTRKv9NdX69Rnvr9JA==} + engines: {node: '>=20.19.0'} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + magicast@0.5.2: + resolution: {integrity: sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==} + + markdown-it@14.1.1: + resolution: {integrity: sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==} + hasBin: true + + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + + marked@16.4.2: + resolution: {integrity: sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==} + engines: {node: '>= 20'} + hasBin: true + + marked@17.0.4: + resolution: {integrity: sha512-NOmVMM+KAokHMvjWmC5N/ZOvgmSWuqJB8FoYI019j4ogb/PeRMKoKIjReZ2w3376kkA8dSJIP8uD993Kxc0iRQ==} + engines: {node: '>= 20'} + hasBin: true + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + md4w@0.2.7: + resolution: {integrity: sha512-lFM7vwk3d4MzkV2mija7aPkK6OjKXZDQsH2beX+e2cvccBoqc6RraheMtAO0Wcr/gjj5L+WS5zhb+06AmuGZrg==} + + mdast-util-find-and-replace@3.0.2: + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} + + mdast-util-from-markdown@2.0.3: + resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} + + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + + mdbox@0.1.1: + resolution: {integrity: sha512-jvLISenzbLRPWWamTG3THlhTcMbKWzJQNyTi61AVXhCBOC+gsldNTUfUNH8d3Vay83zGehFw3wZpF3xChzkTIQ==} + + mdn-data@2.0.28: + resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} + + mdn-data@2.27.1: + resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} + + mdream@0.17.0: + resolution: {integrity: sha512-DVaUCgKJZx7Wp6DNZMBhkMWf40nEtANLa8+ZwhqFJE276YiKUqpupG+eCIxKIcLtUP4aKpKp6EssNjCx49qtSg==} + hasBin: true + + mdurl@2.0.0: + resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + mermaid@11.13.0: + resolution: {integrity: sha512-fEnci+Immw6lKMFI8sqzjlATTyjLkRa6axrEgLV2yHTfv8r+h1wjFbV6xeRtd4rUV1cS4EpR9rwp3Rci7TRWDw==} + + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.1: + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + + mime@4.1.0: + resolution: {integrity: sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==} + engines: {node: '>=16'} + hasBin: true + + mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + + minimark@0.2.0: + resolution: {integrity: sha512-AmtWU9pO0C2/3AM2pikaVhJ//8E5rOpJ7+ioFQfjIq+wCsBeuZoxPd97hBFZ9qrI7DMHZudwGH3r8A7BMnsIew==} + + minimatch@10.2.4: + resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} + engines: {node: 18 || 20 || >=22} + + minimatch@5.1.9: + resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} + engines: {node: '>=10'} + + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minimisted@2.0.1: + resolution: {integrity: sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA==} + + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + + minizlib@3.1.0: + resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} + engines: {node: '>= 18'} + + mlly@1.8.1: + resolution: {integrity: sha512-SnL6sNutTwRWWR/vcmCYHSADjiEesp5TGQQ0pXyLhW5IoeibRlF/CbSLailbB3CNqJUk9cVJ9dUDnbD7GrcHBQ==} + + mocked-exports@0.1.1: + resolution: {integrity: sha512-aF7yRQr/Q0O2/4pIXm6PZ5G+jAd7QS4Yu8m+WEeEHGnbo+7mE36CbLSDQiXYV8bVL3NfmdeqPJct0tUlnjVSnA==} + + motion-dom@12.35.2: + resolution: {integrity: sha512-pWXFMTwvGDbx1Fe9YL5HZebv2NhvGBzRtiNUv58aoK7+XrsuaydQ0JGRKK2r+bTKlwgSWwWxHbP5249Qr/BNpg==} + + motion-utils@12.29.2: + resolution: {integrity: sha512-G3kc34H2cX2gI63RqU+cZq+zWRRPSsNIOjpdl9TN4AQwC4sgwYPl/Q/Obf/d53nOm569T0fYK+tcoSV50BWx8A==} + + motion-v@1.10.3: + resolution: {integrity: sha512-9Ewo/wwGv7FO3PqYJpllBF/Efc7tbeM1iinVrM73s0RUQrnXHwMZCaRX98u4lu0PQCrZghPPfCsQ14pWKIEbnQ==} + peerDependencies: + '@vueuse/core': '>=10.0.0' + vue: '>=3.0.0' + + motion-v@2.0.0: + resolution: {integrity: sha512-oQuQMrPhti+Zps6OosOaW3b/eqzaGAuwI54XHJKq/dIWtQWcNzfyhTo4VB5xmp7yLN+3BE9FKF6skLsynfgbHQ==} + peerDependencies: + '@vueuse/core': '>=10.0.0' + vue: '>=3.0.0' + + mrmime@2.0.1: + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} + engines: {node: '>=10'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + muggle-string@0.4.1: + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + nanotar@0.2.1: + resolution: {integrity: sha512-MUrzzDUcIOPbv7ubhDV/L4CIfVTATd9XhDE2ixFeCrM5yp9AlzUpn91JrnN0HD6hksdxvz9IW9aKANz0Bta0GA==} + + next@16.1.6: + resolution: {integrity: sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==} + engines: {node: '>=20.9.0'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.51.1 + babel-plugin-react-compiler: '*' + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true + + nitropack@2.13.1: + resolution: {integrity: sha512-2dDj89C4wC2uzG7guF3CnyG+zwkZosPEp7FFBGHB3AJo11AywOolWhyQJFHDzve8COvGxJaqscye9wW2IrUsNw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + xml2js: ^0.6.2 + peerDependenciesMeta: + xml2js: + optional: true + + node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + + node-emoji@2.2.0: + resolution: {integrity: sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==} + engines: {node: '>=18'} + + node-fetch-native@1.6.7: + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-forge@1.3.3: + resolution: {integrity: sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==} + engines: {node: '>= 6.13.0'} + + node-gyp-build@4.8.4: + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} + hasBin: true + + node-mock-http@1.0.4: + resolution: {integrity: sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==} + + node-releases@2.0.36: + resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} + + nopt@8.1.0: + resolution: {integrity: sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==} + engines: {node: ^18.17.0 || >=20.5.0} + hasBin: true + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + npm-run-path@6.0.0: + resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} + engines: {node: '>=18'} + + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + + nuxi@3.33.1: + resolution: {integrity: sha512-DcmovmZxNP9FHi+w4fpvqIUrIDSVDRv0GuoX3IEOB7B1mSsROPhUV1/lAAoRe/DWScXvuXOy27JM95ukSCfTBw==} + engines: {node: ^16.10.0 || >=18.0.0} + hasBin: true + + nuxt-component-meta@0.17.2: + resolution: {integrity: sha512-2/mSSqutOX8t+r8cAX1yUYwAPBqicPO5Rfum3XaHVszxKCF4tXEXBiPGfJY9Zn69x/CIeOdw+aM9wmHzQ5Q+lA==} + hasBin: true + + nuxt-llms@0.2.0: + resolution: {integrity: sha512-GoEW00x8zaZ1wS0R0aOYptt3b54JEaRwlyVtuAiQoH51BwYdjN5/3+00/+4wi39M5cT4j5XcnGwOxJ7v4WVb9A==} + + nuxt@4.3.1: + resolution: {integrity: sha512-bl+0rFcT5Ax16aiWFBFPyWcsTob19NTZaDL5P6t0MQdK63AtgS6fN6fwvwdbXtnTk6/YdCzlmuLzXhSM22h0OA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@parcel/watcher': ^2.1.0 + '@types/node': '>=18.12.0' + peerDependenciesMeta: + '@parcel/watcher': + optional: true + '@types/node': + optional: true + + nypm@0.6.5: + resolution: {integrity: sha512-K6AJy1GMVyfyMXRVB88700BJqNUkByijGJM8kEHpLdcAt+vSQAVfkWWHYzuRXHSY6xA2sNc5RjTj0p9rE2izVQ==} + engines: {node: '>=18'} + hasBin: true + + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + + ofetch@1.5.1: + resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} + + ofetch@2.0.0-alpha.3: + resolution: {integrity: sha512-zpYTCs2byOuft65vI3z43Dd6iSdFbOZZLb9/d21aCpx2rGastVU9dOCv0lu4ykc1Ur1anAYjDi3SUvR0vq50JA==} + + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + + on-change@6.0.2: + resolution: {integrity: sha512-08+12qcOVEA0fS9g/VxKS27HaT94nRutUT77J2dr8zv/unzXopvhBuF8tNLWsoLQ5IgrQ6eptGeGqUYat82U1w==} + engines: {node: '>=20'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + + oniguruma-parser@0.12.1: + resolution: {integrity: sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==} + + oniguruma-to-es@4.3.4: + resolution: {integrity: sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==} + + open@10.2.0: + resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} + engines: {node: '>=18'} + + open@8.4.2: + resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} + engines: {node: '>=12'} + + orderedmap@2.1.1: + resolution: {integrity: sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==} + + oxc-minify@0.112.0: + resolution: {integrity: sha512-rkVSeeIRSt+RYI9uX6xonBpLUpvZyegxIg0UL87ev7YAfUqp7IIZlRjkgQN5Us1lyXD//TOo0Dcuuro/TYOWoQ==} + engines: {node: ^20.19.0 || >=22.12.0} + + oxc-parser@0.112.0: + resolution: {integrity: sha512-7rQ3QdJwobMQLMZwQaPuPYMEF2fDRZwf51lZ//V+bA37nejjKW5ifMHbbCwvA889Y4RLhT+/wLJpPRhAoBaZYw==} + engines: {node: ^20.19.0 || >=22.12.0} + + oxc-transform@0.112.0: + resolution: {integrity: sha512-cIRRvZgrHfsAHrkt8LWdAX4+Do8R0MzQSfeo9yzErzHeYiuyNiP4PCTPbOy/wBXL4MYzt3ebrBa5jt3akQkKAg==} + engines: {node: ^20.19.0 || >=22.12.0} + + oxc-walker@0.7.0: + resolution: {integrity: sha512-54B4KUhrzbzc4sKvKwVYm7E2PgeROpGba0/2nlNZMqfDyca+yOor5IMb4WLGBatGDT0nkzYdYuzylg7n3YfB7A==} + peerDependencies: + oxc-parser: '>=0.98.0' + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + package-manager-detector@1.6.0: + resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} + + pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + + parse-path@7.1.0: + resolution: {integrity: sha512-EuCycjZtfPcjWk7KTksnJ5xPMvWGA/6i4zrLYhRG0hGvC3GPU/jGUj3Cy+ZR0v30duV3e23R95T1lE2+lsndSw==} + + parse-url@9.2.0: + resolution: {integrity: sha512-bCgsFI+GeGWPAvAiUv63ZorMeif3/U0zaXABGJbOWt5OH2KCaPHF6S+0ok4aqM9RuIPGyZdx9tR9l13PsW4AYQ==} + engines: {node: '>=14.13.0'} + + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + + parse5@8.0.0: + resolution: {integrity: sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + + path-data-parser@0.1.0: + resolution: {integrity: sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + path-scurry@2.0.2: + resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} + engines: {node: 18 || 20 || >=22} + + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + perfect-debounce@2.1.0: + resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + pify@4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} + + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + pkg-types@2.3.0: + resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} + + points-on-curve@0.2.0: + resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==} + + points-on-path@0.2.1: + resolution: {integrity: sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==} + + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + + postcss-calc@10.1.1: + resolution: {integrity: sha512-NYEsLHh8DgG/PRH2+G9BTuUdtf9ViS+vdoQ0YA5OQdGsfN4ztiwtDWNtBl9EKeqNMFnIu8IKZ0cLxEQ5r5KVMw==} + engines: {node: ^18.12 || ^20.9 || >=22.0} + peerDependencies: + postcss: ^8.4.38 + + postcss-colormin@7.0.6: + resolution: {integrity: sha512-oXM2mdx6IBTRm39797QguYzVEWzbdlFiMNfq88fCCN1Wepw3CYmJ/1/Ifa/KjWo+j5ZURDl2NTldLJIw51IeNQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-convert-values@7.0.9: + resolution: {integrity: sha512-l6uATQATZaCa0bckHV+r6dLXfWtUBKXxO3jK+AtxxJJtgMPD+VhhPCCx51I4/5w8U5uHV67g3w7PXj+V3wlMlg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-discard-comments@7.0.6: + resolution: {integrity: sha512-Sq+Fzj1Eg5/CPf1ERb0wS1Im5cvE2gDXCE+si4HCn1sf+jpQZxDI4DXEp8t77B/ImzDceWE2ebJQFXdqZ6GRJw==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-discard-duplicates@7.0.2: + resolution: {integrity: sha512-eTonaQvPZ/3i1ASDHOKkYwAybiM45zFIc7KXils4mQmHLqIswXD9XNOKEVxtTFnsmwYzF66u4LMgSr0abDlh5w==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-discard-empty@7.0.1: + resolution: {integrity: sha512-cFrJKZvcg/uxB6Ijr4l6qmn3pXQBna9zyrPC+sK0zjbkDUZew+6xDltSF7OeB7rAtzaaMVYSdbod+sZOCWnMOg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-discard-overridden@7.0.1: + resolution: {integrity: sha512-7c3MMjjSZ/qYrx3uc1940GSOzN1Iqjtlqe8uoSg+qdVPYyRb0TILSqqmtlSFuE4mTDECwsm397Ya7iXGzfF7lg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-merge-longhand@7.0.5: + resolution: {integrity: sha512-Kpu5v4Ys6QI59FxmxtNB/iHUVDn9Y9sYw66D6+SZoIk4QTz1prC4aYkhIESu+ieG1iylod1f8MILMs1Em3mmIw==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-merge-rules@7.0.8: + resolution: {integrity: sha512-BOR1iAM8jnr7zoQSlpeBmCsWV5Uudi/+5j7k05D0O/WP3+OFMPD86c1j/20xiuRtyt45bhxw/7hnhZNhW2mNFA==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-minify-font-values@7.0.1: + resolution: {integrity: sha512-2m1uiuJeTplll+tq4ENOQSzB8LRnSUChBv7oSyFLsJRtUgAAJGP6LLz0/8lkinTgxrmJSPOEhgY1bMXOQ4ZXhQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-minify-gradients@7.0.1: + resolution: {integrity: sha512-X9JjaysZJwlqNkJbUDgOclyG3jZEpAMOfof6PUZjPnPrePnPG62pS17CjdM32uT1Uq1jFvNSff9l7kNbmMSL2A==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-minify-params@7.0.6: + resolution: {integrity: sha512-YOn02gC68JijlaXVuKvFSCvQOhTpblkcfDre2hb/Aaa58r2BIaK4AtE/cyZf2wV7YKAG+UlP9DT+By0ry1E4VQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-minify-selectors@7.0.6: + resolution: {integrity: sha512-lIbC0jy3AAwDxEgciZlBullDiMBeBCT+fz5G8RcA9MWqh/hfUkpOI3vNDUNEZHgokaoiv0juB9Y8fGcON7rU/A==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-normalize-charset@7.0.1: + resolution: {integrity: sha512-sn413ofhSQHlZFae//m9FTOfkmiZ+YQXsbosqOWRiVQncU2BA3daX3n0VF3cG6rGLSFVc5Di/yns0dFfh8NFgQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-normalize-display-values@7.0.1: + resolution: {integrity: sha512-E5nnB26XjSYz/mGITm6JgiDpAbVuAkzXwLzRZtts19jHDUBFxZ0BkXAehy0uimrOjYJbocby4FVswA/5noOxrQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-normalize-positions@7.0.1: + resolution: {integrity: sha512-pB/SzrIP2l50ZIYu+yQZyMNmnAcwyYb9R1fVWPRxm4zcUFCY2ign7rcntGFuMXDdd9L2pPNUgoODDk91PzRZuQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-normalize-repeat-style@7.0.1: + resolution: {integrity: sha512-NsSQJ8zj8TIDiF0ig44Byo3Jk9e4gNt9x2VIlJudnQQ5DhWAHJPF4Tr1ITwyHio2BUi/I6Iv0HRO7beHYOloYQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-normalize-string@7.0.1: + resolution: {integrity: sha512-QByrI7hAhsoze992kpbMlJSbZ8FuCEc1OT9EFbZ6HldXNpsdpZr+YXC5di3UEv0+jeZlHbZcoCADgb7a+lPmmQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-normalize-timing-functions@7.0.1: + resolution: {integrity: sha512-bHifyuuSNdKKsnNJ0s8fmfLMlvsQwYVxIoUBnowIVl2ZAdrkYQNGVB4RxjfpvkMjipqvbz0u7feBZybkl/6NJg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-normalize-unicode@7.0.6: + resolution: {integrity: sha512-z6bwTV84YW6ZvvNoaNLuzRW4/uWxDKYI1iIDrzk6D2YTL7hICApy+Q1LP6vBEsljX8FM7YSuV9qI79XESd4ddQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-normalize-url@7.0.1: + resolution: {integrity: sha512-sUcD2cWtyK1AOL/82Fwy1aIVm/wwj5SdZkgZ3QiUzSzQQofrbq15jWJ3BA7Z+yVRwamCjJgZJN0I9IS7c6tgeQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-normalize-whitespace@7.0.1: + resolution: {integrity: sha512-vsbgFHMFQrJBJKrUFJNZ2pgBeBkC2IvvoHjz1to0/0Xk7sII24T0qFOiJzG6Fu3zJoq/0yI4rKWi7WhApW+EFA==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-ordered-values@7.0.2: + resolution: {integrity: sha512-AMJjt1ECBffF7CEON/Y0rekRLS6KsePU6PRP08UqYW4UGFRnTXNrByUzYK1h8AC7UWTZdQ9O3Oq9kFIhm0SFEw==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-reduce-initial@7.0.6: + resolution: {integrity: sha512-G6ZyK68AmrPdMB6wyeA37ejnnRG2S8xinJrZJnOv+IaRKf6koPAVbQsiC7MfkmXaGmF1UO+QCijb27wfpxuRNg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-reduce-transforms@7.0.1: + resolution: {integrity: sha512-MhyEbfrm+Mlp/36hvZ9mT9DaO7dbncU0CvWI8V93LRkY6IYlu38OPg3FObnuKTUxJ4qA8HpurdQOo5CyqqO76g==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-selector-parser@7.1.1: + resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} + engines: {node: '>=4'} + + postcss-svgo@7.1.1: + resolution: {integrity: sha512-zU9H9oEDrUFKa0JB7w+IYL7Qs9ey1mZyjhbf0KLxwJDdDRtoPvCmaEfknzqfHj44QS9VD6c5sJnBAVYTLRg/Sg==} + engines: {node: ^18.12.0 || ^20.9.0 || >= 18} + peerDependencies: + postcss: ^8.4.32 + + postcss-unique-selectors@7.0.5: + resolution: {integrity: sha512-3QoYmEt4qg/rUWDn6Tc8+ZVPmbp4G1hXDtCNWDx0st8SjtCbRcxRXDDM1QrEiXGG3A45zscSJFb4QH90LViyxg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.5.8: + resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} + engines: {node: ^10 || ^12 || >=14} + + prettier@3.8.1: + resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} + engines: {node: '>=14'} + hasBin: true + + pretty-bytes@7.1.0: + resolution: {integrity: sha512-nODzvTiYVRGRqAOvE84Vk5JDPyyxsVk0/fbA/bq7RqlnhksGpset09XTxbpvLTIjoaF7K8Z8DG8yHtKGTPSYRw==} + engines: {node: '>=20'} + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + + property-information@7.1.0: + resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + + prosemirror-changeset@2.4.0: + resolution: {integrity: sha512-LvqH2v7Q2SF6yxatuPP2e8vSUKS/L+xAU7dPDC4RMyHMhZoGDfBC74mYuyYF4gLqOEG758wajtyhNnsTkuhvng==} + + prosemirror-collab@1.3.1: + resolution: {integrity: sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==} + + prosemirror-commands@1.7.1: + resolution: {integrity: sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==} + + prosemirror-dropcursor@1.8.2: + resolution: {integrity: sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==} + + prosemirror-gapcursor@1.4.1: + resolution: {integrity: sha512-pMdYaEnjNMSwl11yjEGtgTmLkR08m/Vl+Jj443167p9eB3HVQKhYCc4gmHVDsLPODfZfjr/MmirsdyZziXbQKw==} + + prosemirror-history@1.5.0: + resolution: {integrity: sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==} + + prosemirror-inputrules@1.5.1: + resolution: {integrity: sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw==} + + prosemirror-keymap@1.2.3: + resolution: {integrity: sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==} + + prosemirror-markdown@1.13.4: + resolution: {integrity: sha512-D98dm4cQ3Hs6EmjK500TdAOew4Z03EV71ajEFiWra3Upr7diytJsjF4mPV2dW+eK5uNectiRj0xFxYI9NLXDbw==} + + prosemirror-menu@1.3.0: + resolution: {integrity: sha512-TImyPXCHPcDsSka2/lwJ6WjTASr4re/qWq1yoTTuLOqfXucwF6VcRa2LWCkM/EyTD1UO3CUwiH8qURJoWJRxwg==} + + prosemirror-model@1.25.4: + resolution: {integrity: sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA==} + + prosemirror-schema-basic@1.2.4: + resolution: {integrity: sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ==} + + prosemirror-schema-list@1.5.1: + resolution: {integrity: sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==} + + prosemirror-state@1.4.4: + resolution: {integrity: sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==} + + prosemirror-tables@1.8.5: + resolution: {integrity: sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw==} + + prosemirror-trailing-node@3.0.0: + resolution: {integrity: sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==} + peerDependencies: + prosemirror-model: ^1.22.1 + prosemirror-state: ^1.4.2 + prosemirror-view: ^1.33.8 + + prosemirror-transform@1.11.0: + resolution: {integrity: sha512-4I7Ce4KpygXb9bkiPS3hTEk4dSHorfRw8uI0pE8IhxlK2GXsqv5tIA7JUSxtSu7u8APVOTtbUBxTmnHIxVkIJw==} + + prosemirror-view@1.41.6: + resolution: {integrity: sha512-mxpcDG4hNQa/CPtzxjdlir5bJFDlm0/x5nGBbStB2BWX+XOQ9M8ekEG+ojqB5BcVu2Rc80/jssCMZzSstJuSYg==} + + protocols@2.0.2: + resolution: {integrity: sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==} + + punycode.js@2.3.1: + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} + + quansync@0.2.11: + resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + radix3@1.1.2: + resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} + + randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + rc9@2.1.2: + resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} + + rc9@3.0.0: + resolution: {integrity: sha512-MGOue0VqscKWQ104udASX/3GYDcKyPI4j4F8gu/jHHzglpmy9a/anZK3PNe8ug6aZFl+9GxLtdhe3kVZuMaQbA==} + + react-dom@19.2.4: + resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} + peerDependencies: + react: ^19.2.4 + + react@19.2.4: + resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} + engines: {node: '>=0.10.0'} + + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + readable-stream@4.7.0: + resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + readdir-glob@1.1.3: + resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} + + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + readdirp@5.0.0: + resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} + engines: {node: '>= 20.19.0'} + + redis-errors@1.2.0: + resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} + engines: {node: '>=4'} + + redis-parser@3.0.0: + resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==} + engines: {node: '>=4'} + + regex-recursion@6.0.2: + resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} + + regex-utilities@2.3.0: + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} + + regex@6.1.0: + resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==} + + regexp-tree@0.1.27: + resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} + hasBin: true + + rehype-external-links@3.0.0: + resolution: {integrity: sha512-yp+e5N9V3C6bwBeAC4n796kc86M4gJCdlVhiMTxIrJG5UHDMh+PJANf9heqORJbt1nrCbDwIlAZKjANIaVBbvw==} + + rehype-minify-whitespace@6.0.2: + resolution: {integrity: sha512-Zk0pyQ06A3Lyxhe9vGtOtzz3Z0+qZ5+7icZ/PL/2x1SHPbKao5oB/g/rlc6BCTajqBb33JcOe71Ye1oFsuYbnw==} + + rehype-raw@7.0.0: + resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==} + + rehype-remark@10.0.1: + resolution: {integrity: sha512-EmDndlb5NVwXGfUa4c9GPK+lXeItTilLhE6ADSaQuHr4JUlKw9MidzGzx4HpqZrNCt6vnHmEifXQiiA+CEnjYQ==} + + rehype-slug@6.0.0: + resolution: {integrity: sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==} + + rehype-sort-attribute-values@5.0.1: + resolution: {integrity: sha512-lU3ABJO5frbUgV132YS6SL7EISf//irIm9KFMaeu5ixHfgWf6jhe+09Uf/Ef8pOYUJWKOaQJDRJGCXs6cNsdsQ==} + + rehype-sort-attributes@5.0.1: + resolution: {integrity: sha512-Bxo+AKUIELcnnAZwJDt5zUDDRpt4uzhfz9d0PVGhcxYWsbFj5Cv35xuWxu5r1LeYNFNhgGqsr9Q2QiIOM/Qctg==} + + reka-ui@2.8.2: + resolution: {integrity: sha512-8lTKcJhmG+D3UyJxhBnNnW/720sLzm0pbA9AC1MWazmJ5YchJAyTSl+O00xP/kxBmEN0fw5JqWVHguiFmsGjzA==} + peerDependencies: + vue: '>= 3.2.0' + + remark-emoji@5.0.2: + resolution: {integrity: sha512-IyIqGELcyK5AVdLFafoiNww+Eaw/F+rGrNSXoKucjo95uL267zrddgxGM83GN1wFIb68pyDuAsY3m5t2Cav1pQ==} + engines: {node: '>=18'} + + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + + remark-mdc@3.10.0: + resolution: {integrity: sha512-gJhrSs4bGyqr7eSuLoaLlpmiDZrJ9fP/8gTA/w1CnKnW/mfxc9VKM+ndzpOxHQnpAU4tjD8QqF6SMLiOvIVTYA==} + + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-rehype@11.1.2: + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} + hasBin: true + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + robust-predicates@3.0.2: + resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + + rollup-plugin-visualizer@6.0.11: + resolution: {integrity: sha512-TBwVHVY7buHjIKVLqr9scTVFwqZqMXINcCphPwIWKPDCOBIa+jCQfafvbjRJDZgXdq/A996Dy6yGJ/+/NtAXDQ==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + rolldown: 1.x || ^1.0.0-beta + rollup: 2.x || 3.x || 4.x + peerDependenciesMeta: + rolldown: + optional: true + rollup: + optional: true + + rollup@4.59.0: + resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + rope-sequence@1.3.4: + resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==} + + rou3@0.7.12: + resolution: {integrity: sha512-iFE4hLDuloSWcD7mjdCDhx2bKcIsYbtOTpfH5MHHLSKMOUyjqQXTeZVa289uuwEGEKFoE/BAPbhaU4B774nceg==} + + roughjs@4.6.6: + resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==} + + run-applescript@7.1.0: + resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} + engines: {node: '>=18'} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + rw@1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + sax@1.5.0: + resolution: {integrity: sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==} + engines: {node: '>=11.0.0'} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + scule@1.3.0: + resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + engines: {node: '>=10'} + hasBin: true + + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + + serialize-javascript@6.0.2: + resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + + seroval@1.5.1: + resolution: {integrity: sha512-OwrZRZAfhHww0WEnKHDY8OM0U/Qs8OTfIDWhUD4BLpNJUfXK4cGmjiagGze086m+mhI+V2nD0gfbHEnJjb9STA==} + engines: {node: '>=10'} + + serve-placeholder@2.0.2: + resolution: {integrity: sha512-/TMG8SboeiQbZJWRlfTCqMs2DD3SZgWp0kDQePz9yUuCnDfDh/92gf7/PxGhzXTKBIPASIHxFcZndoNbp6QOLQ==} + + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + sha.js@2.4.12: + resolution: {integrity: sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==} + engines: {node: '>= 0.10'} + hasBin: true + + shaders@2.3.75: + resolution: {integrity: sha512-j68fkmrmPy0RnNTjvO2r4kpnGh2HBws70M8IHTiO54H+Rv6cClFZCCFz6l7dKeYp3aLR+UQstsijlWPOyi5K2Q==} + peerDependencies: + pixi.js: ^8.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + solid-js: ^1.8.0 + svelte: ^5 + vue: ^3.0.0 + peerDependenciesMeta: + pixi.js: + optional: true + react: + optional: true + react-dom: + optional: true + solid-js: + optional: true + svelte: + optional: true + vue: + optional: true + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + shell-quote@1.8.3: + resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} + engines: {node: '>= 0.4'} + + shiki@3.23.0: + resolution: {integrity: sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA==} + + shiki@4.0.2: + resolution: {integrity: sha512-eAVKTMedR5ckPo4xne/PjYQYrU3qx78gtJZ+sHlXEg5IHhhoQhMfZVzetTYuaJS0L2Ef3AcCRzCHV8T0WI6nIQ==} + engines: {node: '>=20'} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + + simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + + simple-git@3.33.0: + resolution: {integrity: sha512-D4V/tGC2sjsoNhoMybKyGoE+v8A60hRawKQ1iFRA1zwuDgGZCBJ4ByOzZ5J8joBbi4Oam0qiPH+GhzmSBwbJng==} + + sirv@3.0.2: + resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} + engines: {node: '>=18'} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + skin-tone@2.0.0: + resolution: {integrity: sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==} + engines: {node: '>=8'} + + slash@5.1.0: + resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} + engines: {node: '>=14.16'} + + slugify@1.6.6: + resolution: {integrity: sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==} + engines: {node: '>=8.0.0'} + + smob@1.6.1: + resolution: {integrity: sha512-KAkBqZl3c2GvNgNhcoyJae1aKldDW0LO279wF9bk1PnluRTETKBq0WyzRXxEhoQLk56yHaOY4JCBEKDuJIET5g==} + engines: {node: '>=20.0.0'} + + socket.io-client@4.8.3: + resolution: {integrity: sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g==} + engines: {node: '>=10.0.0'} + + socket.io-parser@4.2.5: + resolution: {integrity: sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ==} + engines: {node: '>=10.0.0'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + + srvx@0.11.9: + resolution: {integrity: sha512-97wWJS6F0KTKAhDlHVmBzMvlBOp5FiNp3XrLoodIgYJpXxgG5tE9rX4Pg7s46n2shI4wtEsMATTS1+rI3/ubzA==} + engines: {node: '>=20.16.0'} + hasBin: true + + standard-as-callback@2.1.0: + resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} + + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + + streamx@2.23.0: + resolution: {integrity: sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + + strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + + strip-literal@3.1.0: + resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} + + structured-clone-es@1.0.0: + resolution: {integrity: sha512-FL8EeKFFyNQv5cMnXI31CIMCsFarSVI2bF0U0ImeNE3g/F1IvJQyqzOXxPBRXiwQfyBTlbNe88jh1jFW0O/jiQ==} + + styled-jsx@5.1.6: + resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + + stylehacks@7.0.8: + resolution: {integrity: sha512-I3f053GBLIiS5Fg6OMFhq/c+yW+5Hc2+1fgq7gElDMMSqwlRb3tBf2ef6ucLStYRpId4q//bQO1FjcyNyy4yDQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + stylis@4.3.6: + resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==} + + supports-color@10.2.2: + resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} + engines: {node: '>=18'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + svgo@4.0.1: + resolution: {integrity: sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==} + engines: {node: '>=16'} + hasBin: true + + system-architecture@0.1.0: + resolution: {integrity: sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA==} + engines: {node: '>=18'} + + tagged-tag@1.0.0: + resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} + engines: {node: '>=20'} + + tailwind-merge@3.5.0: + resolution: {integrity: sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==} + + tailwind-variants@3.2.2: + resolution: {integrity: sha512-Mi4kHeMTLvKlM98XPnK+7HoBPmf4gygdFmqQPaDivc3DpYS6aIY6KiG/PgThrGvii5YZJqRsPz0aPyhoFzmZgg==} + engines: {node: '>=16.x', pnpm: '>=7.x'} + peerDependencies: + tailwind-merge: '>=3.0.0' + tailwindcss: '*' + peerDependenciesMeta: + tailwind-merge: + optional: true + + tailwindcss@4.2.1: + resolution: {integrity: sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==} + + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + engines: {node: '>=6'} + + tar-stream@3.1.8: + resolution: {integrity: sha512-U6QpVRyCGHva435KoNWy9PRoi2IFYCgtEhq9nmrPPpbRacPs9IH4aJ3gbrFC8dPcXvdSZ4XXfXT5Fshbp2MtlQ==} + + tar@7.5.11: + resolution: {integrity: sha512-ChjMH33/KetonMTAtpYdgUFr0tbz69Fp2v7zWxQfYZX4g5ZN2nOBXm1R2xyA+lMIKrLKIoKAwFj93jE/avX9cQ==} + engines: {node: '>=18'} + + teex@1.0.1: + resolution: {integrity: sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==} + + terser@5.46.0: + resolution: {integrity: sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==} + engines: {node: '>=10'} + hasBin: true + + text-decoder@1.2.7: + resolution: {integrity: sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==} + + three@0.183.2: + resolution: {integrity: sha512-di3BsL2FEQ1PA7Hcvn4fyJOlxRRgFYBpMTcyOgkwJIaDOdJMebEFPA+t98EvjuljDx4hNulAGwF6KIjtwI5jgQ==} + + tiny-inflate@1.0.3: + resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} + + tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + + tinyexec@1.0.2: + resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + engines: {node: '>=18'} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + to-buffer@1.2.2: + resolution: {integrity: sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==} + engines: {node: '>= 0.4'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + totalist@3.0.1: + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} + engines: {node: '>=6'} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + trim-trailing-lines@2.1.0: + resolution: {integrity: sha512-5UR5Biq4VlVOtzqkm2AZlgvSlDJtME46uV0br0gENbwN4l5+mMKT4b9gJKqWtuL2zAIqajGJGuvbCbcAJUZqBg==} + + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + + ts-dedent@2.2.0: + resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} + engines: {node: '>=6.10'} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-fest@5.4.4: + resolution: {integrity: sha512-JnTrzGu+zPV3aXIUhnyWJj4z/wigMsdYajGLIYakqyOW1nPllzXEJee0QQbHj+CTIQtXGlAjuK0UY+2xTyjVAw==} + engines: {node: '>=20'} + + type-level-regexp@0.1.17: + resolution: {integrity: sha512-wTk4DH3cxwk196uGLK/E9pE45aLfeKJacKmcEgEOA/q5dnPGNxXt0cfYdFxb57L+sEpf1oJH4Dnx/pnRcku9jg==} + + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + uc.micro@2.1.0: + resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + + ufo@1.6.3: + resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} + + ultrahtml@1.6.0: + resolution: {integrity: sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==} + + uncrypto@0.1.3: + resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} + + unctx@2.5.0: + resolution: {integrity: sha512-p+Rz9x0R7X+CYDkT+Xg8/GhpcShTlU8n+cf9OtOEf7zEQsNcCZO1dPKNRDqvUTaq+P32PMMkxWHwfrxkqfqAYg==} + + undocs-nightly@0.4.17-20260310-213525-c3c295a: + resolution: {integrity: sha512-e5mrhsll9v+u0rkbt0QxoIDLJHmwtV0yGUwu8J5UcHr6n2fVFhZFr2QEmeX6s8PKemtLOIzB0tOmLl422/hmQQ==} + hasBin: true + + unenv@2.0.0-rc.24: + resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==} + + unhead@2.1.12: + resolution: {integrity: sha512-iTHdWD9ztTunOErtfUFk6Wr11BxvzumcYJ0CzaSCBUOEtg+DUZ9+gnE99i8QkLFT2q1rZD48BYYGXpOZVDLYkA==} + + unicode-emoji-modifier-base@1.0.0: + resolution: {integrity: sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==} + engines: {node: '>=4'} + + unicorn-magic@0.3.0: + resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} + engines: {node: '>=18'} + + unicorn-magic@0.4.0: + resolution: {integrity: sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==} + engines: {node: '>=20'} + + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unifont@0.7.4: + resolution: {integrity: sha512-oHeis4/xl42HUIeHuNZRGEvxj5AaIKR+bHPNegRq5LV1gdc3jundpONbjglKpihmJf+dswygdMJn3eftGIMemg==} + + unimport@5.7.0: + resolution: {integrity: sha512-njnL6sp8lEA8QQbZrt+52p/g4X0rw3bnGGmUcJnt1jeG8+iiqO779aGz0PirCtydAIVcuTBRlJ52F0u46z309Q==} + engines: {node: '>=18.12.0'} + + unist-builder@4.0.0: + resolution: {integrity: sha512-wmRFnH+BLpZnTKpc5L7O67Kac89s9HMrtELpnNaE6TAobq5DTZZs5YaTQfAZBA9bFPECx2uVAPO31c+GVug8mg==} + + unist-util-find-after@5.0.0: + resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + + unplugin-auto-import@21.0.0: + resolution: {integrity: sha512-vWuC8SwqJmxZFYwPojhOhOXDb5xFhNNcEVb9K/RFkyk/3VnfaOjzitWN7v+8DEKpMjSsY2AEGXNgt6I0yQrhRQ==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@nuxt/kit': ^4.0.0 + '@vueuse/core': '*' + peerDependenciesMeta: + '@nuxt/kit': + optional: true + '@vueuse/core': + optional: true + + unplugin-utils@0.3.1: + resolution: {integrity: sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==} + engines: {node: '>=20.19.0'} + + unplugin-vue-components@31.0.0: + resolution: {integrity: sha512-4ULwfTZTLuWJ7+S9P7TrcStYLsSRkk6vy2jt/WTfgUEUb0nW9//xxmrfhyHUEVpZ2UKRRwfRb8Yy15PDbVZf+Q==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@nuxt/kit': ^3.2.2 || ^4.0.0 + vue: ^3.0.0 + peerDependenciesMeta: + '@nuxt/kit': + optional: true + + unplugin-vue-router@0.19.2: + resolution: {integrity: sha512-u5dgLBarxE5cyDK/hzJGfpCTLIAyiTXGlo85COuD4Nssj6G7NxS+i9mhCWz/1p/ud1eMwdcUbTXehQe41jYZUA==} + deprecated: 'Merged into vuejs/router. Migrate: https://router.vuejs.org/guide/migration/v4-to-v5.html' + peerDependencies: + '@vue/compiler-sfc': ^3.5.17 + vue-router: ^4.6.0 + peerDependenciesMeta: + vue-router: + optional: true + + unplugin@2.3.11: + resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} + engines: {node: '>=18.12.0'} + + unplugin@3.0.0: + resolution: {integrity: sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==} + engines: {node: ^20.19.0 || >=22.12.0} + + unstorage@1.17.4: + resolution: {integrity: sha512-fHK0yNg38tBiJKp/Vgsq4j0JEsCmgqH58HAn707S7zGkArbZsVr/CwINoi+nh3h98BRCwKvx1K3Xg9u3VV83sw==} + peerDependencies: + '@azure/app-configuration': ^1.8.0 + '@azure/cosmos': ^4.2.0 + '@azure/data-tables': ^13.3.0 + '@azure/identity': ^4.6.0 + '@azure/keyvault-secrets': ^4.9.0 + '@azure/storage-blob': ^12.26.0 + '@capacitor/preferences': ^6 || ^7 || ^8 + '@deno/kv': '>=0.9.0' + '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0 + '@planetscale/database': ^1.19.0 + '@upstash/redis': ^1.34.3 + '@vercel/blob': '>=0.27.1' + '@vercel/functions': ^2.2.12 || ^3.0.0 + '@vercel/kv': ^1 || ^2 || ^3 + aws4fetch: ^1.0.20 + db0: '>=0.2.1' + idb-keyval: ^6.2.1 + ioredis: ^5.4.2 + uploadthing: ^7.4.4 + peerDependenciesMeta: + '@azure/app-configuration': + optional: true + '@azure/cosmos': + optional: true + '@azure/data-tables': + optional: true + '@azure/identity': + optional: true + '@azure/keyvault-secrets': + optional: true + '@azure/storage-blob': + optional: true + '@capacitor/preferences': + optional: true + '@deno/kv': + optional: true + '@netlify/blobs': + optional: true + '@planetscale/database': + optional: true + '@upstash/redis': + optional: true + '@vercel/blob': + optional: true + '@vercel/functions': + optional: true + '@vercel/kv': + optional: true + aws4fetch: + optional: true + db0: + optional: true + idb-keyval: + optional: true + ioredis: + optional: true + uploadthing: + optional: true + + untun@0.1.3: + resolution: {integrity: sha512-4luGP9LMYszMRZwsvyUd9MrxgEGZdZuZgpVQHEEX0lCYFESasVRvZd0EYpCkOIbJKHMuv0LskpXc/8Un+MJzEQ==} + hasBin: true + + untyped@2.0.0: + resolution: {integrity: sha512-nwNCjxJTjNuLCgFr42fEak5OcLuB3ecca+9ksPFNvtfYSLpjf+iJqSIaSnIile6ZPbKYxI5k2AfXqeopGudK/g==} + hasBin: true + + unwasm@0.5.3: + resolution: {integrity: sha512-keBgTSfp3r6+s9ZcSma+0chwxQdmLbB5+dAD9vjtB21UTMYuKAxHXCU1K2CbCtnP09EaWeRvACnXk0EJtUx+hw==} + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uqr@0.1.2: + resolution: {integrity: sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + uuid@11.1.0: + resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} + hasBin: true + + vaul-vue@0.4.1: + resolution: {integrity: sha512-A6jOWOZX5yvyo1qMn7IveoWN91mJI5L3BUKsIwkg6qrTGgHs1Sb1JF/vyLJgnbN1rH4OOOxFbtqL9A46bOyGUQ==} + peerDependencies: + reka-ui: ^2.0.0 + vue: ^3.3.0 + + vfile-location@5.0.3: + resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + + vite-dev-rpc@1.1.0: + resolution: {integrity: sha512-pKXZlgoXGoE8sEKiKJSng4hI1sQ4wi5YT24FCrwrLt6opmkjlqPPVmiPWWJn8M8byMxRGzp1CrFuqQs4M/Z39A==} + peerDependencies: + vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1 || ^7.0.0-0 + + vite-hot-client@2.1.0: + resolution: {integrity: sha512-7SpgZmU7R+dDnSmvXE1mfDtnHLHQSisdySVR7lO8ceAXvM0otZeuQQ6C8LrS5d/aYyP/QZ0hI0L+dIPrm4YlFQ==} + peerDependencies: + vite: ^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 + + vite-node@5.3.0: + resolution: {integrity: sha512-8f20COPYJujc3OKPX6OuyBy3ZIv2det4eRRU4GY1y2MjbeGSUmPjedxg1b72KnTagCofwvZ65ThzjxDW2AtQFQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + vite-plugin-checker@0.12.0: + resolution: {integrity: sha512-CmdZdDOGss7kdQwv73UyVgLPv0FVYe5czAgnmRX2oKljgEvSrODGuClaV3PDR2+3ou7N/OKGauDDBjy2MB07Rg==} + engines: {node: '>=16.11'} + peerDependencies: + '@biomejs/biome': '>=1.7' + eslint: '>=9.39.1' + meow: ^13.2.0 + optionator: ^0.9.4 + oxlint: '>=1' + stylelint: '>=16' + typescript: '*' + vite: '>=5.4.21' + vls: '*' + vti: '*' + vue-tsc: ~2.2.10 || ^3.0.0 + peerDependenciesMeta: + '@biomejs/biome': + optional: true + eslint: + optional: true + meow: + optional: true + optionator: + optional: true + oxlint: + optional: true + stylelint: + optional: true + typescript: + optional: true + vls: + optional: true + vti: + optional: true + vue-tsc: + optional: true + + vite-plugin-inspect@11.3.3: + resolution: {integrity: sha512-u2eV5La99oHoYPHE6UvbwgEqKKOQGz86wMg40CCosP6q8BkB6e5xPneZfYagK4ojPJSj5anHCrnvC20DpwVdRA==} + engines: {node: '>=14'} + peerDependencies: + '@nuxt/kit': '*' + vite: ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + '@nuxt/kit': + optional: true + + vite-plugin-vue-tracer@1.2.0: + resolution: {integrity: sha512-a9Z/TLpxwmoE9kIcv28wqQmiszM7ec4zgndXWEsVD/2lEZLRGzcg7ONXmplzGF/UP5W59QNtS809OdywwpUWQQ==} + peerDependencies: + vite: ^6.0.0 || ^7.0.0 + vue: ^3.5.0 + + vite@7.3.1: + resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vscode-jsonrpc@8.2.0: + resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} + engines: {node: '>=14.0.0'} + + vscode-languageserver-protocol@3.17.5: + resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} + + vscode-languageserver-textdocument@1.0.12: + resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} + + vscode-languageserver-types@3.17.5: + resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} + + vscode-languageserver@9.0.1: + resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} + hasBin: true + + vscode-uri@3.1.0: + resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + + vue-bundle-renderer@2.2.0: + resolution: {integrity: sha512-sz/0WEdYH1KfaOm0XaBmRZOWgYTEvUDt6yPYaUzl4E52qzgWLlknaPPTTZmp6benaPTlQAI/hN1x3tAzZygycg==} + + vue-component-meta@3.2.5: + resolution: {integrity: sha512-i7v7S6atD9aZZPouwceJoqcmBzjI4uRIxOj5dDcBPiIhFoY+U5kmy7PnEaAOh/iilJQI7I8F3lKdyZmRdplUpA==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + vue-component-type-helpers@3.2.5: + resolution: {integrity: sha512-tkvNr+bU8+xD/onAThIe7CHFvOJ/BO6XCOrxMzeytJq40nTfpGDJuVjyCM8ccGZKfAbGk2YfuZyDMXM56qheZQ==} + + vue-demi@0.14.10: + resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} + engines: {node: '>=12'} + hasBin: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + + vue-devtools-stub@0.1.0: + resolution: {integrity: sha512-RutnB7X8c5hjq39NceArgXg28WZtZpGc3+J16ljMiYnFhKvd8hITxSWQSQ5bvldxMDU6gG5mkxl1MTQLXckVSQ==} + + vue-router@4.6.4: + resolution: {integrity: sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==} + peerDependencies: + vue: ^3.5.0 + + vue@3.5.30: + resolution: {integrity: sha512-hTHLc6VNZyzzEH/l7PFGjpcTvUgiaPK5mdLkbjrTeWSRcEfxFrv56g/XckIYlE9ckuobsdwqd5mk2g1sBkMewg==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + w3c-keyname@2.2.8: + resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + + web-namespaces@2.0.1: + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + wheel-gestures@2.2.48: + resolution: {integrity: sha512-f+Gy33Oa5Z14XY9679Zze+7VFhbsQfBFXodnU2x589l4kxGM9L5Y8zETTmcMR5pWOPQyRv4Z0lNax6xCO0NSlA==} + engines: {node: '>=18'} + + which-typed-array@1.1.20: + resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==} + engines: {node: '>= 0.4'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + which@5.0.0: + resolution: {integrity: sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==} + engines: {node: ^18.17.0 || >=20.5.0} + hasBin: true + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@8.18.3: + resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + ws@8.19.0: + resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + wsl-utils@0.1.0: + resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==} + engines: {node: '>=18'} + + xmlhttprequest-ssl@2.1.2: + resolution: {integrity: sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==} + engines: {node: '>=0.4.0'} + + y-protocols@1.0.7: + resolution: {integrity: sha512-YSVsLoXxO67J6eE/nV4AtFtT3QEotZf5sK5BHxFBXso7VDUT3Tx07IfA6hsu5Q5OmBdMkQVmFZ9QOA7fikWvnw==} + engines: {node: '>=16.0.0', npm: '>=8.0.0'} + peerDependencies: + yjs: ^13.0.0 + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + + yaml@2.8.2: + resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} + engines: {node: '>= 14.6'} + hasBin: true + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yjs@13.6.29: + resolution: {integrity: sha512-kHqDPdltoXH+X4w1lVmMtddE3Oeqq48nM40FD5ojTd8xYhQpzIDcfE2keMSU5bAgRPJBe225WTUdyUgj1DtbiQ==} + engines: {node: '>=16.0.0', npm: '>=8.0.0'} + + youch-core@0.3.3: + resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==} + + youch@4.1.0: + resolution: {integrity: sha512-cYekNh2tUoU+voS11X0D0UQntVCSO6LQ1h10VriQGmfbpf0mnGTruwZICts23UUNiZCXm8H8hQBtRrdsbhuNNg==} + + zip-stream@6.0.1: + resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} + engines: {node: '>= 14'} + + zod-to-json-schema@3.25.1: + resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==} + peerDependencies: + zod: ^3.25 || ^4 + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + + zod@4.3.6: + resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +snapshots: + + '@alloc/quick-lru@5.2.0': {} + + '@antfu/install-pkg@1.1.0': + dependencies: + package-manager-detector: 1.6.0 + tinyexec: 1.0.2 + + '@apidevtools/json-schema-ref-parser@11.9.3': + dependencies: + '@jsdevtools/ono': 7.1.3 + '@types/json-schema': 7.0.15 + js-yaml: 4.1.1 + + '@babel/code-frame@7.29.0': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.0': {} + + '@babel/core@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helpers': 7.28.6 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.1': + dependencies: + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-annotate-as-pure@7.27.3': + dependencies: + '@babel/types': 7.29.0 + + '@babel/helper-compilation-targets@7.28.6': + dependencies: + '@babel/compat-data': 7.29.0 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.1 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/traverse': 7.29.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-member-expression-to-functions@7.28.5': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-imports@7.28.6': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-optimise-call-expression@7.27.1': + dependencies: + '@babel/types': 7.29.0 + + '@babel/helper-plugin-utils@7.28.6': {} + + '@babel/helper-replace-supers@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.28.6': + dependencies: + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + + '@babel/parser@7.29.0': + dependencies: + '@babel/types': 7.29.0 + + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/runtime@7.28.6': {} + + '@babel/template@7.28.6': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + + '@babel/traverse@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@bomb.sh/tab@0.0.12(cac@6.7.14)(citty@0.2.1)': + optionalDependencies: + cac: 6.7.14 + citty: 0.2.1 + + '@braintree/sanitize-url@7.1.2': {} + + '@capsizecss/unpack@4.0.0': + dependencies: + fontkitten: 1.0.3 + + '@chevrotain/cst-dts-gen@11.1.2': + dependencies: + '@chevrotain/gast': 11.1.2 + '@chevrotain/types': 11.1.2 + lodash-es: 4.17.23 + + '@chevrotain/gast@11.1.2': + dependencies: + '@chevrotain/types': 11.1.2 + lodash-es: 4.17.23 + + '@chevrotain/regexp-to-ast@11.1.2': {} + + '@chevrotain/types@11.1.2': {} + + '@chevrotain/utils@11.1.2': {} + + '@clack/core@1.1.0': + dependencies: + sisteransi: 1.0.5 + + '@clack/prompts@1.1.0': + dependencies: + '@clack/core': 1.1.0 + sisteransi: 1.0.5 + + '@cloudflare/kv-asset-handler@0.4.2': {} + + '@dxup/nuxt@0.3.2(magicast@0.5.2)': + dependencies: + '@dxup/unimport': 0.1.2 + '@nuxt/kit': 4.3.1(magicast@0.5.2) + chokidar: 5.0.0 + pathe: 2.0.3 + tinyglobby: 0.2.15 + transitivePeerDependencies: + - magicast + + '@dxup/unimport@0.1.2': {} + + '@emnapi/core@1.8.1': + dependencies: + '@emnapi/wasi-threads': 1.1.0 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.8.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.1.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@esbuild/aix-ppc64@0.27.3': + optional: true + + '@esbuild/android-arm64@0.27.3': + optional: true + + '@esbuild/android-arm@0.27.3': + optional: true + + '@esbuild/android-x64@0.27.3': + optional: true + + '@esbuild/darwin-arm64@0.27.3': + optional: true + + '@esbuild/darwin-x64@0.27.3': + optional: true + + '@esbuild/freebsd-arm64@0.27.3': + optional: true + + '@esbuild/freebsd-x64@0.27.3': + optional: true + + '@esbuild/linux-arm64@0.27.3': + optional: true + + '@esbuild/linux-arm@0.27.3': + optional: true + + '@esbuild/linux-ia32@0.27.3': + optional: true + + '@esbuild/linux-loong64@0.27.3': + optional: true + + '@esbuild/linux-mips64el@0.27.3': + optional: true + + '@esbuild/linux-ppc64@0.27.3': + optional: true + + '@esbuild/linux-riscv64@0.27.3': + optional: true + + '@esbuild/linux-s390x@0.27.3': + optional: true + + '@esbuild/linux-x64@0.27.3': + optional: true + + '@esbuild/netbsd-arm64@0.27.3': + optional: true + + '@esbuild/netbsd-x64@0.27.3': + optional: true + + '@esbuild/openbsd-arm64@0.27.3': + optional: true + + '@esbuild/openbsd-x64@0.27.3': + optional: true + + '@esbuild/openharmony-arm64@0.27.3': + optional: true + + '@esbuild/sunos-x64@0.27.3': + optional: true + + '@esbuild/win32-arm64@0.27.3': + optional: true + + '@esbuild/win32-ia32@0.27.3': + optional: true + + '@esbuild/win32-x64@0.27.3': + optional: true + + '@floating-ui/core@1.7.5': + dependencies: + '@floating-ui/utils': 0.2.11 + + '@floating-ui/dom@1.7.6': + dependencies: + '@floating-ui/core': 1.7.5 + '@floating-ui/utils': 0.2.11 + + '@floating-ui/utils@0.2.11': {} + + '@floating-ui/vue@1.1.11(vue@3.5.30(typescript@5.9.3))': + dependencies: + '@floating-ui/dom': 1.7.6 + '@floating-ui/utils': 0.2.11 + vue-demi: 0.14.10(vue@3.5.30(typescript@5.9.3)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@headlessui/vue@1.7.23(vue@3.5.30(typescript@5.9.3))': + dependencies: + '@tanstack/vue-virtual': 3.13.21(vue@3.5.30(typescript@5.9.3)) + vue: 3.5.30(typescript@5.9.3) + + '@iconify/collections@1.0.659': + dependencies: + '@iconify/types': 2.0.0 + + '@iconify/types@2.0.0': {} + + '@iconify/utils@3.1.0': + dependencies: + '@antfu/install-pkg': 1.1.0 + '@iconify/types': 2.0.0 + mlly: 1.8.1 + + '@iconify/vue@5.0.0(vue@3.5.30(typescript@5.9.3))': + dependencies: + '@iconify/types': 2.0.0 + vue: 3.5.30(typescript@5.9.3) + + '@img/colour@1.1.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.8.1 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@internationalized/date@3.12.0': + dependencies: + '@swc/helpers': 0.5.19 + + '@internationalized/number@3.6.5': + dependencies: + '@swc/helpers': 0.5.19 + + '@ioredis/commands@1.5.1': {} + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.2.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.3 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/source-map@0.3.11': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@jsdevtools/ono@7.1.3': {} + + '@kwsites/file-exists@1.1.1': + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@kwsites/promise-deferred@1.1.1': {} + + '@mapbox/node-pre-gyp@2.0.3': + dependencies: + consola: 3.4.2 + detect-libc: 2.1.2 + https-proxy-agent: 7.0.6 + node-fetch: 2.7.0 + nopt: 8.1.0 + semver: 7.7.4 + tar: 7.5.11 + transitivePeerDependencies: + - encoding + - supports-color + + '@mermaid-js/parser@1.0.1': + dependencies: + langium: 4.2.1 + + '@napi-rs/wasm-runtime@1.1.1': + dependencies: + '@emnapi/core': 1.8.1 + '@emnapi/runtime': 1.8.1 + '@tybys/wasm-util': 0.10.1 + optional: true + + '@next/env@16.1.6': {} + + '@next/swc-darwin-arm64@16.1.6': + optional: true + + '@next/swc-darwin-x64@16.1.6': + optional: true + + '@next/swc-linux-arm64-gnu@16.1.6': + optional: true + + '@next/swc-linux-arm64-musl@16.1.6': + optional: true + + '@next/swc-linux-x64-gnu@16.1.6': + optional: true + + '@next/swc-linux-x64-musl@16.1.6': + optional: true + + '@next/swc-win32-arm64-msvc@16.1.6': + optional: true + + '@next/swc-win32-x64-msvc@16.1.6': + optional: true + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.20.1 + + '@nuxt/cli@3.33.1(@nuxt/schema@4.3.1)(cac@6.7.14)(magicast@0.5.2)': + dependencies: + '@bomb.sh/tab': 0.0.12(cac@6.7.14)(citty@0.2.1) + '@clack/prompts': 1.1.0 + c12: 3.3.3(magicast@0.5.2) + citty: 0.2.1 + confbox: 0.2.4 + consola: 3.4.2 + copy-paste: 2.2.0 + debug: 4.4.3 + defu: 6.1.4 + exsolve: 1.0.8 + fuse.js: 7.1.0 + fzf: 0.5.2 + giget: 3.1.2 + jiti: 2.6.1 + listhen: 1.9.0 + nypm: 0.6.5 + ofetch: 1.5.1 + ohash: 2.0.11 + pathe: 2.0.3 + perfect-debounce: 2.1.0 + pkg-types: 2.3.0 + scule: 1.3.0 + semver: 7.7.4 + srvx: 0.11.9 + std-env: 3.10.0 + tinyexec: 1.0.2 + ufo: 1.6.3 + youch: 4.1.0 + optionalDependencies: + '@nuxt/schema': 4.3.1 + transitivePeerDependencies: + - cac + - commander + - magicast + - supports-color + + '@nuxt/content@3.12.0(magicast@0.5.2)': + dependencies: + '@nuxt/kit': 4.3.1(magicast@0.5.2) + '@nuxtjs/mdc': 0.20.2(magicast@0.5.2) + '@shikijs/langs': 3.23.0 + '@sqlite.org/sqlite-wasm': 3.50.4-build1 + '@standard-schema/spec': 1.1.0 + '@webcontainer/env': 1.1.1 + c12: 3.3.3(magicast@0.5.2) + chokidar: 5.0.0 + consola: 3.4.2 + db0: 0.3.4 + defu: 6.1.4 + destr: 2.0.5 + git-url-parse: 16.1.0 + hookable: 5.5.3 + isomorphic-git: 1.37.2 + jiti: 2.6.1 + json-schema-to-typescript: 15.0.4 + mdast-util-to-hast: 13.2.1 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromatch: 4.0.8 + minimark: 0.2.0 + minimatch: 10.2.4 + nuxt-component-meta: 0.17.2(magicast@0.5.2) + nypm: 0.6.5 + ohash: 2.0.11 + pathe: 2.0.3 + pkg-types: 2.3.0 + remark-mdc: 3.10.0 + scule: 1.3.0 + shiki: 4.0.2 + slugify: 1.6.6 + socket.io-client: 4.8.3 + std-env: 3.10.0 + tinyglobby: 0.2.15 + ufo: 1.6.3 + unctx: 2.5.0 + unified: 11.0.5 + unist-util-stringify-position: 4.0.0 + unist-util-visit: 5.1.0 + unplugin: 2.3.11 + zod: 3.25.76 + zod-to-json-schema: 3.25.1(zod@3.25.76) + transitivePeerDependencies: + - bufferutil + - drizzle-orm + - magicast + - mysql2 + - supports-color + - utf-8-validate + + '@nuxt/devalue@2.0.2': {} + + '@nuxt/devtools-kit@3.2.3(magicast@0.5.2)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2))': + dependencies: + '@nuxt/kit': 4.3.1(magicast@0.5.2) + execa: 8.0.1 + vite: 7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2) + transitivePeerDependencies: + - magicast + + '@nuxt/devtools-wizard@3.2.3': + dependencies: + '@clack/prompts': 1.1.0 + consola: 3.4.2 + diff: 8.0.3 + execa: 8.0.1 + magicast: 0.5.2 + pathe: 2.0.3 + pkg-types: 2.3.0 + semver: 7.7.4 + + '@nuxt/devtools@3.2.3(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.30(typescript@5.9.3))': + dependencies: + '@nuxt/devtools-kit': 3.2.3(magicast@0.5.2)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2)) + '@nuxt/devtools-wizard': 3.2.3 + '@nuxt/kit': 4.3.1(magicast@0.5.2) + '@vue/devtools-core': 8.0.7(vue@3.5.30(typescript@5.9.3)) + '@vue/devtools-kit': 8.0.7 + birpc: 4.0.0 + consola: 3.4.2 + destr: 2.0.5 + error-stack-parser-es: 1.0.5 + execa: 8.0.1 + fast-npm-meta: 1.4.2 + get-port-please: 3.2.0 + hookable: 6.0.1 + image-meta: 0.2.2 + is-installed-globally: 1.0.0 + launch-editor: 2.13.1 + local-pkg: 1.1.2 + magicast: 0.5.2 + nypm: 0.6.5 + ohash: 2.0.11 + pathe: 2.0.3 + perfect-debounce: 2.1.0 + pkg-types: 2.3.0 + semver: 7.7.4 + simple-git: 3.33.0 + sirv: 3.0.2 + structured-clone-es: 1.0.0 + tinyglobby: 0.2.15 + vite: 7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2) + vite-plugin-inspect: 11.3.3(@nuxt/kit@4.3.1(magicast@0.5.2))(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2)) + vite-plugin-vue-tracer: 1.2.0(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.30(typescript@5.9.3)) + which: 5.0.0 + ws: 8.19.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + - vue + + '@nuxt/fonts@0.14.0(db0@0.3.4)(ioredis@5.10.0)(magicast@0.5.2)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2))': + dependencies: + '@nuxt/devtools-kit': 3.2.3(magicast@0.5.2)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2)) + '@nuxt/kit': 4.3.1(magicast@0.5.2) + consola: 3.4.2 + defu: 6.1.4 + fontless: 0.2.1(db0@0.3.4)(ioredis@5.10.0)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2)) + h3: 1.15.6 + magic-regexp: 0.10.0 + ofetch: 1.5.1 + pathe: 2.0.3 + sirv: 3.0.2 + tinyglobby: 0.2.15 + ufo: 1.6.3 + unifont: 0.7.4 + unplugin: 3.0.0 + unstorage: 1.17.4(db0@0.3.4)(ioredis@5.10.0) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - db0 + - idb-keyval + - ioredis + - magicast + - uploadthing + - vite + + '@nuxt/icon@2.2.1(magicast@0.5.2)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.30(typescript@5.9.3))': + dependencies: + '@iconify/collections': 1.0.659 + '@iconify/types': 2.0.0 + '@iconify/utils': 3.1.0 + '@iconify/vue': 5.0.0(vue@3.5.30(typescript@5.9.3)) + '@nuxt/devtools-kit': 3.2.3(magicast@0.5.2)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2)) + '@nuxt/kit': 4.3.1(magicast@0.5.2) + consola: 3.4.2 + local-pkg: 1.1.2 + mlly: 1.8.1 + ohash: 2.0.11 + pathe: 2.0.3 + picomatch: 4.0.3 + std-env: 3.10.0 + tinyglobby: 0.2.15 + transitivePeerDependencies: + - magicast + - vite + - vue + + '@nuxt/kit@3.21.1(magicast@0.5.2)': + dependencies: + c12: 3.3.3(magicast@0.5.2) + consola: 3.4.2 + defu: 6.1.4 + destr: 2.0.5 + errx: 0.1.0 + exsolve: 1.0.8 + ignore: 7.0.5 + jiti: 2.6.1 + klona: 2.0.6 + knitwork: 1.3.0 + mlly: 1.8.1 + ohash: 2.0.11 + pathe: 2.0.3 + pkg-types: 2.3.0 + rc9: 3.0.0 + scule: 1.3.0 + semver: 7.7.4 + tinyglobby: 0.2.15 + ufo: 1.6.3 + unctx: 2.5.0 + untyped: 2.0.0 + transitivePeerDependencies: + - magicast + + '@nuxt/kit@4.3.1(magicast@0.5.2)': + dependencies: + c12: 3.3.3(magicast@0.5.2) + consola: 3.4.2 + defu: 6.1.4 + destr: 2.0.5 + errx: 0.1.0 + exsolve: 1.0.8 + ignore: 7.0.5 + jiti: 2.6.1 + klona: 2.0.6 + mlly: 1.8.1 + ohash: 2.0.11 + pathe: 2.0.3 + pkg-types: 2.3.0 + rc9: 3.0.0 + scule: 1.3.0 + semver: 7.7.4 + tinyglobby: 0.2.15 + ufo: 1.6.3 + unctx: 2.5.0 + untyped: 2.0.0 + transitivePeerDependencies: + - magicast + + '@nuxt/nitro-server@4.3.1(db0@0.3.4)(ioredis@5.10.0)(magicast@0.5.2)(nuxt@4.3.1(@parcel/watcher@2.5.6)(@vue/compiler-sfc@3.5.30)(cac@6.7.14)(db0@0.3.4)(ioredis@5.10.0)(lightningcss@1.32.0)(magicast@0.5.2)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2))(yaml@2.8.2))(typescript@5.9.3)': + dependencies: + '@nuxt/devalue': 2.0.2 + '@nuxt/kit': 4.3.1(magicast@0.5.2) + '@unhead/vue': 2.1.12(vue@3.5.30(typescript@5.9.3)) + '@vue/shared': 3.5.30 + consola: 3.4.2 + defu: 6.1.4 + destr: 2.0.5 + devalue: 5.6.3 + errx: 0.1.0 + escape-string-regexp: 5.0.0 + exsolve: 1.0.8 + h3: 1.15.6 + impound: 1.1.5 + klona: 2.0.6 + mocked-exports: 0.1.1 + nitropack: 2.13.1 + nuxt: 4.3.1(@parcel/watcher@2.5.6)(@vue/compiler-sfc@3.5.30)(cac@6.7.14)(db0@0.3.4)(ioredis@5.10.0)(lightningcss@1.32.0)(magicast@0.5.2)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2))(yaml@2.8.2) + ohash: 2.0.11 + pathe: 2.0.3 + pkg-types: 2.3.0 + rou3: 0.7.12 + std-env: 3.10.0 + ufo: 1.6.3 + unctx: 2.5.0 + unstorage: 1.17.4(db0@0.3.4)(ioredis@5.10.0) + vue: 3.5.30(typescript@5.9.3) + vue-bundle-renderer: 2.2.0 + vue-devtools-stub: 0.1.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@electric-sql/pglite' + - '@libsql/client' + - '@netlify/blobs' + - '@planetscale/database' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bare-abort-controller + - bare-buffer + - better-sqlite3 + - db0 + - drizzle-orm + - encoding + - idb-keyval + - ioredis + - magicast + - mysql2 + - react-native-b4a + - rolldown + - sqlite3 + - supports-color + - typescript + - uploadthing + - xml2js + + '@nuxt/schema@4.3.1': + dependencies: + '@vue/shared': 3.5.30 + defu: 6.1.4 + pathe: 2.0.3 + pkg-types: 2.3.0 + std-env: 3.10.0 + + '@nuxt/telemetry@2.7.0(@nuxt/kit@4.3.1(magicast@0.5.2))': + dependencies: + '@nuxt/kit': 4.3.1(magicast@0.5.2) + citty: 0.2.1 + consola: 3.4.2 + ofetch: 2.0.0-alpha.3 + rc9: 3.0.0 + std-env: 3.10.0 + + '@nuxt/ui@4.5.1(@nuxt/content@3.12.0(magicast@0.5.2))(@tiptap/extensions@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))(@tiptap/y-tiptap@3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29))(db0@0.3.4)(embla-carousel@8.6.0)(ioredis@5.10.0)(magicast@0.5.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tailwindcss@4.2.1)(typescript@5.9.3)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2))(vue-router@4.6.4(vue@3.5.30(typescript@5.9.3)))(vue@3.5.30(typescript@5.9.3))(yjs@13.6.29)(zod@4.3.6)': + dependencies: + '@floating-ui/dom': 1.7.6 + '@iconify/vue': 5.0.0(vue@3.5.30(typescript@5.9.3)) + '@internationalized/date': 3.12.0 + '@internationalized/number': 3.6.5 + '@nuxt/fonts': 0.14.0(db0@0.3.4)(ioredis@5.10.0)(magicast@0.5.2)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2)) + '@nuxt/icon': 2.2.1(magicast@0.5.2)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.30(typescript@5.9.3)) + '@nuxt/kit': 4.3.1(magicast@0.5.2) + '@nuxt/schema': 4.3.1 + '@nuxtjs/color-mode': 3.5.2(magicast@0.5.2) + '@standard-schema/spec': 1.1.0 + '@tailwindcss/postcss': 4.2.1 + '@tailwindcss/vite': 4.2.1(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2)) + '@tanstack/vue-table': 8.21.3(vue@3.5.30(typescript@5.9.3)) + '@tanstack/vue-virtual': 3.13.21(vue@3.5.30(typescript@5.9.3)) + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/extension-bubble-menu': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + '@tiptap/extension-code': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1)) + '@tiptap/extension-collaboration': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)(@tiptap/y-tiptap@3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29))(yjs@13.6.29) + '@tiptap/extension-drag-handle': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/extension-collaboration@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)(@tiptap/y-tiptap@3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29))(yjs@13.6.29))(@tiptap/extension-node-range@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)(@tiptap/y-tiptap@3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29)) + '@tiptap/extension-drag-handle-vue-3': 3.20.1(@tiptap/extension-drag-handle@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/extension-collaboration@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)(@tiptap/y-tiptap@3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29))(yjs@13.6.29))(@tiptap/extension-node-range@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)(@tiptap/y-tiptap@3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29)))(@tiptap/pm@3.20.1)(@tiptap/vue-3@3.20.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)(vue@3.5.30(typescript@5.9.3)))(vue@3.5.30(typescript@5.9.3)) + '@tiptap/extension-floating-menu': 3.20.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + '@tiptap/extension-horizontal-rule': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + '@tiptap/extension-image': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1)) + '@tiptap/extension-mention': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)(@tiptap/suggestion@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)) + '@tiptap/extension-node-range': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + '@tiptap/extension-placeholder': 3.20.1(@tiptap/extensions@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)) + '@tiptap/markdown': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + '@tiptap/starter-kit': 3.20.1 + '@tiptap/suggestion': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + '@tiptap/vue-3': 3.20.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)(vue@3.5.30(typescript@5.9.3)) + '@unhead/vue': 2.1.12(vue@3.5.30(typescript@5.9.3)) + '@vueuse/core': 14.2.1(vue@3.5.30(typescript@5.9.3)) + '@vueuse/integrations': 14.2.1(fuse.js@7.1.0)(vue@3.5.30(typescript@5.9.3)) + '@vueuse/shared': 14.2.1(vue@3.5.30(typescript@5.9.3)) + colortranslator: 5.0.0 + consola: 3.4.2 + defu: 6.1.4 + embla-carousel-auto-height: 8.6.0(embla-carousel@8.6.0) + embla-carousel-auto-scroll: 8.6.0(embla-carousel@8.6.0) + embla-carousel-autoplay: 8.6.0(embla-carousel@8.6.0) + embla-carousel-class-names: 8.6.0(embla-carousel@8.6.0) + embla-carousel-fade: 8.6.0(embla-carousel@8.6.0) + embla-carousel-vue: 8.6.0(vue@3.5.30(typescript@5.9.3)) + embla-carousel-wheel-gestures: 8.1.0(embla-carousel@8.6.0) + fuse.js: 7.1.0 + hookable: 5.5.3 + knitwork: 1.3.0 + magic-string: 0.30.21 + mlly: 1.8.1 + motion-v: 1.10.3(@vueuse/core@14.2.1(vue@3.5.30(typescript@5.9.3)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vue@3.5.30(typescript@5.9.3)) + ohash: 2.0.11 + pathe: 2.0.3 + reka-ui: 2.8.2(vue@3.5.30(typescript@5.9.3)) + scule: 1.3.0 + tailwind-merge: 3.5.0 + tailwind-variants: 3.2.2(tailwind-merge@3.5.0)(tailwindcss@4.2.1) + tailwindcss: 4.2.1 + tinyglobby: 0.2.15 + typescript: 5.9.3 + ufo: 1.6.3 + unplugin: 3.0.0 + unplugin-auto-import: 21.0.0(@nuxt/kit@4.3.1(magicast@0.5.2))(@vueuse/core@14.2.1(vue@3.5.30(typescript@5.9.3))) + unplugin-vue-components: 31.0.0(@nuxt/kit@4.3.1(magicast@0.5.2))(vue@3.5.30(typescript@5.9.3)) + vaul-vue: 0.4.1(reka-ui@2.8.2(vue@3.5.30(typescript@5.9.3)))(vue@3.5.30(typescript@5.9.3)) + vue-component-type-helpers: 3.2.5 + optionalDependencies: + '@nuxt/content': 3.12.0(magicast@0.5.2) + vue-router: 4.6.4(vue@3.5.30(typescript@5.9.3)) + zod: 4.3.6 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@emotion/is-prop-valid' + - '@netlify/blobs' + - '@planetscale/database' + - '@tiptap/extensions' + - '@tiptap/y-tiptap' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - '@vue/composition-api' + - async-validator + - aws4fetch + - axios + - change-case + - db0 + - drauu + - embla-carousel + - focus-trap + - idb-keyval + - ioredis + - jwt-decode + - magicast + - nprogress + - qrcode + - react + - react-dom + - sortablejs + - universal-cookie + - uploadthing + - vite + - vue + - yjs + + '@nuxt/vite-builder@4.3.1(lightningcss@1.32.0)(magicast@0.5.2)(nuxt@4.3.1(@parcel/watcher@2.5.6)(@vue/compiler-sfc@3.5.30)(cac@6.7.14)(db0@0.3.4)(ioredis@5.10.0)(lightningcss@1.32.0)(magicast@0.5.2)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2))(yaml@2.8.2))(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(vue@3.5.30(typescript@5.9.3))(yaml@2.8.2)': + dependencies: + '@nuxt/kit': 4.3.1(magicast@0.5.2) + '@rollup/plugin-replace': 6.0.3(rollup@4.59.0) + '@vitejs/plugin-vue': 6.0.4(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.30(typescript@5.9.3)) + '@vitejs/plugin-vue-jsx': 5.1.4(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.30(typescript@5.9.3)) + autoprefixer: 10.4.27(postcss@8.5.8) + consola: 3.4.2 + cssnano: 7.1.3(postcss@8.5.8) + defu: 6.1.4 + esbuild: 0.27.3 + escape-string-regexp: 5.0.0 + exsolve: 1.0.8 + get-port-please: 3.2.0 + jiti: 2.6.1 + knitwork: 1.3.0 + magic-string: 0.30.21 + mlly: 1.8.1 + mocked-exports: 0.1.1 + nuxt: 4.3.1(@parcel/watcher@2.5.6)(@vue/compiler-sfc@3.5.30)(cac@6.7.14)(db0@0.3.4)(ioredis@5.10.0)(lightningcss@1.32.0)(magicast@0.5.2)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2))(yaml@2.8.2) + pathe: 2.0.3 + pkg-types: 2.3.0 + postcss: 8.5.8 + rollup-plugin-visualizer: 6.0.11(rollup@4.59.0) + seroval: 1.5.1 + std-env: 3.10.0 + ufo: 1.6.3 + unenv: 2.0.0-rc.24 + vite: 7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2) + vite-node: 5.3.0(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2) + vite-plugin-checker: 0.12.0(typescript@5.9.3)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2)) + vue: 3.5.30(typescript@5.9.3) + vue-bundle-renderer: 2.2.0 + transitivePeerDependencies: + - '@biomejs/biome' + - '@types/node' + - eslint + - less + - lightningcss + - magicast + - meow + - optionator + - oxlint + - rollup + - sass + - sass-embedded + - stylelint + - stylus + - sugarss + - supports-color + - terser + - tsx + - typescript + - vls + - vti + - vue-tsc + - yaml + + '@nuxtjs/color-mode@3.5.2(magicast@0.5.2)': + dependencies: + '@nuxt/kit': 3.21.1(magicast@0.5.2) + pathe: 1.1.2 + pkg-types: 1.3.1 + semver: 7.7.4 + transitivePeerDependencies: + - magicast + + '@nuxtjs/mdc@0.20.2(magicast@0.5.2)': + dependencies: + '@nuxt/kit': 4.3.1(magicast@0.5.2) + '@shikijs/core': 3.23.0 + '@shikijs/langs': 3.23.0 + '@shikijs/themes': 3.23.0 + '@shikijs/transformers': 3.23.0 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@vue/compiler-core': 3.5.30 + consola: 3.4.2 + debug: 4.4.3 + defu: 6.1.4 + destr: 2.0.5 + detab: 3.0.2 + github-slugger: 2.0.0 + hast-util-format: 1.1.0 + hast-util-to-mdast: 10.1.2 + hast-util-to-string: 3.0.1 + mdast-util-to-hast: 13.2.1 + micromark-util-sanitize-uri: 2.0.1 + parse5: 8.0.0 + pathe: 2.0.3 + property-information: 7.1.0 + rehype-external-links: 3.0.0 + rehype-minify-whitespace: 6.0.2 + rehype-raw: 7.0.0 + rehype-remark: 10.0.1 + rehype-slug: 6.0.0 + rehype-sort-attribute-values: 5.0.1 + rehype-sort-attributes: 5.0.1 + remark-emoji: 5.0.2 + remark-gfm: 4.0.1 + remark-mdc: 3.10.0 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + remark-stringify: 11.0.0 + scule: 1.3.0 + shiki: 3.23.0 + ufo: 1.6.3 + unified: 11.0.5 + unist-builder: 4.0.0 + unist-util-visit: 5.1.0 + unwasm: 0.5.3 + vfile: 6.0.3 + transitivePeerDependencies: + - magicast + - supports-color + + '@nuxtjs/plausible@3.0.2(magicast@0.5.2)': + dependencies: + '@nuxt/kit': 4.3.1(magicast@0.5.2) + '@plausible-analytics/tracker': 0.4.4 + defu: 6.1.4 + ufo: 1.6.3 + transitivePeerDependencies: + - magicast + + '@oxc-minify/binding-android-arm-eabi@0.112.0': + optional: true + + '@oxc-minify/binding-android-arm64@0.112.0': + optional: true + + '@oxc-minify/binding-darwin-arm64@0.112.0': + optional: true + + '@oxc-minify/binding-darwin-x64@0.112.0': + optional: true + + '@oxc-minify/binding-freebsd-x64@0.112.0': + optional: true + + '@oxc-minify/binding-linux-arm-gnueabihf@0.112.0': + optional: true + + '@oxc-minify/binding-linux-arm-musleabihf@0.112.0': + optional: true + + '@oxc-minify/binding-linux-arm64-gnu@0.112.0': + optional: true + + '@oxc-minify/binding-linux-arm64-musl@0.112.0': + optional: true + + '@oxc-minify/binding-linux-ppc64-gnu@0.112.0': + optional: true + + '@oxc-minify/binding-linux-riscv64-gnu@0.112.0': + optional: true + + '@oxc-minify/binding-linux-riscv64-musl@0.112.0': + optional: true + + '@oxc-minify/binding-linux-s390x-gnu@0.112.0': + optional: true + + '@oxc-minify/binding-linux-x64-gnu@0.112.0': + optional: true + + '@oxc-minify/binding-linux-x64-musl@0.112.0': + optional: true + + '@oxc-minify/binding-openharmony-arm64@0.112.0': + optional: true + + '@oxc-minify/binding-wasm32-wasi@0.112.0': + dependencies: + '@napi-rs/wasm-runtime': 1.1.1 + optional: true + + '@oxc-minify/binding-win32-arm64-msvc@0.112.0': + optional: true + + '@oxc-minify/binding-win32-ia32-msvc@0.112.0': + optional: true + + '@oxc-minify/binding-win32-x64-msvc@0.112.0': + optional: true + + '@oxc-parser/binding-android-arm-eabi@0.112.0': + optional: true + + '@oxc-parser/binding-android-arm64@0.112.0': + optional: true + + '@oxc-parser/binding-darwin-arm64@0.112.0': + optional: true + + '@oxc-parser/binding-darwin-x64@0.112.0': + optional: true + + '@oxc-parser/binding-freebsd-x64@0.112.0': + optional: true + + '@oxc-parser/binding-linux-arm-gnueabihf@0.112.0': + optional: true + + '@oxc-parser/binding-linux-arm-musleabihf@0.112.0': + optional: true + + '@oxc-parser/binding-linux-arm64-gnu@0.112.0': + optional: true + + '@oxc-parser/binding-linux-arm64-musl@0.112.0': + optional: true + + '@oxc-parser/binding-linux-ppc64-gnu@0.112.0': + optional: true + + '@oxc-parser/binding-linux-riscv64-gnu@0.112.0': + optional: true + + '@oxc-parser/binding-linux-riscv64-musl@0.112.0': + optional: true + + '@oxc-parser/binding-linux-s390x-gnu@0.112.0': + optional: true + + '@oxc-parser/binding-linux-x64-gnu@0.112.0': + optional: true + + '@oxc-parser/binding-linux-x64-musl@0.112.0': + optional: true + + '@oxc-parser/binding-openharmony-arm64@0.112.0': + optional: true + + '@oxc-parser/binding-wasm32-wasi@0.112.0': + dependencies: + '@napi-rs/wasm-runtime': 1.1.1 + optional: true + + '@oxc-parser/binding-win32-arm64-msvc@0.112.0': + optional: true + + '@oxc-parser/binding-win32-ia32-msvc@0.112.0': + optional: true + + '@oxc-parser/binding-win32-x64-msvc@0.112.0': + optional: true + + '@oxc-project/types@0.112.0': {} + + '@oxc-transform/binding-android-arm-eabi@0.112.0': + optional: true + + '@oxc-transform/binding-android-arm64@0.112.0': + optional: true + + '@oxc-transform/binding-darwin-arm64@0.112.0': + optional: true + + '@oxc-transform/binding-darwin-x64@0.112.0': + optional: true + + '@oxc-transform/binding-freebsd-x64@0.112.0': + optional: true + + '@oxc-transform/binding-linux-arm-gnueabihf@0.112.0': + optional: true + + '@oxc-transform/binding-linux-arm-musleabihf@0.112.0': + optional: true + + '@oxc-transform/binding-linux-arm64-gnu@0.112.0': + optional: true + + '@oxc-transform/binding-linux-arm64-musl@0.112.0': + optional: true + + '@oxc-transform/binding-linux-ppc64-gnu@0.112.0': + optional: true + + '@oxc-transform/binding-linux-riscv64-gnu@0.112.0': + optional: true + + '@oxc-transform/binding-linux-riscv64-musl@0.112.0': + optional: true + + '@oxc-transform/binding-linux-s390x-gnu@0.112.0': + optional: true + + '@oxc-transform/binding-linux-x64-gnu@0.112.0': + optional: true + + '@oxc-transform/binding-linux-x64-musl@0.112.0': + optional: true + + '@oxc-transform/binding-openharmony-arm64@0.112.0': + optional: true + + '@oxc-transform/binding-wasm32-wasi@0.112.0': + dependencies: + '@napi-rs/wasm-runtime': 1.1.1 + optional: true + + '@oxc-transform/binding-win32-arm64-msvc@0.112.0': + optional: true + + '@oxc-transform/binding-win32-ia32-msvc@0.112.0': + optional: true + + '@oxc-transform/binding-win32-x64-msvc@0.112.0': + optional: true + + '@parcel/watcher-android-arm64@2.5.6': + optional: true + + '@parcel/watcher-darwin-arm64@2.5.6': + optional: true + + '@parcel/watcher-darwin-x64@2.5.6': + optional: true + + '@parcel/watcher-freebsd-x64@2.5.6': + optional: true + + '@parcel/watcher-linux-arm-glibc@2.5.6': + optional: true + + '@parcel/watcher-linux-arm-musl@2.5.6': + optional: true + + '@parcel/watcher-linux-arm64-glibc@2.5.6': + optional: true + + '@parcel/watcher-linux-arm64-musl@2.5.6': + optional: true + + '@parcel/watcher-linux-x64-glibc@2.5.6': + optional: true + + '@parcel/watcher-linux-x64-musl@2.5.6': + optional: true + + '@parcel/watcher-wasm@2.5.6': + dependencies: + is-glob: 4.0.3 + picomatch: 4.0.3 + + '@parcel/watcher-win32-arm64@2.5.6': + optional: true + + '@parcel/watcher-win32-ia32@2.5.6': + optional: true + + '@parcel/watcher-win32-x64@2.5.6': + optional: true + + '@parcel/watcher@2.5.6': + dependencies: + detect-libc: 2.1.2 + is-glob: 4.0.3 + node-addon-api: 7.1.1 + picomatch: 4.0.3 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.5.6 + '@parcel/watcher-darwin-arm64': 2.5.6 + '@parcel/watcher-darwin-x64': 2.5.6 + '@parcel/watcher-freebsd-x64': 2.5.6 + '@parcel/watcher-linux-arm-glibc': 2.5.6 + '@parcel/watcher-linux-arm-musl': 2.5.6 + '@parcel/watcher-linux-arm64-glibc': 2.5.6 + '@parcel/watcher-linux-arm64-musl': 2.5.6 + '@parcel/watcher-linux-x64-glibc': 2.5.6 + '@parcel/watcher-linux-x64-musl': 2.5.6 + '@parcel/watcher-win32-arm64': 2.5.6 + '@parcel/watcher-win32-ia32': 2.5.6 + '@parcel/watcher-win32-x64': 2.5.6 + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@plausible-analytics/tracker@0.4.4': {} + + '@polka/url@1.0.0-next.29': {} + + '@poppinss/colors@4.1.6': + dependencies: + kleur: 4.1.5 + + '@poppinss/dumper@0.7.0': + dependencies: + '@poppinss/colors': 4.1.6 + '@sindresorhus/is': 7.2.0 + supports-color: 10.2.2 + + '@poppinss/exception@1.2.3': {} + + '@remirror/core-constants@3.0.0': {} + + '@resvg/resvg-wasm@2.6.2': {} + + '@rolldown/pluginutils@1.0.0-rc.2': {} + + '@rolldown/pluginutils@1.0.0-rc.8': {} + + '@rollup/plugin-alias@6.0.0(rollup@4.59.0)': + optionalDependencies: + rollup: 4.59.0 + + '@rollup/plugin-commonjs@29.0.2(rollup@4.59.0)': + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) + commondir: 1.0.1 + estree-walker: 2.0.2 + fdir: 6.5.0(picomatch@4.0.3) + is-reference: 1.2.1 + magic-string: 0.30.21 + picomatch: 4.0.3 + optionalDependencies: + rollup: 4.59.0 + + '@rollup/plugin-inject@5.0.5(rollup@4.59.0)': + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) + estree-walker: 2.0.2 + magic-string: 0.30.21 + optionalDependencies: + rollup: 4.59.0 + + '@rollup/plugin-json@6.1.0(rollup@4.59.0)': + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) + optionalDependencies: + rollup: 4.59.0 + + '@rollup/plugin-node-resolve@16.0.3(rollup@4.59.0)': + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) + '@types/resolve': 1.20.2 + deepmerge: 4.3.1 + is-module: 1.0.0 + resolve: 1.22.11 + optionalDependencies: + rollup: 4.59.0 + + '@rollup/plugin-replace@6.0.3(rollup@4.59.0)': + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) + magic-string: 0.30.21 + optionalDependencies: + rollup: 4.59.0 + + '@rollup/plugin-terser@0.4.4(rollup@4.59.0)': + dependencies: + serialize-javascript: 6.0.2 + smob: 1.6.1 + terser: 5.46.0 + optionalDependencies: + rollup: 4.59.0 + + '@rollup/pluginutils@5.3.0(rollup@4.59.0)': + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.3 + optionalDependencies: + rollup: 4.59.0 + + '@rollup/rollup-android-arm-eabi@4.59.0': + optional: true + + '@rollup/rollup-android-arm64@4.59.0': + optional: true + + '@rollup/rollup-darwin-arm64@4.59.0': + optional: true + + '@rollup/rollup-darwin-x64@4.59.0': + optional: true + + '@rollup/rollup-freebsd-arm64@4.59.0': + optional: true + + '@rollup/rollup-freebsd-x64@4.59.0': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.59.0': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.59.0': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.59.0': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.59.0': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.59.0': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.59.0': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.59.0': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.59.0': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.59.0': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.59.0': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.59.0': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.59.0': + optional: true + + '@rollup/rollup-linux-x64-musl@4.59.0': + optional: true + + '@rollup/rollup-openbsd-x64@4.59.0': + optional: true + + '@rollup/rollup-openharmony-arm64@4.59.0': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.59.0': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.59.0': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.59.0': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.59.0': + optional: true + + '@shikijs/core@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + + '@shikijs/core@4.0.2': + dependencies: + '@shikijs/primitive': 4.0.2 + '@shikijs/types': 4.0.2 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + + '@shikijs/engine-javascript@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + '@shikijs/vscode-textmate': 10.0.2 + oniguruma-to-es: 4.3.4 + + '@shikijs/engine-javascript@4.0.2': + dependencies: + '@shikijs/types': 4.0.2 + '@shikijs/vscode-textmate': 10.0.2 + oniguruma-to-es: 4.3.4 + + '@shikijs/engine-oniguruma@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + '@shikijs/vscode-textmate': 10.0.2 + + '@shikijs/engine-oniguruma@4.0.2': + dependencies: + '@shikijs/types': 4.0.2 + '@shikijs/vscode-textmate': 10.0.2 + + '@shikijs/langs@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + + '@shikijs/langs@4.0.2': + dependencies: + '@shikijs/types': 4.0.2 + + '@shikijs/primitive@4.0.2': + dependencies: + '@shikijs/types': 4.0.2 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + '@shikijs/themes@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + + '@shikijs/themes@4.0.2': + dependencies: + '@shikijs/types': 4.0.2 + + '@shikijs/transformers@3.23.0': + dependencies: + '@shikijs/core': 3.23.0 + '@shikijs/types': 3.23.0 + + '@shikijs/types@3.23.0': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + '@shikijs/types@4.0.2': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + '@shikijs/vscode-textmate@10.0.2': {} + + '@sindresorhus/is@4.6.0': {} + + '@sindresorhus/is@7.2.0': {} + + '@sindresorhus/merge-streams@4.0.0': {} + + '@socket.io/component-emitter@3.1.2': {} + + '@speed-highlight/core@1.2.14': {} + + '@sqlite.org/sqlite-wasm@3.50.4-build1': {} + + '@standard-schema/spec@1.1.0': {} + + '@swc/helpers@0.5.15': + dependencies: + tslib: 2.8.1 + + '@swc/helpers@0.5.19': + dependencies: + tslib: 2.8.1 + + '@tailwindcss/node@4.2.1': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.20.0 + jiti: 2.6.1 + lightningcss: 1.31.1 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.2.1 + + '@tailwindcss/oxide-android-arm64@4.2.1': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.2.1': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.2.1': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.2.1': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.2.1': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.2.1': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.2.1': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.2.1': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.2.1': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.2.1': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.2.1': + optional: true + + '@tailwindcss/oxide@4.2.1': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.2.1 + '@tailwindcss/oxide-darwin-arm64': 4.2.1 + '@tailwindcss/oxide-darwin-x64': 4.2.1 + '@tailwindcss/oxide-freebsd-x64': 4.2.1 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.1 + '@tailwindcss/oxide-linux-arm64-gnu': 4.2.1 + '@tailwindcss/oxide-linux-arm64-musl': 4.2.1 + '@tailwindcss/oxide-linux-x64-gnu': 4.2.1 + '@tailwindcss/oxide-linux-x64-musl': 4.2.1 + '@tailwindcss/oxide-wasm32-wasi': 4.2.1 + '@tailwindcss/oxide-win32-arm64-msvc': 4.2.1 + '@tailwindcss/oxide-win32-x64-msvc': 4.2.1 + + '@tailwindcss/postcss@4.2.1': + dependencies: + '@alloc/quick-lru': 5.2.0 + '@tailwindcss/node': 4.2.1 + '@tailwindcss/oxide': 4.2.1 + postcss: 8.5.8 + tailwindcss: 4.2.1 + + '@tailwindcss/vite@4.2.1(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2))': + dependencies: + '@tailwindcss/node': 4.2.1 + '@tailwindcss/oxide': 4.2.1 + tailwindcss: 4.2.1 + vite: 7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2) + + '@tanstack/table-core@8.21.3': {} + + '@tanstack/virtual-core@3.13.21': {} + + '@tanstack/vue-table@8.21.3(vue@3.5.30(typescript@5.9.3))': + dependencies: + '@tanstack/table-core': 8.21.3 + vue: 3.5.30(typescript@5.9.3) + + '@tanstack/vue-virtual@3.13.21(vue@3.5.30(typescript@5.9.3))': + dependencies: + '@tanstack/virtual-core': 3.13.21 + vue: 3.5.30(typescript@5.9.3) + + '@tiptap/core@3.20.1(@tiptap/pm@3.20.1)': + dependencies: + '@tiptap/pm': 3.20.1 + + '@tiptap/extension-blockquote@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + + '@tiptap/extension-bold@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + + '@tiptap/extension-bubble-menu@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)': + dependencies: + '@floating-ui/dom': 1.7.6 + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + + '@tiptap/extension-bullet-list@3.20.1(@tiptap/extension-list@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/extension-list': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + + '@tiptap/extension-code-block@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + + '@tiptap/extension-code@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + + '@tiptap/extension-collaboration@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)(@tiptap/y-tiptap@3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29))(yjs@13.6.29)': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + '@tiptap/y-tiptap': 3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29) + yjs: 13.6.29 + + '@tiptap/extension-document@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + + '@tiptap/extension-drag-handle-vue-3@3.20.1(@tiptap/extension-drag-handle@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/extension-collaboration@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)(@tiptap/y-tiptap@3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29))(yjs@13.6.29))(@tiptap/extension-node-range@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)(@tiptap/y-tiptap@3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29)))(@tiptap/pm@3.20.1)(@tiptap/vue-3@3.20.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)(vue@3.5.30(typescript@5.9.3)))(vue@3.5.30(typescript@5.9.3))': + dependencies: + '@tiptap/extension-drag-handle': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/extension-collaboration@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)(@tiptap/y-tiptap@3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29))(yjs@13.6.29))(@tiptap/extension-node-range@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)(@tiptap/y-tiptap@3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29)) + '@tiptap/pm': 3.20.1 + '@tiptap/vue-3': 3.20.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)(vue@3.5.30(typescript@5.9.3)) + vue: 3.5.30(typescript@5.9.3) + + '@tiptap/extension-drag-handle@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/extension-collaboration@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)(@tiptap/y-tiptap@3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29))(yjs@13.6.29))(@tiptap/extension-node-range@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)(@tiptap/y-tiptap@3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29))': + dependencies: + '@floating-ui/dom': 1.7.6 + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/extension-collaboration': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)(@tiptap/y-tiptap@3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29))(yjs@13.6.29) + '@tiptap/extension-node-range': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + '@tiptap/y-tiptap': 3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29) + + '@tiptap/extension-dropcursor@3.20.1(@tiptap/extensions@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/extensions': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + + '@tiptap/extension-floating-menu@3.20.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)': + dependencies: + '@floating-ui/dom': 1.7.6 + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + + '@tiptap/extension-gapcursor@3.20.1(@tiptap/extensions@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/extensions': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + + '@tiptap/extension-hard-break@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + + '@tiptap/extension-heading@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + + '@tiptap/extension-horizontal-rule@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + + '@tiptap/extension-image@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + + '@tiptap/extension-italic@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + + '@tiptap/extension-link@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + linkifyjs: 4.3.2 + + '@tiptap/extension-list-item@3.20.1(@tiptap/extension-list@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/extension-list': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + + '@tiptap/extension-list-keymap@3.20.1(@tiptap/extension-list@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/extension-list': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + + '@tiptap/extension-list@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + + '@tiptap/extension-mention@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)(@tiptap/suggestion@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + '@tiptap/suggestion': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + + '@tiptap/extension-node-range@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + + '@tiptap/extension-ordered-list@3.20.1(@tiptap/extension-list@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/extension-list': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + + '@tiptap/extension-paragraph@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + + '@tiptap/extension-placeholder@3.20.1(@tiptap/extensions@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/extensions': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + + '@tiptap/extension-strike@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + + '@tiptap/extension-text@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + + '@tiptap/extension-underline@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + + '@tiptap/extensions@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + + '@tiptap/markdown@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + marked: 17.0.4 + + '@tiptap/pm@3.20.1': + dependencies: + prosemirror-changeset: 2.4.0 + prosemirror-collab: 1.3.1 + prosemirror-commands: 1.7.1 + prosemirror-dropcursor: 1.8.2 + prosemirror-gapcursor: 1.4.1 + prosemirror-history: 1.5.0 + prosemirror-inputrules: 1.5.1 + prosemirror-keymap: 1.2.3 + prosemirror-markdown: 1.13.4 + prosemirror-menu: 1.3.0 + prosemirror-model: 1.25.4 + prosemirror-schema-basic: 1.2.4 + prosemirror-schema-list: 1.5.1 + prosemirror-state: 1.4.4 + prosemirror-tables: 1.8.5 + prosemirror-trailing-node: 3.0.0(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6) + prosemirror-transform: 1.11.0 + prosemirror-view: 1.41.6 + + '@tiptap/starter-kit@3.20.1': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/extension-blockquote': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1)) + '@tiptap/extension-bold': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1)) + '@tiptap/extension-bullet-list': 3.20.1(@tiptap/extension-list@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)) + '@tiptap/extension-code': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1)) + '@tiptap/extension-code-block': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + '@tiptap/extension-document': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1)) + '@tiptap/extension-dropcursor': 3.20.1(@tiptap/extensions@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)) + '@tiptap/extension-gapcursor': 3.20.1(@tiptap/extensions@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)) + '@tiptap/extension-hard-break': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1)) + '@tiptap/extension-heading': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1)) + '@tiptap/extension-horizontal-rule': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + '@tiptap/extension-italic': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1)) + '@tiptap/extension-link': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + '@tiptap/extension-list': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + '@tiptap/extension-list-item': 3.20.1(@tiptap/extension-list@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)) + '@tiptap/extension-list-keymap': 3.20.1(@tiptap/extension-list@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)) + '@tiptap/extension-ordered-list': 3.20.1(@tiptap/extension-list@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)) + '@tiptap/extension-paragraph': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1)) + '@tiptap/extension-strike': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1)) + '@tiptap/extension-text': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1)) + '@tiptap/extension-underline': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1)) + '@tiptap/extensions': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + + '@tiptap/suggestion@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)': + dependencies: + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + + '@tiptap/vue-3@3.20.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1)(vue@3.5.30(typescript@5.9.3))': + dependencies: + '@floating-ui/dom': 1.7.6 + '@tiptap/core': 3.20.1(@tiptap/pm@3.20.1) + '@tiptap/pm': 3.20.1 + vue: 3.5.30(typescript@5.9.3) + optionalDependencies: + '@tiptap/extension-bubble-menu': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + '@tiptap/extension-floating-menu': 3.20.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) + + '@tiptap/y-tiptap@3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29)': + dependencies: + lib0: 0.2.117 + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-view: 1.41.6 + y-protocols: 1.0.7(yjs@13.6.29) + yjs: 13.6.29 + + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/d3-array@3.2.2': {} + + '@types/d3-axis@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-brush@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-chord@3.0.6': {} + + '@types/d3-color@3.1.3': {} + + '@types/d3-contour@3.0.6': + dependencies: + '@types/d3-array': 3.2.2 + '@types/geojson': 7946.0.16 + + '@types/d3-delaunay@6.0.4': {} + + '@types/d3-dispatch@3.0.7': {} + + '@types/d3-drag@3.0.7': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-dsv@3.0.7': {} + + '@types/d3-ease@3.0.2': {} + + '@types/d3-fetch@3.0.7': + dependencies: + '@types/d3-dsv': 3.0.7 + + '@types/d3-force@3.0.10': {} + + '@types/d3-format@3.0.4': {} + + '@types/d3-geo@3.1.0': + dependencies: + '@types/geojson': 7946.0.16 + + '@types/d3-hierarchy@3.1.7': {} + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-path@3.1.1': {} + + '@types/d3-polygon@3.0.2': {} + + '@types/d3-quadtree@3.0.6': {} + + '@types/d3-random@3.0.3': {} + + '@types/d3-scale-chromatic@3.1.0': {} + + '@types/d3-scale@4.0.9': + dependencies: + '@types/d3-time': 3.0.4 + + '@types/d3-selection@3.0.11': {} + + '@types/d3-shape@3.1.8': + dependencies: + '@types/d3-path': 3.1.1 + + '@types/d3-time-format@4.0.3': {} + + '@types/d3-time@3.0.4': {} + + '@types/d3-timer@3.0.2': {} + + '@types/d3-transition@3.0.9': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + + '@types/d3@7.4.3': + dependencies: + '@types/d3-array': 3.2.2 + '@types/d3-axis': 3.0.6 + '@types/d3-brush': 3.0.6 + '@types/d3-chord': 3.0.6 + '@types/d3-color': 3.1.3 + '@types/d3-contour': 3.0.6 + '@types/d3-delaunay': 6.0.4 + '@types/d3-dispatch': 3.0.7 + '@types/d3-drag': 3.0.7 + '@types/d3-dsv': 3.0.7 + '@types/d3-ease': 3.0.2 + '@types/d3-fetch': 3.0.7 + '@types/d3-force': 3.0.10 + '@types/d3-format': 3.0.4 + '@types/d3-geo': 3.1.0 + '@types/d3-hierarchy': 3.1.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-path': 3.1.1 + '@types/d3-polygon': 3.0.2 + '@types/d3-quadtree': 3.0.6 + '@types/d3-random': 3.0.3 + '@types/d3-scale': 4.0.9 + '@types/d3-scale-chromatic': 3.1.0 + '@types/d3-selection': 3.0.11 + '@types/d3-shape': 3.1.8 + '@types/d3-time': 3.0.4 + '@types/d3-time-format': 4.0.3 + '@types/d3-timer': 3.0.2 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + + '@types/debug@4.1.12': + dependencies: + '@types/ms': 2.1.0 + + '@types/estree@1.0.8': {} + + '@types/geojson@7946.0.16': {} + + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/json-schema@7.0.15': {} + + '@types/linkify-it@5.0.0': {} + + '@types/lodash@4.17.24': {} + + '@types/markdown-it@14.1.2': + dependencies: + '@types/linkify-it': 5.0.0 + '@types/mdurl': 2.0.0 + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/mdurl@2.0.0': {} + + '@types/ms@2.1.0': {} + + '@types/parse-path@7.1.0': + dependencies: + parse-path: 7.1.0 + + '@types/resolve@1.20.2': {} + + '@types/trusted-types@2.0.7': + optional: true + + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + + '@types/web-bluetooth@0.0.20': {} + + '@types/web-bluetooth@0.0.21': {} + + '@ungap/structured-clone@1.3.0': {} + + '@unhead/vue@2.1.12(vue@3.5.30(typescript@5.9.3))': + dependencies: + hookable: 6.0.1 + unhead: 2.1.12 + vue: 3.5.30(typescript@5.9.3) + + '@upsetjs/venn.js@2.0.0': + optionalDependencies: + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + '@vercel/nft@1.3.2(rollup@4.59.0)': + dependencies: + '@mapbox/node-pre-gyp': 2.0.3 + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) + acorn: 8.16.0 + acorn-import-attributes: 1.9.5(acorn@8.16.0) + async-sema: 3.1.1 + bindings: 1.5.0 + estree-walker: 2.0.2 + glob: 13.0.6 + graceful-fs: 4.2.11 + node-gyp-build: 4.8.4 + picomatch: 4.0.3 + resolve-from: 5.0.0 + transitivePeerDependencies: + - encoding + - rollup + - supports-color + + '@vitejs/plugin-vue-jsx@5.1.4(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.30(typescript@5.9.3))': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) + '@rolldown/pluginutils': 1.0.0-rc.8 + '@vue/babel-plugin-jsx': 2.0.1(@babel/core@7.29.0) + vite: 7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2) + vue: 3.5.30(typescript@5.9.3) + transitivePeerDependencies: + - supports-color + + '@vitejs/plugin-vue@6.0.4(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.30(typescript@5.9.3))': + dependencies: + '@rolldown/pluginutils': 1.0.0-rc.2 + vite: 7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2) + vue: 3.5.30(typescript@5.9.3) + + '@volar/language-core@2.4.28': + dependencies: + '@volar/source-map': 2.4.28 + + '@volar/source-map@2.4.28': {} + + '@volar/typescript@2.4.28': + dependencies: + '@volar/language-core': 2.4.28 + path-browserify: 1.0.1 + vscode-uri: 3.1.0 + + '@vue-macros/common@3.1.2(vue@3.5.30(typescript@5.9.3))': + dependencies: + '@vue/compiler-sfc': 3.5.30 + ast-kit: 2.2.0 + local-pkg: 1.1.2 + magic-string-ast: 1.0.3 + unplugin-utils: 0.3.1 + optionalDependencies: + vue: 3.5.30(typescript@5.9.3) + + '@vue/babel-helper-vue-transform-on@2.0.1': {} + + '@vue/babel-plugin-jsx@2.0.1(@babel/core@7.29.0)': + dependencies: + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@vue/babel-helper-vue-transform-on': 2.0.1 + '@vue/babel-plugin-resolve-type': 2.0.1(@babel/core@7.29.0) + '@vue/shared': 3.5.30 + optionalDependencies: + '@babel/core': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@vue/babel-plugin-resolve-type@2.0.1(@babel/core@7.29.0)': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/parser': 7.29.0 + '@vue/compiler-sfc': 3.5.30 + transitivePeerDependencies: + - supports-color + + '@vue/compiler-core@3.5.30': + dependencies: + '@babel/parser': 7.29.0 + '@vue/shared': 3.5.30 + entities: 7.0.1 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + '@vue/compiler-dom@3.5.30': + dependencies: + '@vue/compiler-core': 3.5.30 + '@vue/shared': 3.5.30 + + '@vue/compiler-sfc@3.5.30': + dependencies: + '@babel/parser': 7.29.0 + '@vue/compiler-core': 3.5.30 + '@vue/compiler-dom': 3.5.30 + '@vue/compiler-ssr': 3.5.30 + '@vue/shared': 3.5.30 + estree-walker: 2.0.2 + magic-string: 0.30.21 + postcss: 8.5.8 + source-map-js: 1.2.1 + + '@vue/compiler-ssr@3.5.30': + dependencies: + '@vue/compiler-dom': 3.5.30 + '@vue/shared': 3.5.30 + + '@vue/devtools-api@6.6.4': {} + + '@vue/devtools-core@8.0.7(vue@3.5.30(typescript@5.9.3))': + dependencies: + '@vue/devtools-kit': 8.0.7 + '@vue/devtools-shared': 8.0.7 + vue: 3.5.30(typescript@5.9.3) + + '@vue/devtools-kit@8.0.7': + dependencies: + '@vue/devtools-shared': 8.0.7 + birpc: 2.9.0 + hookable: 5.5.3 + perfect-debounce: 2.1.0 + + '@vue/devtools-shared@8.0.7': {} + + '@vue/language-core@3.2.5': + dependencies: + '@volar/language-core': 2.4.28 + '@vue/compiler-dom': 3.5.30 + '@vue/shared': 3.5.30 + alien-signals: 3.1.2 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + picomatch: 4.0.3 + + '@vue/reactivity@3.5.30': + dependencies: + '@vue/shared': 3.5.30 + + '@vue/runtime-core@3.5.30': + dependencies: + '@vue/reactivity': 3.5.30 + '@vue/shared': 3.5.30 + + '@vue/runtime-dom@3.5.30': + dependencies: + '@vue/reactivity': 3.5.30 + '@vue/runtime-core': 3.5.30 + '@vue/shared': 3.5.30 + csstype: 3.2.3 + + '@vue/server-renderer@3.5.30(vue@3.5.30(typescript@5.9.3))': + dependencies: + '@vue/compiler-ssr': 3.5.30 + '@vue/shared': 3.5.30 + vue: 3.5.30(typescript@5.9.3) + + '@vue/shared@3.5.30': {} + + '@vueuse/core@10.11.1(vue@3.5.30(typescript@5.9.3))': + dependencies: + '@types/web-bluetooth': 0.0.20 + '@vueuse/metadata': 10.11.1 + '@vueuse/shared': 10.11.1(vue@3.5.30(typescript@5.9.3)) + vue-demi: 0.14.10(vue@3.5.30(typescript@5.9.3)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@vueuse/core@14.2.1(vue@3.5.30(typescript@5.9.3))': + dependencies: + '@types/web-bluetooth': 0.0.21 + '@vueuse/metadata': 14.2.1 + '@vueuse/shared': 14.2.1(vue@3.5.30(typescript@5.9.3)) + vue: 3.5.30(typescript@5.9.3) + + '@vueuse/integrations@14.2.1(fuse.js@7.1.0)(vue@3.5.30(typescript@5.9.3))': + dependencies: + '@vueuse/core': 14.2.1(vue@3.5.30(typescript@5.9.3)) + '@vueuse/shared': 14.2.1(vue@3.5.30(typescript@5.9.3)) + vue: 3.5.30(typescript@5.9.3) + optionalDependencies: + fuse.js: 7.1.0 + + '@vueuse/metadata@10.11.1': {} + + '@vueuse/metadata@14.2.1': {} + + '@vueuse/shared@10.11.1(vue@3.5.30(typescript@5.9.3))': + dependencies: + vue-demi: 0.14.10(vue@3.5.30(typescript@5.9.3)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@vueuse/shared@14.2.1(vue@3.5.30(typescript@5.9.3))': + dependencies: + vue: 3.5.30(typescript@5.9.3) + + '@webcontainer/env@1.1.1': {} + + abbrev@3.0.1: {} + + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + + acorn-import-attributes@1.9.5(acorn@8.16.0): + dependencies: + acorn: 8.16.0 + + acorn@8.16.0: {} + + agent-base@7.1.4: {} + + alien-signals@3.1.2: {} + + ansi-regex@5.0.1: {} + + ansi-regex@6.2.2: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.3: {} + + ansis@4.2.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + archiver-utils@5.0.2: + dependencies: + glob: 10.5.0 + graceful-fs: 4.2.11 + is-stream: 2.0.1 + lazystream: 1.0.1 + lodash: 4.17.23 + normalize-path: 3.0.0 + readable-stream: 4.7.0 + + archiver@7.0.1: + dependencies: + archiver-utils: 5.0.2 + async: 3.2.6 + buffer-crc32: 1.0.0 + readable-stream: 4.7.0 + readdir-glob: 1.1.3 + tar-stream: 3.1.8 + zip-stream: 6.0.1 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - react-native-b4a + + argparse@2.0.1: {} + + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + + ast-kit@2.2.0: + dependencies: + '@babel/parser': 7.29.0 + pathe: 2.0.3 + + ast-walker-scope@0.8.3: + dependencies: + '@babel/parser': 7.29.0 + ast-kit: 2.2.0 + + async-lock@1.4.1: {} + + async-sema@3.1.1: {} + + async@3.2.6: {} + + automd@0.4.3(magicast@0.5.2): + dependencies: + '@parcel/watcher': 2.5.6 + c12: 3.3.3(magicast@0.5.2) + citty: 0.2.1 + consola: 3.4.2 + defu: 6.1.4 + destr: 2.0.5 + didyoumean2: 7.0.4 + magic-string: 0.30.21 + mdbox: 0.1.1 + mlly: 1.8.1 + ofetch: 1.5.1 + pathe: 2.0.3 + perfect-debounce: 2.1.0 + pkg-types: 2.3.0 + scule: 1.3.0 + tinyglobby: 0.2.15 + untyped: 2.0.0 + transitivePeerDependencies: + - magicast + + autoprefixer@10.4.27(postcss@8.5.8): + dependencies: + browserslist: 4.28.1 + caniuse-lite: 1.0.30001777 + fraction.js: 5.3.4 + picocolors: 1.1.1 + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + + b4a@1.8.0: {} + + bail@2.0.2: {} + + balanced-match@1.0.2: {} + + balanced-match@4.0.4: {} + + bare-events@2.8.2: {} + + bare-fs@4.5.5: + dependencies: + bare-events: 2.8.2 + bare-path: 3.0.0 + bare-stream: 2.8.1(bare-events@2.8.2) + bare-url: 2.3.2 + fast-fifo: 1.3.2 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + bare-os@3.7.1: {} + + bare-path@3.0.0: + dependencies: + bare-os: 3.7.1 + + bare-stream@2.8.1(bare-events@2.8.2): + dependencies: + streamx: 2.23.0 + teex: 1.0.1 + optionalDependencies: + bare-events: 2.8.2 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + bare-url@2.3.2: + dependencies: + bare-path: 3.0.0 + + base64-js@1.5.1: {} + + baseline-browser-mapping@2.10.0: {} + + bindings@1.5.0: + dependencies: + file-uri-to-path: 1.0.0 + + birpc@2.9.0: {} + + birpc@4.0.0: {} + + boolbase@1.0.0: {} + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + brace-expansion@5.0.4: + dependencies: + balanced-match: 4.0.4 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.28.1: + dependencies: + baseline-browser-mapping: 2.10.0 + caniuse-lite: 1.0.30001777 + electron-to-chromium: 1.5.307 + node-releases: 2.0.36 + update-browserslist-db: 1.2.3(browserslist@4.28.1) + + buffer-crc32@1.0.0: {} + + buffer-from@1.1.2: {} + + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + bundle-name@4.1.0: + dependencies: + run-applescript: 7.1.0 + + c12@3.3.3(magicast@0.5.2): + dependencies: + chokidar: 5.0.0 + confbox: 0.2.4 + defu: 6.1.4 + dotenv: 17.3.1 + exsolve: 1.0.8 + giget: 2.0.0 + jiti: 2.6.1 + ohash: 2.0.11 + pathe: 2.0.3 + perfect-debounce: 2.1.0 + pkg-types: 2.3.0 + rc9: 2.1.2 + optionalDependencies: + magicast: 0.5.2 + + c12@4.0.0-beta.3(chokidar@5.0.0)(dotenv@17.3.1)(giget@3.1.2)(jiti@2.6.1)(magicast@0.5.2): + dependencies: + confbox: 0.2.4 + defu: 6.1.4 + exsolve: 1.0.8 + pathe: 2.0.3 + pkg-types: 2.3.0 + rc9: 3.0.0 + optionalDependencies: + chokidar: 5.0.0 + dotenv: 17.3.1 + giget: 3.1.2 + jiti: 2.6.1 + magicast: 0.5.2 + + cac@6.7.14: {} + + cac@7.0.0: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + caniuse-api@3.0.0: + dependencies: + browserslist: 4.28.1 + caniuse-lite: 1.0.30001777 + lodash.memoize: 4.1.2 + lodash.uniq: 4.5.0 + + caniuse-lite@1.0.30001777: {} + + ccount@2.0.1: {} + + char-regex@1.0.2: {} + + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + + chevrotain-allstar@0.3.1(chevrotain@11.1.2): + dependencies: + chevrotain: 11.1.2 + lodash-es: 4.17.23 + + chevrotain@11.1.2: + dependencies: + '@chevrotain/cst-dts-gen': 11.1.2 + '@chevrotain/gast': 11.1.2 + '@chevrotain/regexp-to-ast': 11.1.2 + '@chevrotain/types': 11.1.2 + '@chevrotain/utils': 11.1.2 + lodash-es: 4.17.23 + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + chokidar@5.0.0: + dependencies: + readdirp: 5.0.0 + + chownr@3.0.0: {} + + citty@0.1.6: + dependencies: + consola: 3.4.2 + + citty@0.2.1: {} + + clean-git-ref@2.0.1: {} + + client-only@0.0.1: {} + + clipboardy@4.0.0: + dependencies: + execa: 8.0.1 + is-wsl: 3.1.1 + is64bit: 2.0.0 + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + cluster-key-slot@1.1.2: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + colord@2.9.3: {} + + colortranslator@5.0.0: {} + + comma-separated-tokens@2.0.3: {} + + commander@11.1.0: {} + + commander@2.20.3: {} + + commander@7.2.0: {} + + commander@8.3.0: {} + + commondir@1.0.1: {} + + compatx@0.2.0: {} + + compress-commons@6.0.2: + dependencies: + crc-32: 1.2.2 + crc32-stream: 6.0.0 + is-stream: 2.0.1 + normalize-path: 3.0.0 + readable-stream: 4.7.0 + + confbox@0.1.8: {} + + confbox@0.2.4: {} + + consola@3.4.2: {} + + convert-source-map@2.0.0: {} + + cookie-es@1.2.2: {} + + cookie-es@2.0.0: {} + + copy-paste@2.2.0: + dependencies: + iconv-lite: 0.4.24 + + core-util-is@1.0.3: {} + + cose-base@1.0.3: + dependencies: + layout-base: 1.0.2 + + cose-base@2.2.0: + dependencies: + layout-base: 2.0.1 + + crc-32@1.2.2: {} + + crc32-stream@6.0.0: + dependencies: + crc-32: 1.2.2 + readable-stream: 4.7.0 + + crelt@1.0.6: {} + + croner@9.1.0: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + crossws@0.3.5: + dependencies: + uncrypto: 0.1.3 + + css-declaration-sorter@7.3.1(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + + css-select@5.2.2: + dependencies: + boolbase: 1.0.0 + css-what: 6.2.2 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + + css-tree@2.2.1: + dependencies: + mdn-data: 2.0.28 + source-map-js: 1.2.1 + + css-tree@3.2.1: + dependencies: + mdn-data: 2.27.1 + source-map-js: 1.2.1 + + css-what@6.2.2: {} + + cssesc@3.0.0: {} + + cssnano-preset-default@7.0.11(postcss@8.5.8): + dependencies: + browserslist: 4.28.1 + css-declaration-sorter: 7.3.1(postcss@8.5.8) + cssnano-utils: 5.0.1(postcss@8.5.8) + postcss: 8.5.8 + postcss-calc: 10.1.1(postcss@8.5.8) + postcss-colormin: 7.0.6(postcss@8.5.8) + postcss-convert-values: 7.0.9(postcss@8.5.8) + postcss-discard-comments: 7.0.6(postcss@8.5.8) + postcss-discard-duplicates: 7.0.2(postcss@8.5.8) + postcss-discard-empty: 7.0.1(postcss@8.5.8) + postcss-discard-overridden: 7.0.1(postcss@8.5.8) + postcss-merge-longhand: 7.0.5(postcss@8.5.8) + postcss-merge-rules: 7.0.8(postcss@8.5.8) + postcss-minify-font-values: 7.0.1(postcss@8.5.8) + postcss-minify-gradients: 7.0.1(postcss@8.5.8) + postcss-minify-params: 7.0.6(postcss@8.5.8) + postcss-minify-selectors: 7.0.6(postcss@8.5.8) + postcss-normalize-charset: 7.0.1(postcss@8.5.8) + postcss-normalize-display-values: 7.0.1(postcss@8.5.8) + postcss-normalize-positions: 7.0.1(postcss@8.5.8) + postcss-normalize-repeat-style: 7.0.1(postcss@8.5.8) + postcss-normalize-string: 7.0.1(postcss@8.5.8) + postcss-normalize-timing-functions: 7.0.1(postcss@8.5.8) + postcss-normalize-unicode: 7.0.6(postcss@8.5.8) + postcss-normalize-url: 7.0.1(postcss@8.5.8) + postcss-normalize-whitespace: 7.0.1(postcss@8.5.8) + postcss-ordered-values: 7.0.2(postcss@8.5.8) + postcss-reduce-initial: 7.0.6(postcss@8.5.8) + postcss-reduce-transforms: 7.0.1(postcss@8.5.8) + postcss-svgo: 7.1.1(postcss@8.5.8) + postcss-unique-selectors: 7.0.5(postcss@8.5.8) + + cssnano-utils@5.0.1(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + + cssnano@7.1.3(postcss@8.5.8): + dependencies: + cssnano-preset-default: 7.0.11(postcss@8.5.8) + lilconfig: 3.1.3 + postcss: 8.5.8 + + csso@5.0.5: + dependencies: + css-tree: 2.2.1 + + csstype@3.2.3: {} + + cytoscape-cose-bilkent@4.1.0(cytoscape@3.33.1): + dependencies: + cose-base: 1.0.3 + cytoscape: 3.33.1 + + cytoscape-fcose@2.2.0(cytoscape@3.33.1): + dependencies: + cose-base: 2.2.0 + cytoscape: 3.33.1 + + cytoscape@3.33.1: {} + + d3-array@2.12.1: + dependencies: + internmap: 1.0.1 + + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-axis@3.0.0: {} + + d3-brush@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3-chord@3.0.1: + dependencies: + d3-path: 3.1.0 + + d3-color@3.1.0: {} + + d3-contour@4.0.2: + dependencies: + d3-array: 3.2.4 + + d3-delaunay@6.0.4: + dependencies: + delaunator: 5.0.1 + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-dsv@3.0.1: + dependencies: + commander: 7.2.0 + iconv-lite: 0.6.3 + rw: 1.3.3 + + d3-ease@3.0.1: {} + + d3-fetch@3.0.1: + dependencies: + d3-dsv: 3.0.1 + + d3-force@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + + d3-format@3.1.2: {} + + d3-geo@3.1.1: + dependencies: + d3-array: 3.2.4 + + d3-hierarchy@3.1.2: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-path@1.0.9: {} + + d3-path@3.1.0: {} + + d3-polygon@3.0.1: {} + + d3-quadtree@3.0.1: {} + + d3-random@3.0.1: {} + + d3-sankey@0.12.3: + dependencies: + d3-array: 2.12.1 + d3-shape: 1.3.7 + + d3-scale-chromatic@3.1.0: + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.2 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-selection@3.0.0: {} + + d3-shape@1.3.7: + dependencies: + d3-path: 1.0.9 + + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3@7.9.0: + dependencies: + d3-array: 3.2.4 + d3-axis: 3.0.0 + d3-brush: 3.0.0 + d3-chord: 3.0.1 + d3-color: 3.1.0 + d3-contour: 4.0.2 + d3-delaunay: 6.0.4 + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-dsv: 3.0.1 + d3-ease: 3.0.1 + d3-fetch: 3.0.1 + d3-force: 3.0.0 + d3-format: 3.1.2 + d3-geo: 3.1.1 + d3-hierarchy: 3.1.2 + d3-interpolate: 3.0.1 + d3-path: 3.1.0 + d3-polygon: 3.0.1 + d3-quadtree: 3.0.1 + d3-random: 3.0.1 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + d3-timer: 3.0.1 + d3-transition: 3.0.1(d3-selection@3.0.0) + d3-zoom: 3.0.0 + + dagre-d3-es@7.0.14: + dependencies: + d3: 7.9.0 + lodash-es: 4.17.23 + + dayjs@1.11.19: {} + + db0@0.3.4: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decode-named-character-reference@1.3.0: + dependencies: + character-entities: 2.0.2 + + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + + deepmerge@4.3.1: {} + + default-browser-id@5.0.1: {} + + default-browser@5.5.0: + dependencies: + bundle-name: 4.1.0 + default-browser-id: 5.0.1 + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-lazy-prop@2.0.0: {} + + define-lazy-prop@3.0.0: {} + + defu@6.1.4: {} + + delaunator@5.0.1: + dependencies: + robust-predicates: 3.0.2 + + denque@2.1.0: {} + + depd@2.0.0: {} + + dequal@2.0.3: {} + + destr@2.0.5: {} + + detab@3.0.2: {} + + detect-libc@2.1.2: {} + + devalue@5.6.3: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + didyoumean2@7.0.4: + dependencies: + '@babel/runtime': 7.28.6 + fastest-levenshtein: 1.0.16 + lodash.deburr: 4.1.0 + + diff3@0.0.3: {} + + diff@8.0.3: {} + + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + domelementtype@2.3.0: {} + + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + + dompurify@3.3.2: + optionalDependencies: + '@types/trusted-types': 2.0.7 + + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + + dot-prop@10.1.0: + dependencies: + type-fest: 5.4.4 + + dotenv@17.3.1: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + duplexer@0.1.2: {} + + eastasianwidth@0.2.0: {} + + ee-first@1.1.1: {} + + electron-to-chromium@1.5.307: {} + + embla-carousel-auto-height@8.6.0(embla-carousel@8.6.0): + dependencies: + embla-carousel: 8.6.0 + + embla-carousel-auto-scroll@8.6.0(embla-carousel@8.6.0): + dependencies: + embla-carousel: 8.6.0 + + embla-carousel-autoplay@8.6.0(embla-carousel@8.6.0): + dependencies: + embla-carousel: 8.6.0 + + embla-carousel-class-names@8.6.0(embla-carousel@8.6.0): + dependencies: + embla-carousel: 8.6.0 + + embla-carousel-fade@8.6.0(embla-carousel@8.6.0): + dependencies: + embla-carousel: 8.6.0 + + embla-carousel-reactive-utils@8.6.0(embla-carousel@8.6.0): + dependencies: + embla-carousel: 8.6.0 + + embla-carousel-vue@8.6.0(vue@3.5.30(typescript@5.9.3)): + dependencies: + embla-carousel: 8.6.0 + embla-carousel-reactive-utils: 8.6.0(embla-carousel@8.6.0) + vue: 3.5.30(typescript@5.9.3) + + embla-carousel-wheel-gestures@8.1.0(embla-carousel@8.6.0): + dependencies: + embla-carousel: 8.6.0 + wheel-gestures: 2.2.48 + + embla-carousel@8.6.0: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + emojilib@2.4.0: {} + + emoticon@4.1.0: {} + + encodeurl@2.0.0: {} + + engine.io-client@6.6.4: + dependencies: + '@socket.io/component-emitter': 3.1.2 + debug: 4.4.3 + engine.io-parser: 5.2.3 + ws: 8.18.3 + xmlhttprequest-ssl: 2.1.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + engine.io-parser@5.2.3: {} + + enhanced-resolve@5.20.0: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.0 + + entities@4.5.0: {} + + entities@6.0.1: {} + + entities@7.0.1: {} + + error-stack-parser-es@1.0.5: {} + + errx@0.1.0: {} + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@2.0.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + esbuild@0.27.3: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.3 + '@esbuild/android-arm': 0.27.3 + '@esbuild/android-arm64': 0.27.3 + '@esbuild/android-x64': 0.27.3 + '@esbuild/darwin-arm64': 0.27.3 + '@esbuild/darwin-x64': 0.27.3 + '@esbuild/freebsd-arm64': 0.27.3 + '@esbuild/freebsd-x64': 0.27.3 + '@esbuild/linux-arm': 0.27.3 + '@esbuild/linux-arm64': 0.27.3 + '@esbuild/linux-ia32': 0.27.3 + '@esbuild/linux-loong64': 0.27.3 + '@esbuild/linux-mips64el': 0.27.3 + '@esbuild/linux-ppc64': 0.27.3 + '@esbuild/linux-riscv64': 0.27.3 + '@esbuild/linux-s390x': 0.27.3 + '@esbuild/linux-x64': 0.27.3 + '@esbuild/netbsd-arm64': 0.27.3 + '@esbuild/netbsd-x64': 0.27.3 + '@esbuild/openbsd-arm64': 0.27.3 + '@esbuild/openbsd-x64': 0.27.3 + '@esbuild/openharmony-arm64': 0.27.3 + '@esbuild/sunos-x64': 0.27.3 + '@esbuild/win32-arm64': 0.27.3 + '@esbuild/win32-ia32': 0.27.3 + '@esbuild/win32-x64': 0.27.3 + + escalade@3.2.0: {} + + escape-html@1.0.3: {} + + escape-string-regexp@4.0.0: {} + + escape-string-regexp@5.0.0: {} + + estree-walker@2.0.2: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + etag@1.8.1: {} + + event-target-shim@5.0.1: {} + + events-universal@1.0.1: + dependencies: + bare-events: 2.8.2 + transitivePeerDependencies: + - bare-abort-controller + + events@3.3.0: {} + + execa@8.0.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + + exsolve@1.0.8: {} + + extend@3.0.2: {} + + fast-fifo@1.3.2: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-npm-meta@1.4.2: {} + + fastest-levenshtein@1.0.16: {} + + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + file-uri-to-path@1.0.0: {} + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + flat@6.0.1: {} + + fontaine@0.8.0: + dependencies: + '@capsizecss/unpack': 4.0.0 + css-tree: 3.2.1 + magic-regexp: 0.10.0 + magic-string: 0.30.21 + pathe: 2.0.3 + ufo: 1.6.3 + unplugin: 2.3.11 + + fontkitten@1.0.3: + dependencies: + tiny-inflate: 1.0.3 + + fontless@0.2.1(db0@0.3.4)(ioredis@5.10.0)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2)): + dependencies: + consola: 3.4.2 + css-tree: 3.2.1 + defu: 6.1.4 + esbuild: 0.27.3 + fontaine: 0.8.0 + jiti: 2.6.1 + lightningcss: 1.32.0 + magic-string: 0.30.21 + ohash: 2.0.11 + pathe: 2.0.3 + ufo: 1.6.3 + unifont: 0.7.4 + unstorage: 1.17.4(db0@0.3.4)(ioredis@5.10.0) + optionalDependencies: + vite: 7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - db0 + - idb-keyval + - ioredis + - uploadthing + + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + fraction.js@5.3.4: {} + + framer-motion@12.35.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + dependencies: + motion-dom: 12.35.2 + motion-utils: 12.29.2 + tslib: 2.8.1 + optionalDependencies: + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + fresh@2.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + fuse.js@7.1.0: {} + + fzf@0.5.2: {} + + geist@1.7.0(next@16.1.6(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)): + dependencies: + next: 16.1.6(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-intrinsic@1.3.0: + 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 + + get-port-please@3.2.0: {} + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-stream@8.0.1: {} + + giget@2.0.0: + dependencies: + citty: 0.1.6 + consola: 3.4.2 + defu: 6.1.4 + node-fetch-native: 1.6.7 + nypm: 0.6.5 + pathe: 2.0.3 + + giget@3.1.2: {} + + git-up@8.1.1: + dependencies: + is-ssh: 1.4.1 + parse-url: 9.2.0 + + git-url-parse@16.1.0: + dependencies: + git-up: 8.1.1 + + github-slugger@2.0.0: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob@10.5.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.9 + minipass: 7.1.3 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + glob@13.0.6: + dependencies: + minimatch: 10.2.4 + minipass: 7.1.3 + path-scurry: 2.0.2 + + global-directory@4.0.1: + dependencies: + ini: 4.1.1 + + globby@16.1.1: + dependencies: + '@sindresorhus/merge-streams': 4.0.0 + fast-glob: 3.3.3 + ignore: 7.0.5 + is-path-inside: 4.0.0 + slash: 5.1.0 + unicorn-magic: 0.4.0 + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + gzip-size@7.0.0: + dependencies: + duplexer: 0.1.2 + + h3@1.15.6: + dependencies: + cookie-es: 1.2.2 + crossws: 0.3.5 + defu: 6.1.4 + destr: 2.0.5 + iron-webcrypto: 1.2.1 + node-mock-http: 1.0.4 + radix3: 1.1.2 + ufo: 1.6.3 + uncrypto: 0.1.3 + + hachure-fill@0.5.2: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + hast-util-embedded@3.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-is-element: 3.0.0 + + hast-util-format@1.1.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-embedded: 3.0.0 + hast-util-minify-whitespace: 1.0.1 + hast-util-phrasing: 3.0.1 + hast-util-whitespace: 3.0.0 + html-whitespace-sensitive-tag-names: 3.0.1 + unist-util-visit-parents: 6.0.2 + + hast-util-from-parse5@8.0.3: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + devlop: 1.1.0 + hastscript: 9.0.1 + property-information: 7.1.0 + vfile: 6.0.3 + vfile-location: 5.0.3 + web-namespaces: 2.0.1 + + hast-util-has-property@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-heading-rank@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-is-body-ok-link@3.0.1: + dependencies: + '@types/hast': 3.0.4 + + hast-util-is-element@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-minify-whitespace@1.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-embedded: 3.0.0 + hast-util-is-element: 3.0.0 + hast-util-whitespace: 3.0.0 + unist-util-is: 6.0.1 + + hast-util-parse-selector@4.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-phrasing@3.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-embedded: 3.0.0 + hast-util-has-property: 3.0.0 + hast-util-is-body-ok-link: 3.0.1 + hast-util-is-element: 3.0.0 + + hast-util-raw@9.1.0: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + '@ungap/structured-clone': 1.3.0 + hast-util-from-parse5: 8.0.3 + hast-util-to-parse5: 8.0.1 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + parse5: 7.3.0 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-to-html@9.0.5: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + + hast-util-to-mdast@10.1.2: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.0 + hast-util-phrasing: 3.0.1 + hast-util-to-html: 9.0.5 + hast-util-to-text: 4.0.2 + hast-util-whitespace: 3.0.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-hast: 13.2.1 + mdast-util-to-string: 4.0.0 + rehype-minify-whitespace: 6.0.2 + trim-trailing-lines: 2.1.0 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + + hast-util-to-parse5@8.0.1: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-to-string@3.0.1: + dependencies: + '@types/hast': 3.0.4 + + hast-util-to-text@4.0.2: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + hast-util-is-element: 3.0.0 + unist-util-find-after: 5.0.0 + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hastscript@9.0.1: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + hast-util-parse-selector: 4.0.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + + hey-listen@1.0.8: {} + + hookable@5.5.3: {} + + hookable@6.0.1: {} + + html-void-elements@3.0.0: {} + + html-whitespace-sensitive-tag-names@3.0.1: {} + + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + + http-shutdown@1.2.2: {} + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + httpxy@0.1.7: {} + + human-signals@5.0.0: {} + + iconv-lite@0.4.24: + dependencies: + safer-buffer: 2.1.2 + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + ieee754@1.2.1: {} + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + image-meta@0.2.2: {} + + impound@1.1.5: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + es-module-lexer: 2.0.0 + pathe: 2.0.3 + unplugin: 3.0.0 + unplugin-utils: 0.3.1 + + inherits@2.0.4: {} + + ini@4.1.1: {} + + internmap@1.0.1: {} + + internmap@2.0.3: {} + + ioredis@5.10.0: + dependencies: + '@ioredis/commands': 1.5.1 + cluster-key-slot: 1.1.2 + debug: 4.4.3 + denque: 2.1.0 + lodash.defaults: 4.2.0 + lodash.isarguments: 3.1.0 + redis-errors: 1.2.0 + redis-parser: 3.0.0 + standard-as-callback: 2.1.0 + transitivePeerDependencies: + - supports-color + + iron-webcrypto@1.2.1: {} + + is-absolute-url@4.0.1: {} + + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + + is-callable@1.2.7: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-decimal@2.0.1: {} + + is-docker@2.2.1: {} + + is-docker@3.0.0: {} + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-hexadecimal@2.0.1: {} + + is-inside-container@1.0.0: + dependencies: + is-docker: 3.0.0 + + is-installed-globally@1.0.0: + dependencies: + global-directory: 4.0.1 + is-path-inside: 4.0.0 + + is-module@1.0.0: {} + + is-number@7.0.0: {} + + is-path-inside@4.0.0: {} + + is-plain-obj@4.1.0: {} + + is-reference@1.2.1: + dependencies: + '@types/estree': 1.0.8 + + is-ssh@1.4.1: + dependencies: + protocols: 2.0.2 + + is-stream@2.0.1: {} + + is-stream@3.0.0: {} + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.20 + + is-wsl@2.2.0: + dependencies: + is-docker: 2.2.1 + + is-wsl@3.1.1: + dependencies: + is-inside-container: 1.0.0 + + is64bit@2.0.0: + dependencies: + system-architecture: 0.1.0 + + isarray@1.0.0: {} + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + isexe@3.1.5: {} + + isomorphic-git@1.37.2: + dependencies: + async-lock: 1.4.1 + clean-git-ref: 2.0.1 + crc-32: 1.2.2 + diff3: 0.0.3 + ignore: 5.3.2 + minimisted: 2.0.1 + pako: 1.0.11 + pify: 4.0.1 + readable-stream: 4.7.0 + sha.js: 2.4.12 + simple-get: 4.0.1 + + isomorphic.js@0.2.5: {} + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jiti@2.6.1: {} + + js-tokens@4.0.0: {} + + js-tokens@9.0.1: {} + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-schema-to-typescript@15.0.4: + dependencies: + '@apidevtools/json-schema-ref-parser': 11.9.3 + '@types/json-schema': 7.0.15 + '@types/lodash': 4.17.24 + is-glob: 4.0.3 + js-yaml: 4.1.1 + lodash: 4.17.23 + minimist: 1.2.8 + prettier: 3.8.1 + tinyglobby: 0.2.15 + + json5@2.2.3: {} + + katex@0.16.38: + dependencies: + commander: 8.3.0 + + khroma@2.1.0: {} + + kleur@4.1.5: {} + + klona@2.0.6: {} + + knitwork@1.3.0: {} + + langium@4.2.1: + dependencies: + chevrotain: 11.1.2 + chevrotain-allstar: 0.3.1(chevrotain@11.1.2) + vscode-languageserver: 9.0.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + + launch-editor@2.13.1: + dependencies: + picocolors: 1.1.1 + shell-quote: 1.8.3 + + layout-base@1.0.2: {} + + layout-base@2.0.1: {} + + lazystream@1.0.1: + dependencies: + readable-stream: 2.3.8 + + lib0@0.2.117: + dependencies: + isomorphic.js: 0.2.5 + + lightningcss-android-arm64@1.31.1: + optional: true + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.31.1: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.31.1: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.31.1: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.31.1: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.31.1: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.31.1: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.31.1: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.31.1: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.31.1: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.31.1: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.31.1: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.31.1 + lightningcss-darwin-arm64: 1.31.1 + lightningcss-darwin-x64: 1.31.1 + lightningcss-freebsd-x64: 1.31.1 + lightningcss-linux-arm-gnueabihf: 1.31.1 + lightningcss-linux-arm64-gnu: 1.31.1 + lightningcss-linux-arm64-musl: 1.31.1 + lightningcss-linux-x64-gnu: 1.31.1 + lightningcss-linux-x64-musl: 1.31.1 + lightningcss-win32-arm64-msvc: 1.31.1 + lightningcss-win32-x64-msvc: 1.31.1 + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + lilconfig@3.1.3: {} + + linkify-it@5.0.0: + dependencies: + uc.micro: 2.1.0 + + linkifyjs@4.3.2: {} + + listhen@1.9.0: + dependencies: + '@parcel/watcher': 2.5.6 + '@parcel/watcher-wasm': 2.5.6 + citty: 0.1.6 + clipboardy: 4.0.0 + consola: 3.4.2 + crossws: 0.3.5 + defu: 6.1.4 + get-port-please: 3.2.0 + h3: 1.15.6 + http-shutdown: 1.2.2 + jiti: 2.6.1 + mlly: 1.8.1 + node-forge: 1.3.3 + pathe: 1.1.2 + std-env: 3.10.0 + ufo: 1.6.3 + untun: 0.1.3 + uqr: 0.1.2 + + local-pkg@1.1.2: + dependencies: + mlly: 1.8.1 + pkg-types: 2.3.0 + quansync: 0.2.11 + + lodash-es@4.17.23: {} + + lodash.deburr@4.1.0: {} + + lodash.defaults@4.2.0: {} + + lodash.isarguments@3.1.0: {} + + lodash.memoize@4.1.2: {} + + lodash.uniq@4.5.0: {} + + lodash@4.17.23: {} + + longest-streak@3.1.0: {} + + lru-cache@10.4.3: {} + + lru-cache@11.2.6: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + magic-regexp@0.10.0: + dependencies: + estree-walker: 3.0.3 + magic-string: 0.30.21 + mlly: 1.8.1 + regexp-tree: 0.1.27 + type-level-regexp: 0.1.17 + ufo: 1.6.3 + unplugin: 2.3.11 + + magic-string-ast@1.0.3: + dependencies: + magic-string: 0.30.21 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + magicast@0.5.2: + dependencies: + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + source-map-js: 1.2.1 + + markdown-it@14.1.1: + dependencies: + argparse: 2.0.1 + entities: 4.5.0 + linkify-it: 5.0.0 + mdurl: 2.0.0 + punycode.js: 2.3.1 + uc.micro: 2.1.0 + + markdown-table@3.0.4: {} + + marked@16.4.2: {} + + marked@17.0.4: {} + + math-intrinsics@1.1.0: {} + + md4w@0.2.7: {} + + mdast-util-find-and-replace@3.0.2: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + mdast-util-from-markdown@2.0.3: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.2 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0: + dependencies: + mdast-util-from-markdown: 2.0.3 + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.0 + mdast-util-gfm-strikethrough: 2.0.0 + mdast-util-gfm-table: 2.0.0 + mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-hast@13.2.1: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.0 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.1.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + + mdbox@0.1.1: + dependencies: + md4w: 0.2.7 + + mdn-data@2.0.28: {} + + mdn-data@2.27.1: {} + + mdream@0.17.0: + dependencies: + cac: 7.0.0 + pathe: 2.0.3 + tinyglobby: 0.2.15 + + mdurl@2.0.0: {} + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + mermaid@11.13.0: + dependencies: + '@braintree/sanitize-url': 7.1.2 + '@iconify/utils': 3.1.0 + '@mermaid-js/parser': 1.0.1 + '@types/d3': 7.4.3 + '@upsetjs/venn.js': 2.0.0 + cytoscape: 3.33.1 + cytoscape-cose-bilkent: 4.1.0(cytoscape@3.33.1) + cytoscape-fcose: 2.2.0(cytoscape@3.33.1) + d3: 7.9.0 + d3-sankey: 0.12.3 + dagre-d3-es: 7.0.14 + dayjs: 1.11.19 + dompurify: 3.3.2 + katex: 0.16.38 + khroma: 2.1.0 + lodash-es: 4.17.23 + marked: 16.4.2 + roughjs: 4.6.6 + stylis: 4.3.6 + ts-dedent: 2.2.0 + uuid: 11.1.0 + + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-table@2.1.1: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.1 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.3.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.12 + debug: 4.4.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime-db@1.54.0: {} + + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + + mime@4.1.0: {} + + mimic-fn@4.0.0: {} + + mimic-response@3.1.0: {} + + minimark@0.2.0: {} + + minimatch@10.2.4: + dependencies: + brace-expansion: 5.0.4 + + minimatch@5.1.9: + dependencies: + brace-expansion: 2.0.2 + + minimatch@9.0.9: + dependencies: + brace-expansion: 2.0.2 + + minimist@1.2.8: {} + + minimisted@2.0.1: + dependencies: + minimist: 1.2.8 + + minipass@7.1.3: {} + + minizlib@3.1.0: + dependencies: + minipass: 7.1.3 + + mlly@1.8.1: + dependencies: + acorn: 8.16.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.3 + + mocked-exports@0.1.1: {} + + motion-dom@12.35.2: + dependencies: + motion-utils: 12.29.2 + + motion-utils@12.29.2: {} + + motion-v@1.10.3(@vueuse/core@14.2.1(vue@3.5.30(typescript@5.9.3)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vue@3.5.30(typescript@5.9.3)): + dependencies: + '@vueuse/core': 14.2.1(vue@3.5.30(typescript@5.9.3)) + framer-motion: 12.35.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + hey-listen: 1.0.8 + motion-dom: 12.35.2 + vue: 3.5.30(typescript@5.9.3) + transitivePeerDependencies: + - '@emotion/is-prop-valid' + - react + - react-dom + + motion-v@2.0.0(@vueuse/core@14.2.1(vue@3.5.30(typescript@5.9.3)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vue@3.5.30(typescript@5.9.3)): + dependencies: + '@vueuse/core': 14.2.1(vue@3.5.30(typescript@5.9.3)) + framer-motion: 12.35.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + hey-listen: 1.0.8 + motion-dom: 12.35.2 + motion-utils: 12.29.2 + vue: 3.5.30(typescript@5.9.3) + transitivePeerDependencies: + - '@emotion/is-prop-valid' + - react + - react-dom + + mrmime@2.0.1: {} + + ms@2.1.3: {} + + muggle-string@0.4.1: {} + + nanoid@3.3.11: {} + + nanotar@0.2.1: {} + + next@16.1.6(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + dependencies: + '@next/env': 16.1.6 + '@swc/helpers': 0.5.15 + baseline-browser-mapping: 2.10.0 + caniuse-lite: 1.0.30001777 + postcss: 8.4.31 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + styled-jsx: 5.1.6(@babel/core@7.29.0)(react@19.2.4) + optionalDependencies: + '@next/swc-darwin-arm64': 16.1.6 + '@next/swc-darwin-x64': 16.1.6 + '@next/swc-linux-arm64-gnu': 16.1.6 + '@next/swc-linux-arm64-musl': 16.1.6 + '@next/swc-linux-x64-gnu': 16.1.6 + '@next/swc-linux-x64-musl': 16.1.6 + '@next/swc-win32-arm64-msvc': 16.1.6 + '@next/swc-win32-x64-msvc': 16.1.6 + sharp: 0.34.5 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + + nitropack@2.13.1: + dependencies: + '@cloudflare/kv-asset-handler': 0.4.2 + '@rollup/plugin-alias': 6.0.0(rollup@4.59.0) + '@rollup/plugin-commonjs': 29.0.2(rollup@4.59.0) + '@rollup/plugin-inject': 5.0.5(rollup@4.59.0) + '@rollup/plugin-json': 6.1.0(rollup@4.59.0) + '@rollup/plugin-node-resolve': 16.0.3(rollup@4.59.0) + '@rollup/plugin-replace': 6.0.3(rollup@4.59.0) + '@rollup/plugin-terser': 0.4.4(rollup@4.59.0) + '@vercel/nft': 1.3.2(rollup@4.59.0) + archiver: 7.0.1 + c12: 3.3.3(magicast@0.5.2) + chokidar: 5.0.0 + citty: 0.1.6 + compatx: 0.2.0 + confbox: 0.2.4 + consola: 3.4.2 + cookie-es: 2.0.0 + croner: 9.1.0 + crossws: 0.3.5 + db0: 0.3.4 + defu: 6.1.4 + destr: 2.0.5 + dot-prop: 10.1.0 + esbuild: 0.27.3 + escape-string-regexp: 5.0.0 + etag: 1.8.1 + exsolve: 1.0.8 + globby: 16.1.1 + gzip-size: 7.0.0 + h3: 1.15.6 + hookable: 5.5.3 + httpxy: 0.1.7 + ioredis: 5.10.0 + jiti: 2.6.1 + klona: 2.0.6 + knitwork: 1.3.0 + listhen: 1.9.0 + magic-string: 0.30.21 + magicast: 0.5.2 + mime: 4.1.0 + mlly: 1.8.1 + node-fetch-native: 1.6.7 + node-mock-http: 1.0.4 + ofetch: 1.5.1 + ohash: 2.0.11 + pathe: 2.0.3 + perfect-debounce: 2.1.0 + pkg-types: 2.3.0 + pretty-bytes: 7.1.0 + radix3: 1.1.2 + rollup: 4.59.0 + rollup-plugin-visualizer: 6.0.11(rollup@4.59.0) + scule: 1.3.0 + semver: 7.7.4 + serve-placeholder: 2.0.2 + serve-static: 2.2.1 + source-map: 0.7.6 + std-env: 3.10.0 + ufo: 1.6.3 + ultrahtml: 1.6.0 + uncrypto: 0.1.3 + unctx: 2.5.0 + unenv: 2.0.0-rc.24 + unimport: 5.7.0 + unplugin-utils: 0.3.1 + unstorage: 1.17.4(db0@0.3.4)(ioredis@5.10.0) + untyped: 2.0.0 + unwasm: 0.5.3 + youch: 4.1.0 + youch-core: 0.3.3 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@electric-sql/pglite' + - '@libsql/client' + - '@netlify/blobs' + - '@planetscale/database' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bare-abort-controller + - bare-buffer + - better-sqlite3 + - drizzle-orm + - encoding + - idb-keyval + - mysql2 + - react-native-b4a + - rolldown + - sqlite3 + - supports-color + - uploadthing + + node-addon-api@7.1.1: {} + + node-emoji@2.2.0: + dependencies: + '@sindresorhus/is': 4.6.0 + char-regex: 1.0.2 + emojilib: 2.4.0 + skin-tone: 2.0.0 + + node-fetch-native@1.6.7: {} + + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + + node-forge@1.3.3: {} + + node-gyp-build@4.8.4: {} + + node-mock-http@1.0.4: {} + + node-releases@2.0.36: {} + + nopt@8.1.0: + dependencies: + abbrev: 3.0.1 + + normalize-path@3.0.0: {} + + npm-run-path@5.3.0: + dependencies: + path-key: 4.0.0 + + npm-run-path@6.0.0: + dependencies: + path-key: 4.0.0 + unicorn-magic: 0.3.0 + + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + + nuxi@3.33.1: {} + + nuxt-component-meta@0.17.2(magicast@0.5.2): + dependencies: + '@nuxt/kit': 4.3.1(magicast@0.5.2) + citty: 0.1.6 + mlly: 1.8.1 + ohash: 2.0.11 + scule: 1.3.0 + typescript: 5.9.3 + ufo: 1.6.3 + vue-component-meta: 3.2.5(typescript@5.9.3) + transitivePeerDependencies: + - magicast + + nuxt-llms@0.2.0(magicast@0.5.2): + dependencies: + '@nuxt/kit': 4.3.1(magicast@0.5.2) + transitivePeerDependencies: + - magicast + + nuxt@4.3.1(@parcel/watcher@2.5.6)(@vue/compiler-sfc@3.5.30)(cac@6.7.14)(db0@0.3.4)(ioredis@5.10.0)(lightningcss@1.32.0)(magicast@0.5.2)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2))(yaml@2.8.2): + dependencies: + '@dxup/nuxt': 0.3.2(magicast@0.5.2) + '@nuxt/cli': 3.33.1(@nuxt/schema@4.3.1)(cac@6.7.14)(magicast@0.5.2) + '@nuxt/devtools': 3.2.3(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.30(typescript@5.9.3)) + '@nuxt/kit': 4.3.1(magicast@0.5.2) + '@nuxt/nitro-server': 4.3.1(db0@0.3.4)(ioredis@5.10.0)(magicast@0.5.2)(nuxt@4.3.1(@parcel/watcher@2.5.6)(@vue/compiler-sfc@3.5.30)(cac@6.7.14)(db0@0.3.4)(ioredis@5.10.0)(lightningcss@1.32.0)(magicast@0.5.2)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2))(yaml@2.8.2))(typescript@5.9.3) + '@nuxt/schema': 4.3.1 + '@nuxt/telemetry': 2.7.0(@nuxt/kit@4.3.1(magicast@0.5.2)) + '@nuxt/vite-builder': 4.3.1(lightningcss@1.32.0)(magicast@0.5.2)(nuxt@4.3.1(@parcel/watcher@2.5.6)(@vue/compiler-sfc@3.5.30)(cac@6.7.14)(db0@0.3.4)(ioredis@5.10.0)(lightningcss@1.32.0)(magicast@0.5.2)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2))(yaml@2.8.2))(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(vue@3.5.30(typescript@5.9.3))(yaml@2.8.2) + '@unhead/vue': 2.1.12(vue@3.5.30(typescript@5.9.3)) + '@vue/shared': 3.5.30 + c12: 3.3.3(magicast@0.5.2) + chokidar: 5.0.0 + compatx: 0.2.0 + consola: 3.4.2 + cookie-es: 2.0.0 + defu: 6.1.4 + destr: 2.0.5 + devalue: 5.6.3 + errx: 0.1.0 + escape-string-regexp: 5.0.0 + exsolve: 1.0.8 + h3: 1.15.6 + hookable: 5.5.3 + ignore: 7.0.5 + impound: 1.1.5 + jiti: 2.6.1 + klona: 2.0.6 + knitwork: 1.3.0 + magic-string: 0.30.21 + mlly: 1.8.1 + nanotar: 0.2.1 + nypm: 0.6.5 + ofetch: 1.5.1 + ohash: 2.0.11 + on-change: 6.0.2 + oxc-minify: 0.112.0 + oxc-parser: 0.112.0 + oxc-transform: 0.112.0 + oxc-walker: 0.7.0(oxc-parser@0.112.0) + pathe: 2.0.3 + perfect-debounce: 2.1.0 + pkg-types: 2.3.0 + rou3: 0.7.12 + scule: 1.3.0 + semver: 7.7.4 + std-env: 3.10.0 + tinyglobby: 0.2.15 + ufo: 1.6.3 + ultrahtml: 1.6.0 + uncrypto: 0.1.3 + unctx: 2.5.0 + unimport: 5.7.0 + unplugin: 3.0.0 + unplugin-vue-router: 0.19.2(@vue/compiler-sfc@3.5.30)(vue-router@4.6.4(vue@3.5.30(typescript@5.9.3)))(vue@3.5.30(typescript@5.9.3)) + untyped: 2.0.0 + vue: 3.5.30(typescript@5.9.3) + vue-router: 4.6.4(vue@3.5.30(typescript@5.9.3)) + optionalDependencies: + '@parcel/watcher': 2.5.6 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@biomejs/biome' + - '@capacitor/preferences' + - '@deno/kv' + - '@electric-sql/pglite' + - '@libsql/client' + - '@netlify/blobs' + - '@planetscale/database' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - '@vitejs/devtools' + - '@vue/compiler-sfc' + - aws4fetch + - bare-abort-controller + - bare-buffer + - better-sqlite3 + - bufferutil + - cac + - commander + - db0 + - drizzle-orm + - encoding + - eslint + - idb-keyval + - ioredis + - less + - lightningcss + - magicast + - meow + - mysql2 + - optionator + - oxlint + - react-native-b4a + - rolldown + - rollup + - sass + - sass-embedded + - sqlite3 + - stylelint + - stylus + - sugarss + - supports-color + - terser + - tsx + - typescript + - uploadthing + - utf-8-validate + - vite + - vls + - vti + - vue-tsc + - xml2js + - yaml + + nypm@0.6.5: + dependencies: + citty: 0.2.1 + pathe: 2.0.3 + tinyexec: 1.0.2 + + obug@2.1.1: {} + + ofetch@1.5.1: + dependencies: + destr: 2.0.5 + node-fetch-native: 1.6.7 + ufo: 1.6.3 + + ofetch@2.0.0-alpha.3: {} + + ohash@2.0.11: {} + + on-change@6.0.2: {} + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@6.0.0: + dependencies: + mimic-fn: 4.0.0 + + oniguruma-parser@0.12.1: {} + + oniguruma-to-es@4.3.4: + dependencies: + oniguruma-parser: 0.12.1 + regex: 6.1.0 + regex-recursion: 6.0.2 + + open@10.2.0: + dependencies: + default-browser: 5.5.0 + define-lazy-prop: 3.0.0 + is-inside-container: 1.0.0 + wsl-utils: 0.1.0 + + open@8.4.2: + dependencies: + define-lazy-prop: 2.0.0 + is-docker: 2.2.1 + is-wsl: 2.2.0 + + orderedmap@2.1.1: {} + + oxc-minify@0.112.0: + optionalDependencies: + '@oxc-minify/binding-android-arm-eabi': 0.112.0 + '@oxc-minify/binding-android-arm64': 0.112.0 + '@oxc-minify/binding-darwin-arm64': 0.112.0 + '@oxc-minify/binding-darwin-x64': 0.112.0 + '@oxc-minify/binding-freebsd-x64': 0.112.0 + '@oxc-minify/binding-linux-arm-gnueabihf': 0.112.0 + '@oxc-minify/binding-linux-arm-musleabihf': 0.112.0 + '@oxc-minify/binding-linux-arm64-gnu': 0.112.0 + '@oxc-minify/binding-linux-arm64-musl': 0.112.0 + '@oxc-minify/binding-linux-ppc64-gnu': 0.112.0 + '@oxc-minify/binding-linux-riscv64-gnu': 0.112.0 + '@oxc-minify/binding-linux-riscv64-musl': 0.112.0 + '@oxc-minify/binding-linux-s390x-gnu': 0.112.0 + '@oxc-minify/binding-linux-x64-gnu': 0.112.0 + '@oxc-minify/binding-linux-x64-musl': 0.112.0 + '@oxc-minify/binding-openharmony-arm64': 0.112.0 + '@oxc-minify/binding-wasm32-wasi': 0.112.0 + '@oxc-minify/binding-win32-arm64-msvc': 0.112.0 + '@oxc-minify/binding-win32-ia32-msvc': 0.112.0 + '@oxc-minify/binding-win32-x64-msvc': 0.112.0 + + oxc-parser@0.112.0: + dependencies: + '@oxc-project/types': 0.112.0 + optionalDependencies: + '@oxc-parser/binding-android-arm-eabi': 0.112.0 + '@oxc-parser/binding-android-arm64': 0.112.0 + '@oxc-parser/binding-darwin-arm64': 0.112.0 + '@oxc-parser/binding-darwin-x64': 0.112.0 + '@oxc-parser/binding-freebsd-x64': 0.112.0 + '@oxc-parser/binding-linux-arm-gnueabihf': 0.112.0 + '@oxc-parser/binding-linux-arm-musleabihf': 0.112.0 + '@oxc-parser/binding-linux-arm64-gnu': 0.112.0 + '@oxc-parser/binding-linux-arm64-musl': 0.112.0 + '@oxc-parser/binding-linux-ppc64-gnu': 0.112.0 + '@oxc-parser/binding-linux-riscv64-gnu': 0.112.0 + '@oxc-parser/binding-linux-riscv64-musl': 0.112.0 + '@oxc-parser/binding-linux-s390x-gnu': 0.112.0 + '@oxc-parser/binding-linux-x64-gnu': 0.112.0 + '@oxc-parser/binding-linux-x64-musl': 0.112.0 + '@oxc-parser/binding-openharmony-arm64': 0.112.0 + '@oxc-parser/binding-wasm32-wasi': 0.112.0 + '@oxc-parser/binding-win32-arm64-msvc': 0.112.0 + '@oxc-parser/binding-win32-ia32-msvc': 0.112.0 + '@oxc-parser/binding-win32-x64-msvc': 0.112.0 + + oxc-transform@0.112.0: + optionalDependencies: + '@oxc-transform/binding-android-arm-eabi': 0.112.0 + '@oxc-transform/binding-android-arm64': 0.112.0 + '@oxc-transform/binding-darwin-arm64': 0.112.0 + '@oxc-transform/binding-darwin-x64': 0.112.0 + '@oxc-transform/binding-freebsd-x64': 0.112.0 + '@oxc-transform/binding-linux-arm-gnueabihf': 0.112.0 + '@oxc-transform/binding-linux-arm-musleabihf': 0.112.0 + '@oxc-transform/binding-linux-arm64-gnu': 0.112.0 + '@oxc-transform/binding-linux-arm64-musl': 0.112.0 + '@oxc-transform/binding-linux-ppc64-gnu': 0.112.0 + '@oxc-transform/binding-linux-riscv64-gnu': 0.112.0 + '@oxc-transform/binding-linux-riscv64-musl': 0.112.0 + '@oxc-transform/binding-linux-s390x-gnu': 0.112.0 + '@oxc-transform/binding-linux-x64-gnu': 0.112.0 + '@oxc-transform/binding-linux-x64-musl': 0.112.0 + '@oxc-transform/binding-openharmony-arm64': 0.112.0 + '@oxc-transform/binding-wasm32-wasi': 0.112.0 + '@oxc-transform/binding-win32-arm64-msvc': 0.112.0 + '@oxc-transform/binding-win32-ia32-msvc': 0.112.0 + '@oxc-transform/binding-win32-x64-msvc': 0.112.0 + + oxc-walker@0.7.0(oxc-parser@0.112.0): + dependencies: + magic-regexp: 0.10.0 + oxc-parser: 0.112.0 + + package-json-from-dist@1.0.1: {} + + package-manager-detector@1.6.0: {} + + pako@1.0.11: {} + + parse-entities@4.0.2: + dependencies: + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.3.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + + parse-path@7.1.0: + dependencies: + protocols: 2.0.2 + + parse-url@9.2.0: + dependencies: + '@types/parse-path': 7.1.0 + parse-path: 7.1.0 + + parse5@7.3.0: + dependencies: + entities: 6.0.1 + + parse5@8.0.0: + dependencies: + entities: 6.0.1 + + parseurl@1.3.3: {} + + path-browserify@1.0.1: {} + + path-data-parser@0.1.0: {} + + path-key@3.1.1: {} + + path-key@4.0.0: {} + + path-parse@1.0.7: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.3 + + path-scurry@2.0.2: + dependencies: + lru-cache: 11.2.6 + minipass: 7.1.3 + + pathe@1.1.2: {} + + pathe@2.0.3: {} + + perfect-debounce@2.1.0: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.3: {} + + pify@4.0.1: {} + + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.1 + pathe: 2.0.3 + + pkg-types@2.3.0: + dependencies: + confbox: 0.2.4 + exsolve: 1.0.8 + pathe: 2.0.3 + + points-on-curve@0.2.0: {} + + points-on-path@0.2.1: + dependencies: + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + + possible-typed-array-names@1.1.0: {} + + postcss-calc@10.1.1(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-selector-parser: 7.1.1 + postcss-value-parser: 4.2.0 + + postcss-colormin@7.0.6(postcss@8.5.8): + dependencies: + browserslist: 4.28.1 + caniuse-api: 3.0.0 + colord: 2.9.3 + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-convert-values@7.0.9(postcss@8.5.8): + dependencies: + browserslist: 4.28.1 + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-discard-comments@7.0.6(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-selector-parser: 7.1.1 + + postcss-discard-duplicates@7.0.2(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + + postcss-discard-empty@7.0.1(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + + postcss-discard-overridden@7.0.1(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + + postcss-merge-longhand@7.0.5(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + stylehacks: 7.0.8(postcss@8.5.8) + + postcss-merge-rules@7.0.8(postcss@8.5.8): + dependencies: + browserslist: 4.28.1 + caniuse-api: 3.0.0 + cssnano-utils: 5.0.1(postcss@8.5.8) + postcss: 8.5.8 + postcss-selector-parser: 7.1.1 + + postcss-minify-font-values@7.0.1(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-minify-gradients@7.0.1(postcss@8.5.8): + dependencies: + colord: 2.9.3 + cssnano-utils: 5.0.1(postcss@8.5.8) + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-minify-params@7.0.6(postcss@8.5.8): + dependencies: + browserslist: 4.28.1 + cssnano-utils: 5.0.1(postcss@8.5.8) + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-minify-selectors@7.0.6(postcss@8.5.8): + dependencies: + cssesc: 3.0.0 + postcss: 8.5.8 + postcss-selector-parser: 7.1.1 + + postcss-normalize-charset@7.0.1(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + + postcss-normalize-display-values@7.0.1(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-normalize-positions@7.0.1(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-normalize-repeat-style@7.0.1(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-normalize-string@7.0.1(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-normalize-timing-functions@7.0.1(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-normalize-unicode@7.0.6(postcss@8.5.8): + dependencies: + browserslist: 4.28.1 + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-normalize-url@7.0.1(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-normalize-whitespace@7.0.1(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-ordered-values@7.0.2(postcss@8.5.8): + dependencies: + cssnano-utils: 5.0.1(postcss@8.5.8) + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-reduce-initial@7.0.6(postcss@8.5.8): + dependencies: + browserslist: 4.28.1 + caniuse-api: 3.0.0 + postcss: 8.5.8 + + postcss-reduce-transforms@7.0.1(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-selector-parser@7.1.1: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-svgo@7.1.1(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + svgo: 4.0.1 + + postcss-unique-selectors@7.0.5(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-selector-parser: 7.1.1 + + postcss-value-parser@4.2.0: {} + + postcss@8.4.31: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + postcss@8.5.8: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prettier@3.8.1: {} + + pretty-bytes@7.1.0: {} + + process-nextick-args@2.0.1: {} + + process@0.11.10: {} + + property-information@7.1.0: {} + + prosemirror-changeset@2.4.0: + dependencies: + prosemirror-transform: 1.11.0 + + prosemirror-collab@1.3.1: + dependencies: + prosemirror-state: 1.4.4 + + prosemirror-commands@1.7.1: + dependencies: + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.11.0 + + prosemirror-dropcursor@1.8.2: + dependencies: + prosemirror-state: 1.4.4 + prosemirror-transform: 1.11.0 + prosemirror-view: 1.41.6 + + prosemirror-gapcursor@1.4.1: + dependencies: + prosemirror-keymap: 1.2.3 + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-view: 1.41.6 + + prosemirror-history@1.5.0: + dependencies: + prosemirror-state: 1.4.4 + prosemirror-transform: 1.11.0 + prosemirror-view: 1.41.6 + rope-sequence: 1.3.4 + + prosemirror-inputrules@1.5.1: + dependencies: + prosemirror-state: 1.4.4 + prosemirror-transform: 1.11.0 + + prosemirror-keymap@1.2.3: + dependencies: + prosemirror-state: 1.4.4 + w3c-keyname: 2.2.8 + + prosemirror-markdown@1.13.4: + dependencies: + '@types/markdown-it': 14.1.2 + markdown-it: 14.1.1 + prosemirror-model: 1.25.4 + + prosemirror-menu@1.3.0: + dependencies: + crelt: 1.0.6 + prosemirror-commands: 1.7.1 + prosemirror-history: 1.5.0 + prosemirror-state: 1.4.4 + + prosemirror-model@1.25.4: + dependencies: + orderedmap: 2.1.1 + + prosemirror-schema-basic@1.2.4: + dependencies: + prosemirror-model: 1.25.4 + + prosemirror-schema-list@1.5.1: + dependencies: + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.11.0 + + prosemirror-state@1.4.4: + dependencies: + prosemirror-model: 1.25.4 + prosemirror-transform: 1.11.0 + prosemirror-view: 1.41.6 + + prosemirror-tables@1.8.5: + dependencies: + prosemirror-keymap: 1.2.3 + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.11.0 + prosemirror-view: 1.41.6 + + prosemirror-trailing-node@3.0.0(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6): + dependencies: + '@remirror/core-constants': 3.0.0 + escape-string-regexp: 4.0.0 + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-view: 1.41.6 + + prosemirror-transform@1.11.0: + dependencies: + prosemirror-model: 1.25.4 + + prosemirror-view@1.41.6: + dependencies: + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.11.0 + + protocols@2.0.2: {} + + punycode.js@2.3.1: {} + + quansync@0.2.11: {} + + queue-microtask@1.2.3: {} + + radix3@1.1.2: {} + + randombytes@2.1.0: + dependencies: + safe-buffer: 5.2.1 + + range-parser@1.2.1: {} + + rc9@2.1.2: + dependencies: + defu: 6.1.4 + destr: 2.0.5 + + rc9@3.0.0: + dependencies: + defu: 6.1.4 + destr: 2.0.5 + + react-dom@19.2.4(react@19.2.4): + dependencies: + react: 19.2.4 + scheduler: 0.27.0 + + react@19.2.4: {} + + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + + readable-stream@4.7.0: + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + string_decoder: 1.3.0 + + readdir-glob@1.1.3: + dependencies: + minimatch: 5.1.9 + + readdirp@4.1.2: {} + + readdirp@5.0.0: {} + + redis-errors@1.2.0: {} + + redis-parser@3.0.0: + dependencies: + redis-errors: 1.2.0 + + regex-recursion@6.0.2: + dependencies: + regex-utilities: 2.3.0 + + regex-utilities@2.3.0: {} + + regex@6.1.0: + dependencies: + regex-utilities: 2.3.0 + + regexp-tree@0.1.27: {} + + rehype-external-links@3.0.0: + dependencies: + '@types/hast': 3.0.4 + '@ungap/structured-clone': 1.3.0 + hast-util-is-element: 3.0.0 + is-absolute-url: 4.0.1 + space-separated-tokens: 2.0.2 + unist-util-visit: 5.1.0 + + rehype-minify-whitespace@6.0.2: + dependencies: + '@types/hast': 3.0.4 + hast-util-minify-whitespace: 1.0.1 + + rehype-raw@7.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-raw: 9.1.0 + vfile: 6.0.3 + + rehype-remark@10.0.1: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + hast-util-to-mdast: 10.1.2 + unified: 11.0.5 + vfile: 6.0.3 + + rehype-slug@6.0.0: + dependencies: + '@types/hast': 3.0.4 + github-slugger: 2.0.0 + hast-util-heading-rank: 3.0.0 + hast-util-to-string: 3.0.1 + unist-util-visit: 5.1.0 + + rehype-sort-attribute-values@5.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-is-element: 3.0.0 + unist-util-visit: 5.1.0 + + rehype-sort-attributes@5.0.1: + dependencies: + '@types/hast': 3.0.4 + unist-util-visit: 5.1.0 + + reka-ui@2.8.2(vue@3.5.30(typescript@5.9.3)): + dependencies: + '@floating-ui/dom': 1.7.6 + '@floating-ui/vue': 1.1.11(vue@3.5.30(typescript@5.9.3)) + '@internationalized/date': 3.12.0 + '@internationalized/number': 3.6.5 + '@tanstack/vue-virtual': 3.13.21(vue@3.5.30(typescript@5.9.3)) + '@vueuse/core': 14.2.1(vue@3.5.30(typescript@5.9.3)) + '@vueuse/shared': 14.2.1(vue@3.5.30(typescript@5.9.3)) + aria-hidden: 1.2.6 + defu: 6.1.4 + ohash: 2.0.11 + vue: 3.5.30(typescript@5.9.3) + transitivePeerDependencies: + - '@vue/composition-api' + + remark-emoji@5.0.2: + dependencies: + '@types/mdast': 4.0.4 + emoticon: 4.1.0 + mdast-util-find-and-replace: 3.0.2 + node-emoji: 2.2.0 + unified: 11.0.5 + + remark-gfm@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-mdc@3.10.0: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + flat: 6.0.1 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + micromark: 4.0.2 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + parse-entities: 4.0.2 + scule: 1.3.0 + stringify-entities: 4.0.4 + unified: 11.0.5 + unist-util-visit: 5.1.0 + unist-util-visit-parents: 6.0.2 + yaml: 2.8.2 + transitivePeerDependencies: + - supports-color + + remark-parse@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + micromark-util-types: 2.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-rehype@11.1.2: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + mdast-util-to-hast: 13.2.1 + unified: 11.0.5 + vfile: 6.0.3 + + remark-stringify@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.1.2 + unified: 11.0.5 + + require-directory@2.1.1: {} + + resolve-from@5.0.0: {} + + resolve@1.22.11: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + reusify@1.1.0: {} + + robust-predicates@3.0.2: {} + + rollup-plugin-visualizer@6.0.11(rollup@4.59.0): + dependencies: + open: 8.4.2 + picomatch: 4.0.3 + source-map: 0.7.6 + yargs: 17.7.2 + optionalDependencies: + rollup: 4.59.0 + + rollup@4.59.0: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.59.0 + '@rollup/rollup-android-arm64': 4.59.0 + '@rollup/rollup-darwin-arm64': 4.59.0 + '@rollup/rollup-darwin-x64': 4.59.0 + '@rollup/rollup-freebsd-arm64': 4.59.0 + '@rollup/rollup-freebsd-x64': 4.59.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.59.0 + '@rollup/rollup-linux-arm-musleabihf': 4.59.0 + '@rollup/rollup-linux-arm64-gnu': 4.59.0 + '@rollup/rollup-linux-arm64-musl': 4.59.0 + '@rollup/rollup-linux-loong64-gnu': 4.59.0 + '@rollup/rollup-linux-loong64-musl': 4.59.0 + '@rollup/rollup-linux-ppc64-gnu': 4.59.0 + '@rollup/rollup-linux-ppc64-musl': 4.59.0 + '@rollup/rollup-linux-riscv64-gnu': 4.59.0 + '@rollup/rollup-linux-riscv64-musl': 4.59.0 + '@rollup/rollup-linux-s390x-gnu': 4.59.0 + '@rollup/rollup-linux-x64-gnu': 4.59.0 + '@rollup/rollup-linux-x64-musl': 4.59.0 + '@rollup/rollup-openbsd-x64': 4.59.0 + '@rollup/rollup-openharmony-arm64': 4.59.0 + '@rollup/rollup-win32-arm64-msvc': 4.59.0 + '@rollup/rollup-win32-ia32-msvc': 4.59.0 + '@rollup/rollup-win32-x64-gnu': 4.59.0 + '@rollup/rollup-win32-x64-msvc': 4.59.0 + fsevents: 2.3.3 + + rope-sequence@1.3.4: {} + + rou3@0.7.12: {} + + roughjs@4.6.6: + dependencies: + hachure-fill: 0.5.2 + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + points-on-path: 0.2.1 + + run-applescript@7.1.0: {} + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + rw@1.3.3: {} + + safe-buffer@5.1.2: {} + + safe-buffer@5.2.1: {} + + safer-buffer@2.1.2: {} + + sax@1.5.0: {} + + scheduler@0.27.0: {} + + scule@1.3.0: {} + + semver@6.3.1: {} + + semver@7.7.4: {} + + send@1.2.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + serialize-javascript@6.0.2: + dependencies: + randombytes: 2.1.0 + + seroval@1.5.1: {} + + serve-placeholder@2.0.2: + dependencies: + defu: 6.1.4 + + serve-static@2.2.1: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.1 + transitivePeerDependencies: + - supports-color + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + setprototypeof@1.2.0: {} + + sha.js@2.4.12: + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + to-buffer: 1.2.2 + + shaders@2.3.75(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vue@3.5.30(typescript@5.9.3)): + dependencies: + three: 0.183.2 + optionalDependencies: + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + vue: 3.5.30(typescript@5.9.3) + + sharp@0.34.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.7.4 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + optional: true + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + shell-quote@1.8.3: {} + + shiki@3.23.0: + dependencies: + '@shikijs/core': 3.23.0 + '@shikijs/engine-javascript': 3.23.0 + '@shikijs/engine-oniguruma': 3.23.0 + '@shikijs/langs': 3.23.0 + '@shikijs/themes': 3.23.0 + '@shikijs/types': 3.23.0 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + shiki@4.0.2: + dependencies: + '@shikijs/core': 4.0.2 + '@shikijs/engine-javascript': 4.0.2 + '@shikijs/engine-oniguruma': 4.0.2 + '@shikijs/langs': 4.0.2 + '@shikijs/themes': 4.0.2 + '@shikijs/types': 4.0.2 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + signal-exit@4.1.0: {} + + simple-concat@1.0.1: {} + + simple-get@4.0.1: + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + + simple-git@3.33.0: + dependencies: + '@kwsites/file-exists': 1.1.1 + '@kwsites/promise-deferred': 1.1.1 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + sirv@3.0.2: + dependencies: + '@polka/url': 1.0.0-next.29 + mrmime: 2.0.1 + totalist: 3.0.1 + + sisteransi@1.0.5: {} + + skin-tone@2.0.0: + dependencies: + unicode-emoji-modifier-base: 1.0.0 + + slash@5.1.0: {} + + slugify@1.6.6: {} + + smob@1.6.1: {} + + socket.io-client@4.8.3: + dependencies: + '@socket.io/component-emitter': 3.1.2 + debug: 4.4.3 + engine.io-client: 6.6.4 + socket.io-parser: 4.2.5 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + socket.io-parser@4.2.5: + dependencies: + '@socket.io/component-emitter': 3.1.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + source-map-js@1.2.1: {} + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + source-map@0.7.6: {} + + space-separated-tokens@2.0.2: {} + + srvx@0.11.9: {} + + standard-as-callback@2.1.0: {} + + statuses@2.0.2: {} + + std-env@3.10.0: {} + + streamx@2.23.0: + dependencies: + events-universal: 1.0.1 + fast-fifo: 1.3.2 + text-decoder: 1.2.7 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.2.0 + + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.2.0: + dependencies: + ansi-regex: 6.2.2 + + strip-final-newline@3.0.0: {} + + strip-literal@3.1.0: + dependencies: + js-tokens: 9.0.1 + + structured-clone-es@1.0.0: {} + + styled-jsx@5.1.6(@babel/core@7.29.0)(react@19.2.4): + dependencies: + client-only: 0.0.1 + react: 19.2.4 + optionalDependencies: + '@babel/core': 7.29.0 + + stylehacks@7.0.8(postcss@8.5.8): + dependencies: + browserslist: 4.28.1 + postcss: 8.5.8 + postcss-selector-parser: 7.1.1 + + stylis@4.3.6: {} + + supports-color@10.2.2: {} + + supports-preserve-symlinks-flag@1.0.0: {} + + svgo@4.0.1: + dependencies: + commander: 11.1.0 + css-select: 5.2.2 + css-tree: 3.2.1 + css-what: 6.2.2 + csso: 5.0.5 + picocolors: 1.1.1 + sax: 1.5.0 + + system-architecture@0.1.0: {} + + tagged-tag@1.0.0: {} + + tailwind-merge@3.5.0: {} + + tailwind-variants@3.2.2(tailwind-merge@3.5.0)(tailwindcss@4.2.1): + dependencies: + tailwindcss: 4.2.1 + optionalDependencies: + tailwind-merge: 3.5.0 + + tailwindcss@4.2.1: {} + + tapable@2.3.0: {} + + tar-stream@3.1.8: + dependencies: + b4a: 1.8.0 + bare-fs: 4.5.5 + fast-fifo: 1.3.2 + streamx: 2.23.0 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - react-native-b4a + + tar@7.5.11: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.3 + minizlib: 3.1.0 + yallist: 5.0.0 + + teex@1.0.1: + dependencies: + streamx: 2.23.0 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + terser@5.46.0: + dependencies: + '@jridgewell/source-map': 0.3.11 + acorn: 8.16.0 + commander: 2.20.3 + source-map-support: 0.5.21 + + text-decoder@1.2.7: + dependencies: + b4a: 1.8.0 + transitivePeerDependencies: + - react-native-b4a + + three@0.183.2: {} + + tiny-inflate@1.0.3: {} + + tiny-invariant@1.3.3: {} + + tinyexec@1.0.2: {} + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + to-buffer@1.2.2: + dependencies: + isarray: 2.0.5 + safe-buffer: 5.2.1 + typed-array-buffer: 1.0.3 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + toidentifier@1.0.1: {} + + totalist@3.0.1: {} + + tr46@0.0.3: {} + + trim-lines@3.0.1: {} + + trim-trailing-lines@2.1.0: {} + + trough@2.2.0: {} + + ts-dedent@2.2.0: {} + + tslib@2.8.1: {} + + type-fest@5.4.4: + dependencies: + tagged-tag: 1.0.0 + + type-level-regexp@0.1.17: {} + + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typescript@5.9.3: {} + + uc.micro@2.1.0: {} + + ufo@1.6.3: {} + + ultrahtml@1.6.0: {} + + uncrypto@0.1.3: {} + + unctx@2.5.0: + dependencies: + acorn: 8.16.0 + estree-walker: 3.0.3 + magic-string: 0.30.21 + unplugin: 2.3.11 + + undocs-nightly@0.4.17-20260310-213525-c3c295a(@parcel/watcher@2.5.6)(@tiptap/extensions@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))(@tiptap/y-tiptap@3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29))(@vue/compiler-sfc@3.5.30)(@vueuse/core@14.2.1(vue@3.5.30(typescript@5.9.3)))(cac@6.7.14)(chokidar@5.0.0)(db0@0.3.4)(dotenv@17.3.1)(embla-carousel@8.6.0)(giget@3.1.2)(ioredis@5.10.0)(jiti@2.6.1)(lightningcss@1.32.0)(magicast@0.5.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2))(vue-router@4.6.4(vue@3.5.30(typescript@5.9.3)))(yaml@2.8.2)(yjs@13.6.29)(zod@4.3.6): + dependencies: + '@headlessui/vue': 1.7.23(vue@3.5.30(typescript@5.9.3)) + '@nuxt/content': 3.12.0(magicast@0.5.2) + '@nuxt/fonts': 0.14.0(db0@0.3.4)(ioredis@5.10.0)(magicast@0.5.2)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2)) + '@nuxt/ui': 4.5.1(@nuxt/content@3.12.0(magicast@0.5.2))(@tiptap/extensions@3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1))(@tiptap/y-tiptap@3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29))(db0@0.3.4)(embla-carousel@8.6.0)(ioredis@5.10.0)(magicast@0.5.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tailwindcss@4.2.1)(typescript@5.9.3)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2))(vue-router@4.6.4(vue@3.5.30(typescript@5.9.3)))(vue@3.5.30(typescript@5.9.3))(yjs@13.6.29)(zod@4.3.6) + '@nuxtjs/plausible': 3.0.2(magicast@0.5.2) + '@resvg/resvg-wasm': 2.6.2 + automd: 0.4.3(magicast@0.5.2) + c12: 4.0.0-beta.3(chokidar@5.0.0)(dotenv@17.3.1)(giget@3.1.2)(jiti@2.6.1)(magicast@0.5.2) + citty: 0.2.1 + consola: 3.4.2 + defu: 6.1.4 + md4w: 0.2.7 + mdream: 0.17.0 + mermaid: 11.13.0 + motion-v: 2.0.0(@vueuse/core@14.2.1(vue@3.5.30(typescript@5.9.3)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vue@3.5.30(typescript@5.9.3)) + nuxi: 3.33.1 + nuxt: 4.3.1(@parcel/watcher@2.5.6)(@vue/compiler-sfc@3.5.30)(cac@6.7.14)(db0@0.3.4)(ioredis@5.10.0)(lightningcss@1.32.0)(magicast@0.5.2)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2))(yaml@2.8.2) + nuxt-llms: 0.2.0(magicast@0.5.2) + pathe: 2.0.3 + scule: 1.3.0 + shiki: 4.0.2 + tailwindcss: 4.2.1 + unctx: 2.5.0 + vue: 3.5.30(typescript@5.9.3) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@biomejs/biome' + - '@capacitor/preferences' + - '@deno/kv' + - '@electric-sql/pglite' + - '@emotion/is-prop-valid' + - '@inertiajs/vue3' + - '@libsql/client' + - '@netlify/blobs' + - '@parcel/watcher' + - '@planetscale/database' + - '@tiptap/extensions' + - '@tiptap/y-tiptap' + - '@types/node' + - '@upstash/redis' + - '@valibot/to-json-schema' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - '@vitejs/devtools' + - '@vue/compiler-sfc' + - '@vue/composition-api' + - '@vueuse/core' + - async-validator + - aws4fetch + - axios + - bare-abort-controller + - bare-buffer + - better-sqlite3 + - bufferutil + - cac + - change-case + - chokidar + - commander + - db0 + - dotenv + - drauu + - drizzle-orm + - embla-carousel + - encoding + - eslint + - focus-trap + - giget + - idb-keyval + - ioredis + - jiti + - joi + - jwt-decode + - less + - lightningcss + - magicast + - meow + - mysql2 + - nprogress + - optionator + - oxlint + - qrcode + - react + - react-dom + - react-native-b4a + - rolldown + - rollup + - sass + - sass-embedded + - sortablejs + - sqlite3 + - stylelint + - stylus + - sugarss + - superstruct + - supports-color + - terser + - tsx + - typescript + - universal-cookie + - uploadthing + - utf-8-validate + - valibot + - vite + - vls + - vti + - vue-router + - vue-tsc + - xml2js + - yaml + - yjs + - yup + - zod + + unenv@2.0.0-rc.24: + dependencies: + pathe: 2.0.3 + + unhead@2.1.12: + dependencies: + hookable: 6.0.1 + + unicode-emoji-modifier-base@1.0.0: {} + + unicorn-magic@0.3.0: {} + + unicorn-magic@0.4.0: {} + + unified@11.0.5: + dependencies: + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + + unifont@0.7.4: + dependencies: + css-tree: 3.2.1 + ofetch: 1.5.1 + ohash: 2.0.11 + + unimport@5.7.0: + dependencies: + acorn: 8.16.0 + escape-string-regexp: 5.0.0 + estree-walker: 3.0.3 + local-pkg: 1.1.2 + magic-string: 0.30.21 + mlly: 1.8.1 + pathe: 2.0.3 + picomatch: 4.0.3 + pkg-types: 2.3.0 + scule: 1.3.0 + strip-literal: 3.1.0 + tinyglobby: 0.2.15 + unplugin: 2.3.11 + unplugin-utils: 0.3.1 + + unist-builder@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-find-after@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.1.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + unplugin-auto-import@21.0.0(@nuxt/kit@4.3.1(magicast@0.5.2))(@vueuse/core@14.2.1(vue@3.5.30(typescript@5.9.3))): + dependencies: + local-pkg: 1.1.2 + magic-string: 0.30.21 + picomatch: 4.0.3 + unimport: 5.7.0 + unplugin: 2.3.11 + unplugin-utils: 0.3.1 + optionalDependencies: + '@nuxt/kit': 4.3.1(magicast@0.5.2) + '@vueuse/core': 14.2.1(vue@3.5.30(typescript@5.9.3)) + + unplugin-utils@0.3.1: + dependencies: + pathe: 2.0.3 + picomatch: 4.0.3 + + unplugin-vue-components@31.0.0(@nuxt/kit@4.3.1(magicast@0.5.2))(vue@3.5.30(typescript@5.9.3)): + dependencies: + chokidar: 5.0.0 + local-pkg: 1.1.2 + magic-string: 0.30.21 + mlly: 1.8.1 + obug: 2.1.1 + picomatch: 4.0.3 + tinyglobby: 0.2.15 + unplugin: 2.3.11 + unplugin-utils: 0.3.1 + vue: 3.5.30(typescript@5.9.3) + optionalDependencies: + '@nuxt/kit': 4.3.1(magicast@0.5.2) + + unplugin-vue-router@0.19.2(@vue/compiler-sfc@3.5.30)(vue-router@4.6.4(vue@3.5.30(typescript@5.9.3)))(vue@3.5.30(typescript@5.9.3)): + dependencies: + '@babel/generator': 7.29.1 + '@vue-macros/common': 3.1.2(vue@3.5.30(typescript@5.9.3)) + '@vue/compiler-sfc': 3.5.30 + '@vue/language-core': 3.2.5 + ast-walker-scope: 0.8.3 + chokidar: 5.0.0 + json5: 2.2.3 + local-pkg: 1.1.2 + magic-string: 0.30.21 + mlly: 1.8.1 + muggle-string: 0.4.1 + pathe: 2.0.3 + picomatch: 4.0.3 + scule: 1.3.0 + tinyglobby: 0.2.15 + unplugin: 2.3.11 + unplugin-utils: 0.3.1 + yaml: 2.8.2 + optionalDependencies: + vue-router: 4.6.4(vue@3.5.30(typescript@5.9.3)) + transitivePeerDependencies: + - vue + + unplugin@2.3.11: + dependencies: + '@jridgewell/remapping': 2.3.5 + acorn: 8.16.0 + picomatch: 4.0.3 + webpack-virtual-modules: 0.6.2 + + unplugin@3.0.0: + dependencies: + '@jridgewell/remapping': 2.3.5 + picomatch: 4.0.3 + webpack-virtual-modules: 0.6.2 + + unstorage@1.17.4(db0@0.3.4)(ioredis@5.10.0): + dependencies: + anymatch: 3.1.3 + chokidar: 5.0.0 + destr: 2.0.5 + h3: 1.15.6 + lru-cache: 11.2.6 + node-fetch-native: 1.6.7 + ofetch: 1.5.1 + ufo: 1.6.3 + optionalDependencies: + db0: 0.3.4 + ioredis: 5.10.0 + + untun@0.1.3: + dependencies: + citty: 0.1.6 + consola: 3.4.2 + pathe: 1.1.2 + + untyped@2.0.0: + dependencies: + citty: 0.1.6 + defu: 6.1.4 + jiti: 2.6.1 + knitwork: 1.3.0 + scule: 1.3.0 + + unwasm@0.5.3: + dependencies: + exsolve: 1.0.8 + knitwork: 1.3.0 + magic-string: 0.30.21 + mlly: 1.8.1 + pathe: 2.0.3 + pkg-types: 2.3.0 + + update-browserslist-db@1.2.3(browserslist@4.28.1): + dependencies: + browserslist: 4.28.1 + escalade: 3.2.0 + picocolors: 1.1.1 + + uqr@0.1.2: {} + + util-deprecate@1.0.2: {} + + uuid@11.1.0: {} + + vaul-vue@0.4.1(reka-ui@2.8.2(vue@3.5.30(typescript@5.9.3)))(vue@3.5.30(typescript@5.9.3)): + dependencies: + '@vueuse/core': 10.11.1(vue@3.5.30(typescript@5.9.3)) + reka-ui: 2.8.2(vue@3.5.30(typescript@5.9.3)) + vue: 3.5.30(typescript@5.9.3) + transitivePeerDependencies: + - '@vue/composition-api' + + vfile-location@5.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile: 6.0.3 + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + + vite-dev-rpc@1.1.0(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2)): + dependencies: + birpc: 2.9.0 + vite: 7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2) + vite-hot-client: 2.1.0(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2)) + + vite-hot-client@2.1.0(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2)): + dependencies: + vite: 7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2) + + vite-node@5.3.0(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2): + dependencies: + cac: 6.7.14 + es-module-lexer: 2.0.0 + obug: 2.1.1 + pathe: 2.0.3 + vite: 7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - yaml + + vite-plugin-checker@0.12.0(typescript@5.9.3)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2)): + dependencies: + '@babel/code-frame': 7.29.0 + chokidar: 4.0.3 + npm-run-path: 6.0.0 + picocolors: 1.1.1 + picomatch: 4.0.3 + tiny-invariant: 1.3.3 + tinyglobby: 0.2.15 + vite: 7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2) + vscode-uri: 3.1.0 + optionalDependencies: + typescript: 5.9.3 + + vite-plugin-inspect@11.3.3(@nuxt/kit@4.3.1(magicast@0.5.2))(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2)): + dependencies: + ansis: 4.2.0 + debug: 4.4.3 + error-stack-parser-es: 1.0.5 + ohash: 2.0.11 + open: 10.2.0 + perfect-debounce: 2.1.0 + sirv: 3.0.2 + unplugin-utils: 0.3.1 + vite: 7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2) + vite-dev-rpc: 1.1.0(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2)) + optionalDependencies: + '@nuxt/kit': 4.3.1(magicast@0.5.2) + transitivePeerDependencies: + - supports-color + + vite-plugin-vue-tracer@1.2.0(vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.30(typescript@5.9.3)): + dependencies: + estree-walker: 3.0.3 + exsolve: 1.0.8 + magic-string: 0.30.21 + pathe: 2.0.3 + source-map-js: 1.2.1 + vite: 7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2) + vue: 3.5.30(typescript@5.9.3) + + vite@7.3.1(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(yaml@2.8.2): + dependencies: + esbuild: 0.27.3 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.8 + rollup: 4.59.0 + tinyglobby: 0.2.15 + optionalDependencies: + fsevents: 2.3.3 + jiti: 2.6.1 + lightningcss: 1.32.0 + terser: 5.46.0 + yaml: 2.8.2 + + vscode-jsonrpc@8.2.0: {} + + vscode-languageserver-protocol@3.17.5: + dependencies: + vscode-jsonrpc: 8.2.0 + vscode-languageserver-types: 3.17.5 + + vscode-languageserver-textdocument@1.0.12: {} + + vscode-languageserver-types@3.17.5: {} + + vscode-languageserver@9.0.1: + dependencies: + vscode-languageserver-protocol: 3.17.5 + + vscode-uri@3.1.0: {} + + vue-bundle-renderer@2.2.0: + dependencies: + ufo: 1.6.3 + + vue-component-meta@3.2.5(typescript@5.9.3): + dependencies: + '@volar/typescript': 2.4.28 + '@vue/language-core': 3.2.5 + path-browserify: 1.0.1 + optionalDependencies: + typescript: 5.9.3 + + vue-component-type-helpers@3.2.5: {} + + vue-demi@0.14.10(vue@3.5.30(typescript@5.9.3)): + dependencies: + vue: 3.5.30(typescript@5.9.3) + + vue-devtools-stub@0.1.0: {} + + vue-router@4.6.4(vue@3.5.30(typescript@5.9.3)): + dependencies: + '@vue/devtools-api': 6.6.4 + vue: 3.5.30(typescript@5.9.3) + + vue@3.5.30(typescript@5.9.3): + dependencies: + '@vue/compiler-dom': 3.5.30 + '@vue/compiler-sfc': 3.5.30 + '@vue/runtime-dom': 3.5.30 + '@vue/server-renderer': 3.5.30(vue@3.5.30(typescript@5.9.3)) + '@vue/shared': 3.5.30 + optionalDependencies: + typescript: 5.9.3 + + w3c-keyname@2.2.8: {} + + web-namespaces@2.0.1: {} + + webidl-conversions@3.0.1: {} + + webpack-virtual-modules@0.6.2: {} + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + wheel-gestures@2.2.48: {} + + which-typed-array@1.1.20: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + which@5.0.0: + dependencies: + isexe: 3.1.5 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 5.1.2 + strip-ansi: 7.2.0 + + wrappy@1.0.2: {} + + ws@8.18.3: {} + + ws@8.19.0: {} + + wsl-utils@0.1.0: + dependencies: + is-wsl: 3.1.1 + + xmlhttprequest-ssl@2.1.2: {} + + y-protocols@1.0.7(yjs@13.6.29): + dependencies: + lib0: 0.2.117 + yjs: 13.6.29 + + y18n@5.0.8: {} + + yallist@3.1.1: {} + + yallist@5.0.0: {} + + yaml@2.8.2: {} + + yargs-parser@21.1.1: {} + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yjs@13.6.29: + dependencies: + lib0: 0.2.117 + + youch-core@0.3.3: + dependencies: + '@poppinss/exception': 1.2.3 + error-stack-parser-es: 1.0.5 + + youch@4.1.0: + dependencies: + '@poppinss/colors': 4.1.6 + '@poppinss/dumper': 0.7.0 + '@speed-highlight/core': 1.2.14 + cookie-es: 2.0.0 + youch-core: 0.3.3 + + zip-stream@6.0.1: + dependencies: + archiver-utils: 5.0.2 + compress-commons: 6.0.2 + readable-stream: 4.7.0 + + zod-to-json-schema@3.25.1(zod@3.25.76): + dependencies: + zod: 3.25.76 + + zod@3.25.76: {} + + zod@4.3.6: {} + + zwitch@2.0.4: {} diff --git a/docs/pnpm-workspace.yaml b/docs/pnpm-workspace.yaml new file mode 100644 index 0000000000..b8691c8845 --- /dev/null +++ b/docs/pnpm-workspace.yaml @@ -0,0 +1,10 @@ +packages: [] + +ignoredBuiltDependencies: + - '@parcel/watcher' + - '@tailwindcss/oxide' + - esbuild + - vue-demi + +onlyBuiltDependencies: + - better-sqlite3 diff --git a/eslint.config.mjs b/eslint.config.mjs deleted file mode 100644 index c2fb62f134..0000000000 --- a/eslint.config.mjs +++ /dev/null @@ -1,22 +0,0 @@ -import unjs from "eslint-config-unjs"; - -export default unjs({ - ignores: [ - "**/.output", - "**/.nitro", - "**/.netlify", - "**/.vercel", - "**/.nuxt", - "**/*.gen.*", - "**/dist", - ], - rules: { - "unicorn/no-null": 0, - "no-undef": 0, - "@typescript-eslint/no-unused-vars": 0, - "unicorn/filename-case": 0, - "unicorn/consistent-function-scoping": 0, - "@typescript-eslint/no-empty-object-type": 0, - "unicorn/no-empty-file": 0, - }, -}); diff --git a/examples/api-routes/README.md b/examples/api-routes/README.md new file mode 100644 index 0000000000..3cd430b58e --- /dev/null +++ b/examples/api-routes/README.md @@ -0,0 +1,51 @@ +Nitro supports file-based routing in the `api/` or `routes/` directory. Each file becomes an API endpoint based on its path. + +## Basic Route + +Create a file in the `api/` directory to define a route. The file path becomes the URL path: + +```ts [api/hello.ts] +import { defineHandler } from "nitro"; + +export default defineHandler(() => "Nitro is amazing!"); +``` + +This creates a `GET /api/hello` endpoint. + +## Dynamic Routes + +Use square brackets `[param]` for dynamic URL segments. Access params via `event.context.params`: + +```ts [api/hello/[name].ts] +import { defineHandler } from "nitro"; + +export default defineHandler((event) => `Hello (param: ${event.context.params!.name})!`); +``` + +This creates a `GET /api/hello/:name` endpoint (e.g., `/api/hello/world`). + +## HTTP Methods + +Suffix your file with the HTTP method (`.get.ts`, `.post.ts`, `.put.ts`, `.delete.ts`, etc.): + +### GET Handler + +```ts [api/test.get.ts] +import { defineHandler } from "nitro"; + +export default defineHandler(() => "Test get handler"); +``` + +### POST Handler + +```ts [api/test.post.ts] +import { defineHandler } from "nitro"; + +export default defineHandler(async (event) => { + const body = await event.req.json(); + return { + message: "Test post handler", + body, + }; +}); +``` diff --git a/examples/api-routes/api/hello.ts b/examples/api-routes/api/hello.ts index 21fe2776d8..a14364644e 100644 --- a/examples/api-routes/api/hello.ts +++ b/examples/api-routes/api/hello.ts @@ -1 +1,3 @@ -export default defineEventHandler(() => "Nitro is amazing!"); +import { defineHandler } from "nitro"; + +export default defineHandler(() => "Nitro is amazing!"); diff --git a/examples/api-routes/api/hello/[name].ts b/examples/api-routes/api/hello/[name].ts index ee43aab612..0de138b7ba 100644 --- a/examples/api-routes/api/hello/[name].ts +++ b/examples/api-routes/api/hello/[name].ts @@ -1,3 +1,3 @@ -export default defineEventHandler( - (event) => `Hello ${event.context.params.name}!` -); +import { defineHandler } from "nitro"; + +export default defineHandler((event) => `Hello (param: ${event.context.params!.name})!`); diff --git a/examples/api-routes/api/test.get.ts b/examples/api-routes/api/test.get.ts index 927dfd195e..394f899fd1 100644 --- a/examples/api-routes/api/test.get.ts +++ b/examples/api-routes/api/test.get.ts @@ -1 +1,3 @@ -export default defineEventHandler(() => "Test get handler"); +import { defineHandler } from "nitro"; + +export default defineHandler(() => "Test get handler"); diff --git a/examples/api-routes/api/test.post.ts b/examples/api-routes/api/test.post.ts index e26a13ca3e..82a161fd04 100644 --- a/examples/api-routes/api/test.post.ts +++ b/examples/api-routes/api/test.post.ts @@ -1,5 +1,7 @@ -export default defineEventHandler(async (event) => { - const body = await readBody(event); +import { defineHandler } from "nitro"; + +export default defineHandler(async (event) => { + const body = await event.req.json(); return { message: "Test post handler", body, diff --git a/examples/api-routes/index.html b/examples/api-routes/index.html new file mode 100644 index 0000000000..a98b747764 --- /dev/null +++ b/examples/api-routes/index.html @@ -0,0 +1,16 @@ + + + + + + API Routes + + +

API Routes:

+ + + diff --git a/examples/api-routes/nitro.config.ts b/examples/api-routes/nitro.config.ts index e83a8daf81..e87bfb1938 100644 --- a/examples/api-routes/nitro.config.ts +++ b/examples/api-routes/nitro.config.ts @@ -1,3 +1,5 @@ -export default defineNitroConfig({ - compatibilityDate: "2025-03-01", +import { defineConfig } from "nitro"; + +export default defineConfig({ + serverDir: "./", }); diff --git a/examples/api-routes/package.json b/examples/api-routes/package.json index 99f13ac46a..736abd40ad 100644 --- a/examples/api-routes/package.json +++ b/examples/api-routes/package.json @@ -1,11 +1,10 @@ { - "name": "example-api-routes", - "private": true, + "type": "module", "scripts": { "dev": "nitro dev", "build": "nitro build" }, "devDependencies": { - "nitropack": "latest" + "nitro": "latest" } } diff --git a/examples/api-routes/routes/[...].ts b/examples/api-routes/routes/[...].ts deleted file mode 100644 index 22a7d27ec0..0000000000 --- a/examples/api-routes/routes/[...].ts +++ /dev/null @@ -1,10 +0,0 @@ -export default defineEventHandler(() => { - return ` -

API Routes:

- -`; -}); diff --git a/examples/api-routes/tsconfig.json b/examples/api-routes/tsconfig.json index 43008af1c7..4b886bd47e 100644 --- a/examples/api-routes/tsconfig.json +++ b/examples/api-routes/tsconfig.json @@ -1,3 +1,3 @@ { - "extends": "./.nitro/types/tsconfig.json" + "extends": "nitro/tsconfig" } diff --git a/examples/api-routes/vite.config.ts b/examples/api-routes/vite.config.ts new file mode 100644 index 0000000000..34d3353e1c --- /dev/null +++ b/examples/api-routes/vite.config.ts @@ -0,0 +1,4 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); diff --git a/examples/auto-imports/README.md b/examples/auto-imports/README.md new file mode 100644 index 0000000000..adf409b39b --- /dev/null +++ b/examples/auto-imports/README.md @@ -0,0 +1,35 @@ +Functions exported from `server/utils/` are automatically available without explicit imports when auto-imports are enabled. Define a utility once and use it anywhere in your server code. + +## Configuration + +Enable auto-imports by setting `imports` in your config: + +```ts [nitro.config.ts] +import { defineConfig } from "nitro"; + +export default defineConfig({ + serverDir: true, + imports: {}, +}); +``` + +## Using Auto Imports + +1. Create a utility file in `server/utils/`: + +```ts [server/utils/hello.ts] +export function makeGreeting(name: string) { + return `Hello, ${name}!`; +} +``` + +2. The function is available without importing it: + +```ts [server.ts] +import { defineHandler } from "nitro"; +import { makeGreeting } from "./server/utils/hello.ts"; + +export default defineHandler(() => `

${makeGreeting("Nitro")}

`); +``` + +With this setup, any function exported from `server/utils/` becomes globally available. Nitro scans the directory and generates the necessary imports automatically. diff --git a/examples/auto-imports/nitro.config.ts b/examples/auto-imports/nitro.config.ts index e83a8daf81..92e639d056 100644 --- a/examples/auto-imports/nitro.config.ts +++ b/examples/auto-imports/nitro.config.ts @@ -1,3 +1,6 @@ -export default defineNitroConfig({ - compatibilityDate: "2025-03-01", +import { defineConfig } from "nitro"; + +export default defineConfig({ + serverDir: true, + imports: {}, }); diff --git a/examples/auto-imports/package.json b/examples/auto-imports/package.json index 9629263db6..736abd40ad 100644 --- a/examples/auto-imports/package.json +++ b/examples/auto-imports/package.json @@ -1,11 +1,10 @@ { - "name": "example-auto-imports", - "private": true, + "type": "module", "scripts": { "dev": "nitro dev", "build": "nitro build" }, "devDependencies": { - "nitropack": "latest" + "nitro": "latest" } } diff --git a/examples/auto-imports/routes/index.ts b/examples/auto-imports/routes/index.ts deleted file mode 100644 index 700dfa0f30..0000000000 --- a/examples/auto-imports/routes/index.ts +++ /dev/null @@ -1 +0,0 @@ -export default defineEventHandler(() => `

${makeGreeting("Nitro")}

`); diff --git a/examples/auto-imports/server.ts b/examples/auto-imports/server.ts new file mode 100644 index 0000000000..90391beea3 --- /dev/null +++ b/examples/auto-imports/server.ts @@ -0,0 +1,4 @@ +import { defineHandler } from "nitro"; +import { makeGreeting } from "./server/utils/hello.ts"; + +export default defineHandler(() => `

${makeGreeting("Nitro")}

`); diff --git a/examples/auto-imports/utils/hello.ts b/examples/auto-imports/server/utils/hello.ts similarity index 100% rename from examples/auto-imports/utils/hello.ts rename to examples/auto-imports/server/utils/hello.ts diff --git a/examples/auto-imports/tsconfig.json b/examples/auto-imports/tsconfig.json index 43008af1c7..972dd4b7f2 100644 --- a/examples/auto-imports/tsconfig.json +++ b/examples/auto-imports/tsconfig.json @@ -1,3 +1,3 @@ { - "extends": "./.nitro/types/tsconfig.json" + "include": [".nitro/types/nitro-imports.d.ts", "src"] } diff --git a/examples/auto-imports/vite.config.ts b/examples/auto-imports/vite.config.ts new file mode 100644 index 0000000000..34d3353e1c --- /dev/null +++ b/examples/auto-imports/vite.config.ts @@ -0,0 +1,4 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); diff --git a/examples/cached-handler/README.md b/examples/cached-handler/README.md new file mode 100644 index 0000000000..2128b4eab1 --- /dev/null +++ b/examples/cached-handler/README.md @@ -0,0 +1,21 @@ +This example shows how to cache an expensive operation (a 500 ms delay) and conditionally bypass the cache using a query parameter. On first request, the handler executes and caches the result. Subsequent requests return the cached response instantly until the cache expires or is bypassed. + +## How It Works + +```ts [server.ts] +import { html } from "nitro"; +import { defineCachedHandler } from "nitro/cache"; + +export default defineCachedHandler( + async () => { + await new Promise((resolve) => setTimeout(resolve, 500)); + return html` + Response generated at ${new Date().toISOString()} (took 500ms) +
(skip cache) + `; + }, + { shouldBypassCache: ({ req }) => req.url.includes("skipCache=true") } +); +``` + +The handler simulates a slow operation with a 500ms delay. As `defineCachedHandler` wraps it, the response is cached after the first execution. The `shouldBypassCache` option checks for `?skipCache=true` in the URL and when present the cache is skipped and the handler runs fresh. diff --git a/examples/cached-handler/nitro.config.ts b/examples/cached-handler/nitro.config.ts index e83a8daf81..50c7c4fd97 100644 --- a/examples/cached-handler/nitro.config.ts +++ b/examples/cached-handler/nitro.config.ts @@ -1,3 +1,3 @@ -export default defineNitroConfig({ - compatibilityDate: "2025-03-01", -}); +import { defineConfig } from "nitro"; + +export default defineConfig({}); diff --git a/examples/cached-handler/package.json b/examples/cached-handler/package.json index 4c7eb5aa7c..736abd40ad 100644 --- a/examples/cached-handler/package.json +++ b/examples/cached-handler/package.json @@ -1,11 +1,10 @@ { - "name": "example-cached-handler", - "private": true, + "type": "module", "scripts": { "dev": "nitro dev", "build": "nitro build" }, "devDependencies": { - "nitropack": "latest" + "nitro": "latest" } } diff --git a/examples/cached-handler/routes/index.ts b/examples/cached-handler/routes/index.ts deleted file mode 100644 index 48f2a83875..0000000000 --- a/examples/cached-handler/routes/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -export default defineCachedEventHandler( - async () => { - await new Promise((resolve) => setTimeout(resolve, 1000)); - return `Response generated at ${new Date().toISOString()} (took 1 second)`; - }, - { - shouldBypassCache: (e) => e.node.req.url.includes("preview"), - } -); diff --git a/examples/cached-handler/server.ts b/examples/cached-handler/server.ts new file mode 100644 index 0000000000..49456227d9 --- /dev/null +++ b/examples/cached-handler/server.ts @@ -0,0 +1,13 @@ +import { html } from "nitro"; +import { defineCachedHandler } from "nitro/cache"; + +export default defineCachedHandler( + async () => { + await new Promise((resolve) => setTimeout(resolve, 500)); + return html` + Response generated at ${new Date().toISOString()} (took 500ms) +
(skip cache) + `; + }, + { shouldBypassCache: ({ req }) => req.url.includes("skipCache=true") } +); diff --git a/examples/cached-handler/tsconfig.json b/examples/cached-handler/tsconfig.json index 43008af1c7..4b886bd47e 100644 --- a/examples/cached-handler/tsconfig.json +++ b/examples/cached-handler/tsconfig.json @@ -1,3 +1,3 @@ { - "extends": "./.nitro/types/tsconfig.json" + "extends": "nitro/tsconfig" } diff --git a/examples/cached-handler/vite.config.ts b/examples/cached-handler/vite.config.ts new file mode 100644 index 0000000000..34d3353e1c --- /dev/null +++ b/examples/cached-handler/vite.config.ts @@ -0,0 +1,4 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); diff --git a/examples/custom-error-handler/README.md b/examples/custom-error-handler/README.md new file mode 100644 index 0000000000..47a6cfb69a --- /dev/null +++ b/examples/custom-error-handler/README.md @@ -0,0 +1,32 @@ +This example shows how to intercept all errors and return a custom response format. When any route throws an error, Nitro calls your error handler instead of returning the default error page. + +## Error Handler + +Create an `error.ts` file in your project root to define the global error handler: + +```ts [error.ts] +import { defineErrorHandler } from "nitro"; + +export default defineErrorHandler((error, _event) => { + return new Response(`Custom Error Handler: ${error.message}`, { + status: 500, + headers: { "Content-Type": "text/plain" }, + }); +}); +``` + +The handler receives the thrown error and the H3 event object. You can use the event to access request details like headers, cookies, or the URL path to customize responses per route. + +## Triggering an Error + +The main handler throws an error to demonstrate the custom error handler: + +```ts [server.ts] +import { defineHandler, HTTPError } from "nitro"; + +export default defineHandler(() => { + throw new HTTPError("Example Error!", { status: 500 }); +}); +``` + +When you visit the page, instead of seeing a generic error page, you'll see "Custom Error Handler: Example Error!" because the error handler intercepts the thrown error. diff --git a/examples/custom-error-handler/error.ts b/examples/custom-error-handler/error.ts index c2b46126cd..c37b2ec061 100644 --- a/examples/custom-error-handler/error.ts +++ b/examples/custom-error-handler/error.ts @@ -1,7 +1,8 @@ -import type { NitroErrorHandler } from "nitropack"; +import { defineErrorHandler } from "nitro"; -const errorHandler: NitroErrorHandler = function (error, event) { - event.res.end("[custom error handler] " + error.stack); -}; - -export default errorHandler; +export default defineErrorHandler((error, _event) => { + return new Response(`Custom Error Handler: ${error.message}`, { + status: 500, + headers: { "Content-Type": "text/plain" }, + }); +}); diff --git a/examples/custom-error-handler/nitro.config.ts b/examples/custom-error-handler/nitro.config.ts index d0dfc5f119..57da7f5bbf 100644 --- a/examples/custom-error-handler/nitro.config.ts +++ b/examples/custom-error-handler/nitro.config.ts @@ -1,7 +1,7 @@ -import errorHandler from "./error"; +import { defineConfig } from "nitro"; +// import errorHandler from "./error"; -export default defineNitroConfig({ - compatibilityDate: "2025-03-01", - errorHandler: "~/error", - devErrorHandler: errorHandler, +export default defineConfig({ + errorHandler: "./error.ts", + // devErrorHandler: errorHandler, }); diff --git a/examples/custom-error-handler/package.json b/examples/custom-error-handler/package.json index 3b576230f1..736abd40ad 100644 --- a/examples/custom-error-handler/package.json +++ b/examples/custom-error-handler/package.json @@ -1,11 +1,10 @@ { - "name": "example-custom-error-handler", - "private": true, + "type": "module", "scripts": { "dev": "nitro dev", "build": "nitro build" }, "devDependencies": { - "nitropack": "latest" + "nitro": "latest" } } diff --git a/examples/custom-error-handler/routes/index.ts b/examples/custom-error-handler/routes/index.ts deleted file mode 100644 index 820c4b6596..0000000000 --- a/examples/custom-error-handler/routes/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default defineEventHandler(() => { - throw new Error("Example Error!"); -}); diff --git a/examples/custom-error-handler/server.ts b/examples/custom-error-handler/server.ts new file mode 100644 index 0000000000..6bd9802608 --- /dev/null +++ b/examples/custom-error-handler/server.ts @@ -0,0 +1,5 @@ +import { defineHandler, HTTPError } from "nitro"; + +export default defineHandler(() => { + throw new HTTPError("Example Error!", { status: 500 }); +}); diff --git a/examples/custom-error-handler/tsconfig.json b/examples/custom-error-handler/tsconfig.json index 43008af1c7..4b886bd47e 100644 --- a/examples/custom-error-handler/tsconfig.json +++ b/examples/custom-error-handler/tsconfig.json @@ -1,3 +1,3 @@ { - "extends": "./.nitro/types/tsconfig.json" + "extends": "nitro/tsconfig" } diff --git a/examples/custom-error-handler/vite.config.ts b/examples/custom-error-handler/vite.config.ts new file mode 100644 index 0000000000..34d3353e1c --- /dev/null +++ b/examples/custom-error-handler/vite.config.ts @@ -0,0 +1,4 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); diff --git a/examples/database/README.md b/examples/database/README.md new file mode 100644 index 0000000000..4d7d25fafd --- /dev/null +++ b/examples/database/README.md @@ -0,0 +1,57 @@ +Nitro provides a built-in database layer that uses SQL template literals for safe, parameterized queries. This example creates a users table, inserts a record, and queries it back. + +## Querying the Database + +```ts [server.ts] +import { defineHandler } from "nitro"; +import { useDatabase } from "nitro/database"; + +export default defineHandler(async () => { + const db = useDatabase(); + + // Create users table + await db.sql`DROP TABLE IF EXISTS users`; + await db.sql`CREATE TABLE IF NOT EXISTS users ("id" TEXT PRIMARY KEY, "firstName" TEXT, "lastName" TEXT, "email" TEXT)`; + + // Add a new user + const userId = String(Math.round(Math.random() * 10_000)); + await db.sql`INSERT INTO users VALUES (${userId}, 'John', 'Doe', '')`; + + // Query for users + const { rows } = await db.sql`SELECT * FROM users WHERE id = ${userId}`; + + return { + rows, + }; +}); +``` + +Retrieve the database instance using `useDatabase()`. The database can be queried using `db.sql`, and variables like `${userId}` are automatically escaped to prevent SQL injection. + +## Running Migrations with Tasks + +Nitro tasks let you run operations outside of request handlers. For database migrations, create a task file in `tasks/` and run it via the CLI. This keeps schema changes separate from your application code. + +```ts [tasks/db/migrate.ts] +import { defineTask } from "nitro/task"; +import { useDatabase } from "nitro/database"; + +export default defineTask({ + meta: { + description: "Run database migrations", + }, + async run() { + const db = useDatabase(); + + console.log("Running database migrations..."); + + // Create users table + await db.sql`DROP TABLE IF EXISTS users`; + await db.sql`CREATE TABLE IF NOT EXISTS users ("id" TEXT PRIMARY KEY, "firstName" TEXT, "lastName" TEXT, "email" TEXT)`; + + return { + result: "Database migrations complete!", + }; + }, +}); +``` diff --git a/examples/database/nitro.config.ts b/examples/database/nitro.config.ts index 5d83a5b741..d99fc9679a 100644 --- a/examples/database/nitro.config.ts +++ b/examples/database/nitro.config.ts @@ -1,7 +1,11 @@ -export default defineNitroConfig({ - compatibilityDate: "2025-03-01", +import { defineConfig } from "nitro"; + +export default defineConfig({ experimental: { database: true, tasks: true, }, + database: { + default: { connector: "sqlite" }, + }, }); diff --git a/examples/database/package.json b/examples/database/package.json index 7fe35275e5..736abd40ad 100644 --- a/examples/database/package.json +++ b/examples/database/package.json @@ -1,11 +1,10 @@ { - "name": "example-database", - "private": true, + "type": "module", "scripts": { "dev": "nitro dev", "build": "nitro build" }, "devDependencies": { - "nitropack": "latest" + "nitro": "latest" } } diff --git a/examples/database/routes/index.ts b/examples/database/server.ts similarity index 79% rename from examples/database/routes/index.ts rename to examples/database/server.ts index c68a24d5d6..6472de84d6 100644 --- a/examples/database/routes/index.ts +++ b/examples/database/server.ts @@ -1,4 +1,7 @@ -export default defineEventHandler(async () => { +import { defineHandler } from "nitro"; +import { useDatabase } from "nitro/database"; + +export default defineHandler(async () => { const db = useDatabase(); // Create users table diff --git a/examples/database/tasks/db/migrate.ts b/examples/database/tasks/db/migrate.ts index 11155f34a7..58c4ee1fb0 100644 --- a/examples/database/tasks/db/migrate.ts +++ b/examples/database/tasks/db/migrate.ts @@ -1,3 +1,6 @@ +import { defineTask } from "nitro/task"; +import { useDatabase } from "nitro/database"; + export default defineTask({ meta: { description: "Run database migrations", diff --git a/examples/database/tsconfig.json b/examples/database/tsconfig.json index 43008af1c7..4b886bd47e 100644 --- a/examples/database/tsconfig.json +++ b/examples/database/tsconfig.json @@ -1,3 +1,3 @@ { - "extends": "./.nitro/types/tsconfig.json" + "extends": "nitro/tsconfig" } diff --git a/examples/database/vite.config.ts b/examples/database/vite.config.ts new file mode 100644 index 0000000000..34d3353e1c --- /dev/null +++ b/examples/database/vite.config.ts @@ -0,0 +1,4 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); diff --git a/examples/elysia/README.md b/examples/elysia/README.md new file mode 100644 index 0000000000..ca543c5a64 --- /dev/null +++ b/examples/elysia/README.md @@ -0,0 +1,15 @@ +## Server Entry + +```ts [server.ts] +import { Elysia } from "elysia"; + +const app = new Elysia(); + +app.get("/", () => "Hello, Elysia with Nitro!"); + +export default app.compile(); +``` + +Nitro auto-detects `server.ts` in your project root and uses it as the server entry. The Elysia app handles all incoming requests, giving you full control over routing and middleware. + +Call `app.compile()` before exporting to optimize the router for production. diff --git a/examples/elysia/nitro.config.ts b/examples/elysia/nitro.config.ts new file mode 100644 index 0000000000..50c7c4fd97 --- /dev/null +++ b/examples/elysia/nitro.config.ts @@ -0,0 +1,3 @@ +import { defineConfig } from "nitro"; + +export default defineConfig({}); diff --git a/examples/elysia/package.json b/examples/elysia/package.json new file mode 100644 index 0000000000..49b9e9a47a --- /dev/null +++ b/examples/elysia/package.json @@ -0,0 +1,11 @@ +{ + "type": "module", + "scripts": { + "build": "nitro build", + "dev": "nitro dev" + }, + "devDependencies": { + "elysia": "^1.4.22", + "nitro": "latest" + } +} diff --git a/examples/elysia/server.ts b/examples/elysia/server.ts new file mode 100644 index 0000000000..4c8ff28f89 --- /dev/null +++ b/examples/elysia/server.ts @@ -0,0 +1,7 @@ +import { Elysia } from "elysia"; + +const app = new Elysia(); + +app.get("/", () => "Hello, Elysia with Nitro!"); + +export default app.compile(); diff --git a/examples/elysia/tsconfig.json b/examples/elysia/tsconfig.json new file mode 100644 index 0000000000..4b886bd47e --- /dev/null +++ b/examples/elysia/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "nitro/tsconfig" +} diff --git a/examples/elysia/vite.config.ts b/examples/elysia/vite.config.ts new file mode 100644 index 0000000000..34d3353e1c --- /dev/null +++ b/examples/elysia/vite.config.ts @@ -0,0 +1,4 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); diff --git a/examples/express/README.md b/examples/express/README.md new file mode 100644 index 0000000000..322fb68aaa --- /dev/null +++ b/examples/express/README.md @@ -0,0 +1,19 @@ +## Server Entry + +```ts [server.node.ts] +import Express from "express"; + +const app = Express(); + +app.use("/", (_req, res) => { + res.send("Hello from Express with Nitro!"); +}); + +export default app; +``` + +Nitro auto-detects `server.node.ts` in your project root and uses it as the server entry. The Express app handles all incoming requests, giving you full control over routing and middleware. + +::note +The `.node.ts` suffix indicates this entry is Node.js specific and won't work in other runtimes like Cloudflare Workers or Deno. +:: diff --git a/examples/express/nitro.config.ts b/examples/express/nitro.config.ts new file mode 100644 index 0000000000..50c7c4fd97 --- /dev/null +++ b/examples/express/nitro.config.ts @@ -0,0 +1,3 @@ +import { defineConfig } from "nitro"; + +export default defineConfig({}); diff --git a/examples/express/package.json b/examples/express/package.json new file mode 100644 index 0000000000..f69d4fc12a --- /dev/null +++ b/examples/express/package.json @@ -0,0 +1,12 @@ +{ + "type": "module", + "scripts": { + "build": "nitro build", + "dev": "nitro dev" + }, + "devDependencies": { + "@types/express": "^5.0.6", + "express": "^5.2.1", + "nitro": "latest" + } +} diff --git a/examples/express/server.node.ts b/examples/express/server.node.ts new file mode 100644 index 0000000000..0129f38bf1 --- /dev/null +++ b/examples/express/server.node.ts @@ -0,0 +1,9 @@ +import Express from "express"; + +const app = Express(); + +app.use("/", (_req, res) => { + res.send("Hello from Express with Nitro!"); +}); + +export default app; diff --git a/examples/express/tsconfig.json b/examples/express/tsconfig.json new file mode 100644 index 0000000000..4b886bd47e --- /dev/null +++ b/examples/express/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "nitro/tsconfig" +} diff --git a/examples/express/vite.config.ts b/examples/express/vite.config.ts new file mode 100644 index 0000000000..34d3353e1c --- /dev/null +++ b/examples/express/vite.config.ts @@ -0,0 +1,4 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); diff --git a/examples/fastify/README.md b/examples/fastify/README.md new file mode 100644 index 0000000000..14ad1102dd --- /dev/null +++ b/examples/fastify/README.md @@ -0,0 +1,21 @@ +## Server Entry + +```ts [server.node.ts] +import Fastify from "fastify"; + +const app = Fastify(); + +app.get("/", () => "Hello, Fastify with Nitro!"); + +await app.ready(); + +export default app.routing; +``` + +Nitro auto-detects `server.node.ts` in your project root and uses it as the server entry. + +Call `await app.ready()` to initialize all registered plugins before exporting. Export `app.routing` (not `app`) to provide Nitro with the request handler function. + +::note +The `.node.ts` suffix indicates this entry is Node.js specific and won't work in other runtimes like Cloudflare Workers or Deno. +:: diff --git a/examples/fastify/nitro.config.ts b/examples/fastify/nitro.config.ts new file mode 100644 index 0000000000..50c7c4fd97 --- /dev/null +++ b/examples/fastify/nitro.config.ts @@ -0,0 +1,3 @@ +import { defineConfig } from "nitro"; + +export default defineConfig({}); diff --git a/examples/fastify/package.json b/examples/fastify/package.json new file mode 100644 index 0000000000..30944aa68f --- /dev/null +++ b/examples/fastify/package.json @@ -0,0 +1,11 @@ +{ + "type": "module", + "scripts": { + "build": "nitro build", + "dev": "nitro dev" + }, + "devDependencies": { + "fastify": "^5.7.4", + "nitro": "latest" + } +} diff --git a/examples/fastify/server.node.ts b/examples/fastify/server.node.ts new file mode 100644 index 0000000000..475d735d1e --- /dev/null +++ b/examples/fastify/server.node.ts @@ -0,0 +1,9 @@ +import Fastify from "fastify"; + +const app = Fastify(); + +app.get("/", () => "Hello, Fastify with Nitro!"); + +await app.ready(); + +export default app.routing; diff --git a/examples/fastify/tsconfig.json b/examples/fastify/tsconfig.json new file mode 100644 index 0000000000..4b886bd47e --- /dev/null +++ b/examples/fastify/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "nitro/tsconfig" +} diff --git a/examples/fastify/vite.config.ts b/examples/fastify/vite.config.ts new file mode 100644 index 0000000000..34d3353e1c --- /dev/null +++ b/examples/fastify/vite.config.ts @@ -0,0 +1,4 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); diff --git a/examples/graceful-shutdown/nitro.config.ts b/examples/graceful-shutdown/nitro.config.ts deleted file mode 100644 index 5787a5ed6c..0000000000 --- a/examples/graceful-shutdown/nitro.config.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { defineNitroConfig } from "nitropack/config"; - -export default defineNitroConfig({ - compatibilityDate: "2025-03-01", -}); diff --git a/examples/graceful-shutdown/plugins/db.ts b/examples/graceful-shutdown/plugins/db.ts deleted file mode 100644 index b142dd71bb..0000000000 --- a/examples/graceful-shutdown/plugins/db.ts +++ /dev/null @@ -1,10 +0,0 @@ -export default defineNitroPlugin((nitroApp) => { - nitroApp.hooks.hookOnce("close", async () => { - console.log("Disconnecting database..."); - - // something you want to do, such like disconnect the database, or wait until the task is done - await new Promise((resolve) => setTimeout(resolve, 500)); - - console.log("Database is disconnected!"); - }); -}); diff --git a/examples/graceful-shutdown/routes/index.ts b/examples/graceful-shutdown/routes/index.ts deleted file mode 100644 index e42503e598..0000000000 --- a/examples/graceful-shutdown/routes/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { eventHandler } from "h3"; - -export default eventHandler(async () => { - console.log("Event handler is running..."); - await new Promise((resolve) => setTimeout(resolve, 2000)); - return { message: "Response took 2 seconds" }; -}); diff --git a/examples/graceful-shutdown/tsconfig.json b/examples/graceful-shutdown/tsconfig.json deleted file mode 100644 index 43008af1c7..0000000000 --- a/examples/graceful-shutdown/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./.nitro/types/tsconfig.json" -} diff --git a/examples/hello-world/.gitignore b/examples/hello-world/.gitignore deleted file mode 100644 index ebe9be8721..0000000000 --- a/examples/hello-world/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -node_modules -dist -.data -.nitro -.cache -.output -.env diff --git a/examples/hello-world/README.md b/examples/hello-world/README.md index b161ee5d42..60861b543f 100644 --- a/examples/hello-world/README.md +++ b/examples/hello-world/README.md @@ -1,3 +1,16 @@ -# Nitro starter +The simplest Nitro server. Export an object with a `fetch` method that receives a standard `Request` and returns a `Response`. No frameworks, no abstractions, just the web platform. -Look at the [nitro quick start](https://nitro.build/guide#quick-start) to learn more how to get started. + +## Server Entry + +```ts [server.ts] +export default { + fetch(req: Request) { + return new Response("Nitro Works!"); + }, +}; +``` + +The `fetch` method follows the same signature as Service Workers and Cloudflare Workers. This pattern works across all deployment targets because it uses web standards. + +Add the Nitro plugin to Vite and it handles the rest: dev server, hot reloading, and production builds. diff --git a/examples/hello-world/nitro.config.ts b/examples/hello-world/nitro.config.ts index 4d78169e2f..50c7c4fd97 100644 --- a/examples/hello-world/nitro.config.ts +++ b/examples/hello-world/nitro.config.ts @@ -1,5 +1,3 @@ -// https://nitro.build/config -export default defineNitroConfig({ - compatibilityDate: "2025-03-01", - srcDir: "server", -}); +import { defineConfig } from "nitro"; + +export default defineConfig({}); diff --git a/examples/hello-world/package.json b/examples/hello-world/package.json index 0ef33628a5..d2273241a1 100644 --- a/examples/hello-world/package.json +++ b/examples/hello-world/package.json @@ -6,6 +6,6 @@ "preview": "node .output/server/index.mjs" }, "devDependencies": { - "nitropack": "latest" + "nitro": "latest" } } diff --git a/examples/hello-world/server.ts b/examples/hello-world/server.ts new file mode 100644 index 0000000000..fa7f5ddcd5 --- /dev/null +++ b/examples/hello-world/server.ts @@ -0,0 +1,5 @@ +export default { + fetch(req: Request) { + return new Response("Nitro Works!"); + }, +}; diff --git a/examples/hello-world/server/routes/index.ts b/examples/hello-world/server/routes/index.ts deleted file mode 100644 index 40d8050765..0000000000 --- a/examples/hello-world/server/routes/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default eventHandler((event) => { - return "Start by editing server/routes/index.ts."; -}); diff --git a/examples/hello-world/tsconfig.json b/examples/hello-world/tsconfig.json index e2cabfcb8c..4b886bd47e 100644 --- a/examples/hello-world/tsconfig.json +++ b/examples/hello-world/tsconfig.json @@ -1,4 +1,3 @@ -// https://nitro.build/guide/typescript { - "extends": "./.nitro/types/tsconfig.json" + "extends": "nitro/tsconfig" } diff --git a/examples/hello-world/vite.config.ts b/examples/hello-world/vite.config.ts new file mode 100644 index 0000000000..34d3353e1c --- /dev/null +++ b/examples/hello-world/vite.config.ts @@ -0,0 +1,4 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); diff --git a/examples/hono/README.md b/examples/hono/README.md new file mode 100644 index 0000000000..6079b7840b --- /dev/null +++ b/examples/hono/README.md @@ -0,0 +1,17 @@ +## Server Entry + +```ts [server.ts] +import { Hono } from "hono"; + +const app = new Hono(); + +app.get("/", (c) => { + return c.text("Hello, Hono with Nitro!"); +}); + +export default app; +``` + +Nitro auto-detects `server.ts` in your project root and uses it as the server entry. The Hono app handles all incoming requests, giving you full control over routing and middleware. + +Hono is cross-runtime compatible, so this server entry works across all Nitro deployment targets including Node.js, Deno, Bun, and Cloudflare Workers. diff --git a/examples/hono/nitro.config.ts b/examples/hono/nitro.config.ts new file mode 100644 index 0000000000..50c7c4fd97 --- /dev/null +++ b/examples/hono/nitro.config.ts @@ -0,0 +1,3 @@ +import { defineConfig } from "nitro"; + +export default defineConfig({}); diff --git a/examples/hono/package.json b/examples/hono/package.json new file mode 100644 index 0000000000..31f4d4bbad --- /dev/null +++ b/examples/hono/package.json @@ -0,0 +1,11 @@ +{ + "type": "module", + "scripts": { + "build": "nitro build", + "dev": "nitro dev" + }, + "devDependencies": { + "hono": "^4.11.8", + "nitro": "latest" + } +} diff --git a/examples/hono/server.ts b/examples/hono/server.ts new file mode 100644 index 0000000000..9b28e4fdcf --- /dev/null +++ b/examples/hono/server.ts @@ -0,0 +1,9 @@ +import { Hono } from "hono"; + +const app = new Hono(); + +app.get("/", (c) => { + return c.text("Hello, Hono with Nitro!"); +}); + +export default app; diff --git a/examples/hono/tsconfig.json b/examples/hono/tsconfig.json new file mode 100644 index 0000000000..4b886bd47e --- /dev/null +++ b/examples/hono/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "nitro/tsconfig" +} diff --git a/examples/hono/vite.config.ts b/examples/hono/vite.config.ts new file mode 100644 index 0000000000..34d3353e1c --- /dev/null +++ b/examples/hono/vite.config.ts @@ -0,0 +1,4 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); diff --git a/examples/import-alias/README.md b/examples/import-alias/README.md new file mode 100644 index 0000000000..22274bc8c6 --- /dev/null +++ b/examples/import-alias/README.md @@ -0,0 +1,21 @@ +Import aliases like `~` and `#` let you reference modules with shorter paths instead of relative imports. + +## Importing Using Aliases + +```ts [server/routes/index.ts] +import { sum } from "~server/utils/math.ts"; + +import { rand } from "#server/utils/math.ts"; + +export default () => { + const [a, b] = [rand(1, 10), rand(1, 10)]; + const result = sum(a, b); + return `The sum of ${a} + ${b} = ${result}`; +}; +``` + +The route imports the `sum` function using `~server/` and `rand` using `#server/`. Both resolve to the same `server/utils/math.ts` file. The handler generates two random numbers and returns their sum. + +## Configuration + +Aliases can be configured in `package.json` imports field or `nitro.config.ts`. diff --git a/examples/import-alias/nitro.config.ts b/examples/import-alias/nitro.config.ts new file mode 100644 index 0000000000..dd8eb07b69 --- /dev/null +++ b/examples/import-alias/nitro.config.ts @@ -0,0 +1,5 @@ +import { defineConfig } from "nitro"; + +export default defineConfig({ + serverDir: true, +}); diff --git a/examples/import-alias/package.json b/examples/import-alias/package.json new file mode 100644 index 0000000000..99d1333619 --- /dev/null +++ b/examples/import-alias/package.json @@ -0,0 +1,14 @@ +{ + "type": "module", + "imports": { + "#server/*": "./server/*" + }, + "scripts": { + "build": "nitro build", + "dev": "nitro dev", + "preview": "node .output/server/index.mjs" + }, + "devDependencies": { + "nitro": "latest" + } +} diff --git a/examples/import-alias/server/routes/index.ts b/examples/import-alias/server/routes/index.ts new file mode 100644 index 0000000000..23b0f251c5 --- /dev/null +++ b/examples/import-alias/server/routes/index.ts @@ -0,0 +1,9 @@ +import { sum } from "~server/utils/math.ts"; + +import { rand } from "#server/utils/math.ts"; + +export default () => { + const [a, b] = [rand(1, 10), rand(1, 10)]; + const result = sum(a, b); + return `The sum of ${a} + ${b} = ${result}`; +}; diff --git a/examples/import-alias/server/utils/math.ts b/examples/import-alias/server/utils/math.ts new file mode 100644 index 0000000000..d67487178f --- /dev/null +++ b/examples/import-alias/server/utils/math.ts @@ -0,0 +1,7 @@ +export function rand(min: number, max: number): number { + return Math.floor(Math.random() * (max - min + 1)) + min; +} + +export function sum(a: number, b: number): number { + return a + b; +} diff --git a/examples/import-alias/tsconfig.json b/examples/import-alias/tsconfig.json new file mode 100644 index 0000000000..daf0446750 --- /dev/null +++ b/examples/import-alias/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "nitro/tsconfig", + "compilerOptions": { + "paths": { + "~server/*": ["./server/*"] + } + } +} diff --git a/examples/import-alias/vite.config.ts b/examples/import-alias/vite.config.ts new file mode 100644 index 0000000000..4b49960179 --- /dev/null +++ b/examples/import-alias/vite.config.ts @@ -0,0 +1,4 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()], resolve: { tsconfigPaths: true } }); diff --git a/examples/middleware/README.md b/examples/middleware/README.md new file mode 100644 index 0000000000..eab473e051 --- /dev/null +++ b/examples/middleware/README.md @@ -0,0 +1,30 @@ +Middleware functions run before route handlers on every request. They can modify the request, add context, or return early responses. + +## Defining Middleware + +Create files in `server/middleware/`. They run in alphabetical order: + +```ts [server/middleware/auth.ts] +import { defineMiddleware } from "nitro"; + +export default defineMiddleware((event) => { + event.context.auth = { name: "User " + Math.round(Math.random() * 100) }; +}); +``` + +Middleware can: +- Add data to `event.context` for use in handlers +- Return a response early to short-circuit the request +- Modify request headers or other properties + +## Accessing Context in Handlers + +Data added to `event.context` in middleware is available in all subsequent handlers: + +```ts [server.ts] +import { defineHandler } from "nitro"; + +export default defineHandler((event) => ({ + auth: event.context.auth, +})); +``` diff --git a/examples/middleware/middleware/auth.ts b/examples/middleware/middleware/auth.ts deleted file mode 100644 index 00f610ce10..0000000000 --- a/examples/middleware/middleware/auth.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default defineEventHandler((event) => { - event.context.auth = { name: "User " + Math.round(Math.random() * 100) }; -}); diff --git a/examples/middleware/nitro.config.ts b/examples/middleware/nitro.config.ts index e83a8daf81..dd8eb07b69 100644 --- a/examples/middleware/nitro.config.ts +++ b/examples/middleware/nitro.config.ts @@ -1,3 +1,5 @@ -export default defineNitroConfig({ - compatibilityDate: "2025-03-01", +import { defineConfig } from "nitro"; + +export default defineConfig({ + serverDir: true, }); diff --git a/examples/middleware/package.json b/examples/middleware/package.json index 41e367d2e7..736abd40ad 100644 --- a/examples/middleware/package.json +++ b/examples/middleware/package.json @@ -1,11 +1,10 @@ { - "name": "example-middleware", - "private": true, + "type": "module", "scripts": { "dev": "nitro dev", "build": "nitro build" }, "devDependencies": { - "nitropack": "latest" + "nitro": "latest" } } diff --git a/examples/middleware/routes/index.ts b/examples/middleware/routes/index.ts deleted file mode 100644 index e7961fa36d..0000000000 --- a/examples/middleware/routes/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default defineEventHandler((event) => ({ - auth: event.context.auth, -})); diff --git a/examples/middleware/server.ts b/examples/middleware/server.ts new file mode 100644 index 0000000000..7d74232914 --- /dev/null +++ b/examples/middleware/server.ts @@ -0,0 +1,5 @@ +import { defineHandler } from "nitro"; + +export default defineHandler((event) => ({ + auth: event.context.auth, +})); diff --git a/examples/middleware/server/middleware/auth.ts b/examples/middleware/server/middleware/auth.ts new file mode 100644 index 0000000000..f87768a931 --- /dev/null +++ b/examples/middleware/server/middleware/auth.ts @@ -0,0 +1,5 @@ +import { defineMiddleware } from "nitro"; + +export default defineMiddleware((event) => { + event.context.auth = { name: "User " + Math.round(Math.random() * 100) }; +}); diff --git a/examples/middleware/tsconfig.json b/examples/middleware/tsconfig.json index 43008af1c7..4b886bd47e 100644 --- a/examples/middleware/tsconfig.json +++ b/examples/middleware/tsconfig.json @@ -1,3 +1,3 @@ { - "extends": "./.nitro/types/tsconfig.json" + "extends": "nitro/tsconfig" } diff --git a/examples/middleware/vite.config.ts b/examples/middleware/vite.config.ts new file mode 100644 index 0000000000..34d3353e1c --- /dev/null +++ b/examples/middleware/vite.config.ts @@ -0,0 +1,4 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); diff --git a/examples/mono-jsx/README.md b/examples/mono-jsx/README.md new file mode 100644 index 0000000000..63e42b69bb --- /dev/null +++ b/examples/mono-jsx/README.md @@ -0,0 +1,11 @@ +## Server Entry + +```tsx [server.tsx] +export default () => ( + +

Nitro + mono-jsx works!

+ +); +``` + +Nitro auto-detects `server.tsx` and uses mono-jsx to transform JSX into HTML. Export a function that returns JSX, and Nitro sends the rendered HTML as the response. diff --git a/examples/mono-jsx/nitro.config.ts b/examples/mono-jsx/nitro.config.ts new file mode 100644 index 0000000000..50c7c4fd97 --- /dev/null +++ b/examples/mono-jsx/nitro.config.ts @@ -0,0 +1,3 @@ +import { defineConfig } from "nitro"; + +export default defineConfig({}); diff --git a/examples/graceful-shutdown/package.json b/examples/mono-jsx/package.json similarity index 54% rename from examples/graceful-shutdown/package.json rename to examples/mono-jsx/package.json index 8d67c4f8e0..d64d0c6ee4 100644 --- a/examples/graceful-shutdown/package.json +++ b/examples/mono-jsx/package.json @@ -1,11 +1,11 @@ { - "name": "example-graceful-shutdown", - "private": true, + "type": "module", "scripts": { "dev": "nitro dev", "build": "nitro build" }, "devDependencies": { - "nitropack": "latest" + "mono-jsx": "latest", + "nitro": "latest" } } diff --git a/examples/mono-jsx/server.tsx b/examples/mono-jsx/server.tsx new file mode 100644 index 0000000000..e0bc3dc3ab --- /dev/null +++ b/examples/mono-jsx/server.tsx @@ -0,0 +1,5 @@ +export default () => ( + +

Nitro + mono-jsx works!

+ +); diff --git a/examples/mono-jsx/tsconfig.json b/examples/mono-jsx/tsconfig.json new file mode 100644 index 0000000000..211d2c8473 --- /dev/null +++ b/examples/mono-jsx/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "nitro/tsconfig", + "compilerOptions": { + "jsx": "react-jsx", + "jsxImportSource": "mono-jsx" + } +} diff --git a/examples/mono-jsx/vite.config.ts b/examples/mono-jsx/vite.config.ts new file mode 100644 index 0000000000..34d3353e1c --- /dev/null +++ b/examples/mono-jsx/vite.config.ts @@ -0,0 +1,4 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); diff --git a/examples/nano-jsx/README.md b/examples/nano-jsx/README.md new file mode 100644 index 0000000000..a1f7156952 --- /dev/null +++ b/examples/nano-jsx/README.md @@ -0,0 +1,12 @@ +## Server Entry + +```tsx [server.tsx] +import { defineHandler, html } from "nitro"; +import { renderSSR } from "nano-jsx"; + +export default defineHandler(() => { + return html(renderSSR(() =>

Nitro + nano-jsx works!

)); +}); +``` + +Nitro auto-detects `server.tsx` and uses it as the server entry. Use `renderSSR` from nano-jsx to convert JSX into an HTML string. The `html` helper from H3 sets the correct content type header. diff --git a/examples/nano-jsx/nitro.config.ts b/examples/nano-jsx/nitro.config.ts index e83a8daf81..50c7c4fd97 100644 --- a/examples/nano-jsx/nitro.config.ts +++ b/examples/nano-jsx/nitro.config.ts @@ -1,3 +1,3 @@ -export default defineNitroConfig({ - compatibilityDate: "2025-03-01", -}); +import { defineConfig } from "nitro"; + +export default defineConfig({}); diff --git a/examples/nano-jsx/package.json b/examples/nano-jsx/package.json index ac4a499e70..6f81041613 100644 --- a/examples/nano-jsx/package.json +++ b/examples/nano-jsx/package.json @@ -1,12 +1,11 @@ { - "name": "example-nano-jsx", - "private": true, + "type": "module", "scripts": { "dev": "nitro dev", "build": "nitro build" }, "devDependencies": { - "nano-jsx": "^0.0.37", - "nitropack": "latest" + "nano-jsx": "^0.2.1", + "nitro": "latest" } } diff --git a/examples/nano-jsx/routes/[...path].tsx b/examples/nano-jsx/routes/[...path].tsx deleted file mode 100644 index 3f4915580f..0000000000 --- a/examples/nano-jsx/routes/[...path].tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { defineEventHandler } from "h3"; -import { h, renderSSR } from "nano-jsx"; - -export default defineEventHandler(() => { - const html = renderSSR(() =>

Nitro + nano-jsx works!

); - return html; -}); diff --git a/examples/nano-jsx/server.tsx b/examples/nano-jsx/server.tsx new file mode 100644 index 0000000000..98c6842e1f --- /dev/null +++ b/examples/nano-jsx/server.tsx @@ -0,0 +1,6 @@ +import { defineHandler, html } from "nitro"; +import { renderSSR } from "nano-jsx"; + +export default defineHandler(() => { + return html(renderSSR(() =>

Nitro + nano-jsx works!

)); +}); diff --git a/examples/nano-jsx/tsconfig.json b/examples/nano-jsx/tsconfig.json new file mode 100644 index 0000000000..f2d6fa6b30 --- /dev/null +++ b/examples/nano-jsx/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "nitro/tsconfig", + "compilerOptions": { + "jsx": "react-jsx", + "jsxImportSource": "nano-jsx/esm" + } +} diff --git a/examples/nano-jsx/vite.config.ts b/examples/nano-jsx/vite.config.ts new file mode 100644 index 0000000000..34d3353e1c --- /dev/null +++ b/examples/nano-jsx/vite.config.ts @@ -0,0 +1,4 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); diff --git a/examples/plugins/README.md b/examples/plugins/README.md new file mode 100644 index 0000000000..51420d853c --- /dev/null +++ b/examples/plugins/README.md @@ -0,0 +1,27 @@ +Plugins let you hook into Nitro's runtime lifecycle. This example shows a plugin that modifies the `Content-Type` header on every response. Create files in `server/plugins/` and they're automatically loaded at startup. + +## Defining a Plugin + +```ts [server/plugins/test.ts] +import { definePlugin } from "nitro"; +import { useNitroHooks } from "nitro/app"; + +export default definePlugin((nitroApp) => { + const hooks = useNitroHooks(); + hooks.hook("response", (event) => { + event.headers.set("content-type", "html; charset=utf-8"); + }); +}); +``` + +The plugin uses `useNitroHooks()` to access the hooks system, then registers a `response` hook that runs after every request. Here it sets the content type to HTML, but you could log requests, add security headers, or modify responses in any way. + +## Main Handler + +```ts [server.ts] +import { eventHandler } from "h3"; + +export default eventHandler(() => "

Hello Nitro!

"); +``` + +The handler returns HTML without setting a content type. The plugin automatically adds the correct `Content-Type: html; charset=utf-8` header to the response. diff --git a/examples/plugins/nitro.config.ts b/examples/plugins/nitro.config.ts index f038a12cd2..dd8eb07b69 100644 --- a/examples/plugins/nitro.config.ts +++ b/examples/plugins/nitro.config.ts @@ -1,4 +1,5 @@ -export default defineNitroConfig({ - compatibilityDate: "2025-03-01", - plugins: ["~/plugins/test"], +import { defineConfig } from "nitro"; + +export default defineConfig({ + serverDir: true, }); diff --git a/examples/plugins/package.json b/examples/plugins/package.json index 28a06f9422..736abd40ad 100644 --- a/examples/plugins/package.json +++ b/examples/plugins/package.json @@ -1,11 +1,10 @@ { - "name": "example-plugins", - "private": true, + "type": "module", "scripts": { "dev": "nitro dev", "build": "nitro build" }, "devDependencies": { - "nitropack": "latest" + "nitro": "latest" } } diff --git a/examples/plugins/plugins/test.ts b/examples/plugins/plugins/test.ts deleted file mode 100644 index d6f5a24e88..0000000000 --- a/examples/plugins/plugins/test.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default defineNitroPlugin((_nitroApp) => { - console.log("Nitro plugin!"); -}); diff --git a/examples/plugins/routes/index.ts b/examples/plugins/server.ts similarity index 100% rename from examples/plugins/routes/index.ts rename to examples/plugins/server.ts diff --git a/examples/plugins/server/plugins/test.ts b/examples/plugins/server/plugins/test.ts new file mode 100644 index 0000000000..a559b4897f --- /dev/null +++ b/examples/plugins/server/plugins/test.ts @@ -0,0 +1,9 @@ +import { definePlugin } from "nitro"; +import { useNitroHooks } from "nitro/app"; + +export default definePlugin((nitroApp) => { + const hooks = useNitroHooks(); + hooks.hook("response", (event) => { + event.headers.set("content-type", "html; charset=utf-8"); + }); +}); diff --git a/examples/plugins/tsconfig.json b/examples/plugins/tsconfig.json index 43008af1c7..4b886bd47e 100644 --- a/examples/plugins/tsconfig.json +++ b/examples/plugins/tsconfig.json @@ -1,3 +1,3 @@ { - "extends": "./.nitro/types/tsconfig.json" + "extends": "nitro/tsconfig" } diff --git a/examples/plugins/vite.config.ts b/examples/plugins/vite.config.ts new file mode 100644 index 0000000000..34d3353e1c --- /dev/null +++ b/examples/plugins/vite.config.ts @@ -0,0 +1,4 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); diff --git a/examples/renderer/README.md b/examples/renderer/README.md new file mode 100644 index 0000000000..68d5ba38ca --- /dev/null +++ b/examples/renderer/README.md @@ -0,0 +1,39 @@ +Create a custom renderer that generates HTML responses with data from API routes. Use Nitro's internal `fetch` to call routes without network overhead. + +## Renderer + +```ts [renderer.ts] +import { fetch } from "nitro"; + +export default async function renderer({ url }: { req: Request; url: URL }) { + const apiRes = await fetch("/api/hello").then((res) => res.text()); + return new Response( + /* html */ ` + + + Custom Renderer + + +

Hello from custom renderer!

+

Current path: ${url.pathname}

+

API says: ${apiRes}

+ + `, + { headers: { "content-type": "text/html; charset=utf-8" } } + ); +} +``` + +Nitro auto-detects `renderer.ts` in your project root and uses it for all non-API routes. The renderer function receives the request URL and returns a `Response`. + +Use `fetch` from `nitro` to call API routes without network overhead—these requests stay in-process. + +## API Route + +```ts [api/hello.ts] +import { defineHandler } from "nitro"; + +export default defineHandler(() => "Nitro is amazing!"); +``` + +Define API routes in the `api/` directory. When the renderer calls `fetch("/api/hello")`, this handler runs and returns its response. diff --git a/examples/renderer/api/hello.ts b/examples/renderer/api/hello.ts index 21fe2776d8..a14364644e 100644 --- a/examples/renderer/api/hello.ts +++ b/examples/renderer/api/hello.ts @@ -1 +1,3 @@ -export default defineEventHandler(() => "Nitro is amazing!"); +import { defineHandler } from "nitro"; + +export default defineHandler(() => "Nitro is amazing!"); diff --git a/examples/renderer/nitro.config.ts b/examples/renderer/nitro.config.ts index 3d9ba98119..3166c9b00c 100644 --- a/examples/renderer/nitro.config.ts +++ b/examples/renderer/nitro.config.ts @@ -1,4 +1,6 @@ -export default defineNitroConfig({ - compatibilityDate: "2025-03-01", - renderer: "~/renderer", +import { defineConfig } from "nitro"; + +export default defineConfig({ + serverDir: "./", + renderer: { handler: "./renderer" }, }); diff --git a/examples/renderer/package.json b/examples/renderer/package.json index 8176d51679..736abd40ad 100644 --- a/examples/renderer/package.json +++ b/examples/renderer/package.json @@ -1,11 +1,10 @@ { - "name": "example-renderer", - "private": true, + "type": "module", "scripts": { "dev": "nitro dev", "build": "nitro build" }, "devDependencies": { - "nitropack": "latest" + "nitro": "latest" } } diff --git a/examples/renderer/renderer.ts b/examples/renderer/renderer.ts index f942d29cab..4cdb0806b6 100644 --- a/examples/renderer/renderer.ts +++ b/examples/renderer/renderer.ts @@ -1,15 +1,19 @@ -import { defineRenderHandler } from "nitropack/runtime"; +import { fetch } from "nitro"; -export default defineRenderHandler((_event) => { - return { - body: /* html */ ` +export default async function renderer({ url }: { req: Request; url: URL }) { + const apiRes = await fetch("/api/hello").then((res) => res.text()); + return new Response( + /* html */ ` - - Rendered Page - - -

Rendered by Nitro!

- + + Custom Renderer + + +

Hello from custom renderer!

+

Current path: ${url.pathname}

+

API says: ${apiRes}

+ `, - }; -}); + { headers: { "content-type": "text/html; charset=utf-8" } } + ); +} diff --git a/examples/renderer/tsconfig.json b/examples/renderer/tsconfig.json index 43008af1c7..4b886bd47e 100644 --- a/examples/renderer/tsconfig.json +++ b/examples/renderer/tsconfig.json @@ -1,3 +1,3 @@ { - "extends": "./.nitro/types/tsconfig.json" + "extends": "nitro/tsconfig" } diff --git a/examples/renderer/vite.config.ts b/examples/renderer/vite.config.ts new file mode 100644 index 0000000000..34d3353e1c --- /dev/null +++ b/examples/renderer/vite.config.ts @@ -0,0 +1,4 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); diff --git a/examples/runtime-config/.env b/examples/runtime-config/.env new file mode 100644 index 0000000000..795c741d2e --- /dev/null +++ b/examples/runtime-config/.env @@ -0,0 +1,2 @@ +# NEVER COMMIT SENSITIVE DATA. THIS IS ONLY FOR DEMO PURPOSES. +NITRO_API_KEY=secret-api-key diff --git a/examples/runtime-config/.gitignore b/examples/runtime-config/.gitignore new file mode 100644 index 0000000000..847fcd3abb --- /dev/null +++ b/examples/runtime-config/.gitignore @@ -0,0 +1,2 @@ +# THIS IS ONLY FOR DEMO. DO NOT COMMIT SENSITIVE DATA IN REAL PROJECTS +!.env diff --git a/examples/runtime-config/README.md b/examples/runtime-config/README.md new file mode 100644 index 0000000000..145f18f640 --- /dev/null +++ b/examples/runtime-config/README.md @@ -0,0 +1,39 @@ +Runtime config lets you define configuration values that can be overridden by environment variables at runtime. + +## Define Config Schema + +Declare your runtime config with default values in `nitro.config.ts`: + +```ts [nitro.config.ts] +import { defineConfig } from "nitro"; + +export default defineConfig({ + serverDir: "./", + runtimeConfig: { + apiKey: "", + }, +}); +``` + +## Access at Runtime + +Use `useRuntimeConfig` to access configuration values in your handlers: + +```ts [server.ts] +import { defineHandler } from "nitro"; +import { useRuntimeConfig } from "nitro/runtime-config"; + +export default defineHandler((event) => { + const runtimeConfig = useRuntimeConfig(); + return { runtimeConfig }; +}); +``` + +## Environment Variables + +Override config values via environment variables prefixed with `NITRO_`: + +```sh [.env] +# NEVER COMMIT SENSITIVE DATA. THIS IS ONLY FOR DEMO PURPOSES. +NITRO_API_KEY=secret-api-key +``` diff --git a/examples/runtime-config/nitro.config.ts b/examples/runtime-config/nitro.config.ts new file mode 100644 index 0000000000..b6752db0d6 --- /dev/null +++ b/examples/runtime-config/nitro.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from "nitro"; + +export default defineConfig({ + serverDir: "./", + runtimeConfig: { + apiKey: "", + }, +}); diff --git a/examples/runtime-config/package.json b/examples/runtime-config/package.json new file mode 100644 index 0000000000..736abd40ad --- /dev/null +++ b/examples/runtime-config/package.json @@ -0,0 +1,10 @@ +{ + "type": "module", + "scripts": { + "dev": "nitro dev", + "build": "nitro build" + }, + "devDependencies": { + "nitro": "latest" + } +} diff --git a/examples/runtime-config/server.ts b/examples/runtime-config/server.ts new file mode 100644 index 0000000000..4d58eb4af7 --- /dev/null +++ b/examples/runtime-config/server.ts @@ -0,0 +1,7 @@ +import { defineHandler } from "nitro"; +import { useRuntimeConfig } from "nitro/runtime-config"; + +export default defineHandler((event) => { + const runtimeConfig = useRuntimeConfig(); + return { runtimeConfig }; +}); diff --git a/examples/runtime-config/tsconfig.json b/examples/runtime-config/tsconfig.json new file mode 100644 index 0000000000..4b886bd47e --- /dev/null +++ b/examples/runtime-config/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "nitro/tsconfig" +} diff --git a/examples/runtime-config/vite.config.ts b/examples/runtime-config/vite.config.ts new file mode 100644 index 0000000000..34d3353e1c --- /dev/null +++ b/examples/runtime-config/vite.config.ts @@ -0,0 +1,4 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); diff --git a/examples/server-fetch/README.md b/examples/server-fetch/README.md new file mode 100644 index 0000000000..1970cdb18e --- /dev/null +++ b/examples/server-fetch/README.md @@ -0,0 +1,22 @@ +When you need one route to call another, use Nitro's `fetch` function instead of the global fetch. It makes internal requests that stay in-process, avoiding network round-trips. The request never leaves the server. + +## Main Route + +```ts [routes/index.ts] +import { defineHandler } from "nitro"; +import { fetch } from "nitro"; + +export default defineHandler(() => fetch("/hello")); +``` + +The index route imports `fetch` from `nitro` (not the global fetch) and calls the `/hello` route. This request is handled internally without going through the network stack. + +## Internal API Route + +```ts [routes/hello.ts] +import { defineHandler } from "nitro"; + +export default defineHandler(() => "Hello!"); +``` + +A simple route that returns "Hello!". When the index route calls `fetch("/hello")`, this handler runs and its response is returned directly. diff --git a/examples/server-fetch/nitro.config.ts b/examples/server-fetch/nitro.config.ts new file mode 100644 index 0000000000..b586233fa4 --- /dev/null +++ b/examples/server-fetch/nitro.config.ts @@ -0,0 +1,12 @@ +import { defineConfig, serverFetch } from "nitro"; + +export default defineConfig({ + serverDir: "./", + hooks: { + "dev:start": async () => { + const res = await serverFetch("/hello"); + const text = await res.text(); + console.log("Fetched /hello in nitro module:", res.status, text); + }, + }, +}); diff --git a/examples/server-fetch/package.json b/examples/server-fetch/package.json new file mode 100644 index 0000000000..736abd40ad --- /dev/null +++ b/examples/server-fetch/package.json @@ -0,0 +1,10 @@ +{ + "type": "module", + "scripts": { + "dev": "nitro dev", + "build": "nitro build" + }, + "devDependencies": { + "nitro": "latest" + } +} diff --git a/examples/server-fetch/routes/hello.ts b/examples/server-fetch/routes/hello.ts new file mode 100644 index 0000000000..4ccc9dbd0d --- /dev/null +++ b/examples/server-fetch/routes/hello.ts @@ -0,0 +1,3 @@ +import { defineHandler } from "nitro"; + +export default defineHandler(() => "Hello!"); diff --git a/examples/server-fetch/routes/index.ts b/examples/server-fetch/routes/index.ts new file mode 100644 index 0000000000..ce37a1bf15 --- /dev/null +++ b/examples/server-fetch/routes/index.ts @@ -0,0 +1,4 @@ +import { defineHandler } from "nitro"; +import { fetch } from "nitro"; + +export default defineHandler(() => fetch("/hello")); diff --git a/examples/server-fetch/tsconfig.json b/examples/server-fetch/tsconfig.json new file mode 100644 index 0000000000..4b886bd47e --- /dev/null +++ b/examples/server-fetch/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "nitro/tsconfig" +} diff --git a/examples/server-fetch/vite.config.ts b/examples/server-fetch/vite.config.ts new file mode 100644 index 0000000000..34d3353e1c --- /dev/null +++ b/examples/server-fetch/vite.config.ts @@ -0,0 +1,4 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); diff --git a/examples/shiki/README.md b/examples/shiki/README.md new file mode 100644 index 0000000000..a47d8f1561 --- /dev/null +++ b/examples/shiki/README.md @@ -0,0 +1,56 @@ +Use Shiki for syntax highlighting with TextMate grammars. This example highlights code on the server using Nitro's server scripts feature, which runs JavaScript inside HTML files before sending the response. + +## API Route + +```ts [api/highlight.ts] +import { createHighlighterCore } from "shiki/core"; +import { createOnigurumaEngine } from "shiki/engine/oniguruma"; + +const highlighter = await createHighlighterCore({ + engine: createOnigurumaEngine(import("shiki/wasm")), + themes: [await import("shiki/themes/vitesse-dark.mjs")], + langs: [await import("shiki/langs/ts.mjs")], +}); + +export default async ({ req }: { req: Request }) => { + const code = await req.text(); + const html = await highlighter.codeToHtml(code, { + lang: "ts", + theme: "vitesse-dark", + }); + return new Response(html, { + headers: { "Content-Type": "text/html; charset=utf-8" }, + }); +}; +``` + +Create a Shiki highlighter with the Vitesse Dark theme and TypeScript language support. When the API receives a POST request, it reads the code from the request body and returns highlighted HTML. + +## Server-Side Rendering + +```html [index.html] + + + + + + Hello World Snippet + + + +
+
JavaScript
+ +
{{{ hl(`console.log("💚 Simple is beautiful!");`) }}}
+
+ + +``` + +The ` +
{{{ hl(`console.log("💚 Simple is beautiful!");`) }}}
+ + + diff --git a/examples/shiki/nitro.config.ts b/examples/shiki/nitro.config.ts new file mode 100644 index 0000000000..e87bfb1938 --- /dev/null +++ b/examples/shiki/nitro.config.ts @@ -0,0 +1,5 @@ +import { defineConfig } from "nitro"; + +export default defineConfig({ + serverDir: "./", +}); diff --git a/examples/shiki/package.json b/examples/shiki/package.json new file mode 100644 index 0000000000..d5de72dde2 --- /dev/null +++ b/examples/shiki/package.json @@ -0,0 +1,11 @@ +{ + "type": "module", + "scripts": { + "dev": "vite dev", + "build": "vite build" + }, + "devDependencies": { + "nitro": "latest", + "shiki": "^3.22.0" + } +} diff --git a/examples/shiki/styles.css b/examples/shiki/styles.css new file mode 100644 index 0000000000..ccd2277fef --- /dev/null +++ b/examples/shiki/styles.css @@ -0,0 +1,44 @@ +html, +body { + height: 100%; + margin: 0; +} +body { + display: flex; + align-items: center; + justify-content: center; + background: #f6f8fa; + font-family: + system-ui, + -apple-system, + "Segoe UI", + Roboto, + "Helvetica Neue", + Arial, + "Noto Sans", + "Liberation Sans", + sans-serif; +} +.card { + text-align: left; + background: #0b1220; + color: #e6edf3; + padding: 1rem; + border-radius: 8px; + box-shadow: 0 8px 24px rgba(2, 6, 23, 0.2); + max-width: 90%; + width: 520px; +} +.label { + font-size: 12px; + color: #9aa7b2; + margin-bottom: 8px; +} +pre { + margin: 0; + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, "Courier New", monospace; + font-size: 14px; + background: transparent; + white-space: pre; + overflow: auto; +} diff --git a/examples/shiki/tsconfig.json b/examples/shiki/tsconfig.json new file mode 100644 index 0000000000..4b886bd47e --- /dev/null +++ b/examples/shiki/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "nitro/tsconfig" +} diff --git a/examples/shiki/vite.config.ts b/examples/shiki/vite.config.ts new file mode 100644 index 0000000000..dc884054e6 --- /dev/null +++ b/examples/shiki/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ + plugins: [nitro()], +}); diff --git a/examples/tsconfig.json b/examples/tsconfig.json deleted file mode 100644 index 379a994d81..0000000000 --- a/examples/tsconfig.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": "../tsconfig.json", - "include": ["."] -} diff --git a/examples/virtual-routes/README.md b/examples/virtual-routes/README.md new file mode 100644 index 0000000000..f2a190e7eb --- /dev/null +++ b/examples/virtual-routes/README.md @@ -0,0 +1,21 @@ +Virtual routes let you define handlers as strings in your config instead of creating separate files. This is useful when generating routes dynamically, building plugins, or keeping simple routes inline. + +## Configuration + +```ts [nitro.config.ts] +import { defineConfig } from "nitro"; + +export default defineConfig({ + routes: { + "/": "#virtual-route", + }, + virtual: { + "#virtual-route": () => + /* js */ `export default () => new Response("Hello from virtual entry!")`, + }, +}); +``` + +The `routes` option maps URL paths to virtual module identifiers (prefixed with `#`). The `virtual` option defines the module content as a string or function returning a string. At build time, Nitro resolves these virtual modules to actual handlers. + +There are no route files in this project. The entire handler is defined inline in the config, and Nitro generates the route at build time. diff --git a/examples/virtual-routes/nitro.config.ts b/examples/virtual-routes/nitro.config.ts new file mode 100644 index 0000000000..3a778666fb --- /dev/null +++ b/examples/virtual-routes/nitro.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from "nitro"; + +export default defineConfig({ + routes: { + "/": "#virtual-route", + }, + virtual: { + "#virtual-route": () => + /* js */ `export default () => new Response("Hello from virtual entry!")`, + }, +}); diff --git a/examples/virtual-routes/package.json b/examples/virtual-routes/package.json new file mode 100644 index 0000000000..d2273241a1 --- /dev/null +++ b/examples/virtual-routes/package.json @@ -0,0 +1,11 @@ +{ + "type": "module", + "scripts": { + "build": "nitro build", + "dev": "nitro dev", + "preview": "node .output/server/index.mjs" + }, + "devDependencies": { + "nitro": "latest" + } +} diff --git a/examples/virtual-routes/tsconfig.json b/examples/virtual-routes/tsconfig.json new file mode 100644 index 0000000000..4b886bd47e --- /dev/null +++ b/examples/virtual-routes/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "nitro/tsconfig" +} diff --git a/examples/virtual-routes/vite.config.ts b/examples/virtual-routes/vite.config.ts new file mode 100644 index 0000000000..34d3353e1c --- /dev/null +++ b/examples/virtual-routes/vite.config.ts @@ -0,0 +1,4 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); diff --git a/examples/vite-nitro-plugin/README.md b/examples/vite-nitro-plugin/README.md new file mode 100644 index 0000000000..cefd7d29e8 --- /dev/null +++ b/examples/vite-nitro-plugin/README.md @@ -0,0 +1,26 @@ +Instead of using a separate `nitro.config.ts`, you can configure Nitro directly in your Vite config. This gives you access to Nitro's setup hook where you can register routes and virtual modules programmatically. + +## Vite Configuration + +```js [vite.config.mjs] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ + plugins: [ + nitro(), + { + name: "my-nitro-plugin", + nitro: { + setup: (nitro) => { + nitro.options.routes["/"] = "#virtual-by-plugin"; + nitro.options.virtual["#virtual-by-plugin"] = + `export default () => new Response("Hello from virtual entry!")`; + }, + }, + }, + ], +}); +``` + +The config adds two plugins: the `nitro()` plugin and a custom plugin that uses the `nitro.setup` hook. Inside the setup function, you have access to Nitro's options object. This example registers a virtual route at `/` that maps to a virtual module `#virtual-by-plugin`, then defines that module inline. diff --git a/examples/vite-nitro-plugin/package.json b/examples/vite-nitro-plugin/package.json new file mode 100644 index 0000000000..2f6cf0a777 --- /dev/null +++ b/examples/vite-nitro-plugin/package.json @@ -0,0 +1,12 @@ +{ + "type": "module", + "scripts": { + "build": "vite build", + "preview": "vite preview", + "dev": "vite dev" + }, + "devDependencies": { + "nitro": "latest", + "vite": "beta" + } +} diff --git a/examples/vite-nitro-plugin/tsconfig.json b/examples/vite-nitro-plugin/tsconfig.json new file mode 100644 index 0000000000..4b886bd47e --- /dev/null +++ b/examples/vite-nitro-plugin/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "nitro/tsconfig" +} diff --git a/examples/vite-nitro-plugin/vite.config.mjs b/examples/vite-nitro-plugin/vite.config.mjs new file mode 100644 index 0000000000..ea1fd5a940 --- /dev/null +++ b/examples/vite-nitro-plugin/vite.config.mjs @@ -0,0 +1,18 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ + plugins: [ + nitro(), + { + name: "my-nitro-plugin", + nitro: { + setup: (nitro) => { + nitro.options.routes["/"] = "#virtual-by-plugin"; + nitro.options.virtual["#virtual-by-plugin"] = + `export default () => new Response("Hello from virtual entry!")`; + }, + }, + }, + ], +}); diff --git a/examples/vite-rsc/.gitignore b/examples/vite-rsc/.gitignore new file mode 100644 index 0000000000..f06235c460 --- /dev/null +++ b/examples/vite-rsc/.gitignore @@ -0,0 +1,2 @@ +node_modules +dist diff --git a/examples/vite-rsc/README.md b/examples/vite-rsc/README.md new file mode 100644 index 0000000000..fec04e5047 --- /dev/null +++ b/examples/vite-rsc/README.md @@ -0,0 +1,193 @@ +This example demonstrates React Server Components (RSC) using Vite's experimental RSC plugin with Nitro. It includes server components, client components, server actions, and streaming SSR. + +## Overview + +1. **SSR Entry** handles incoming requests and renders React components to HTML +2. **Root Component** defines the page structure as a server component +3. **Client Components** use the `"use client"` directive for interactive parts + +## 1. SSR Entry + +```tsx [app/framework/entry.ssr.tsx] +import { createFromReadableStream } from "@vitejs/plugin-rsc/ssr"; +import React from "react"; +import type { ReactFormState } from "react-dom/client"; +import { renderToReadableStream } from "react-dom/server.edge"; +import { injectRSCPayload } from "rsc-html-stream/server"; +import type { RscPayload } from "./entry.rsc"; + +export default { + fetch: async (request: Request) => { + const rscEntryModule = await import.meta.viteRsc.loadModule( + "rsc", + "index" + ); + return rscEntryModule.default(request); + }, +}; + +export async function renderHTML( + rscStream: ReadableStream, + options: { + formState?: ReactFormState; + nonce?: string; + debugNoJS?: boolean; + } +): Promise<{ stream: ReadableStream; status?: number }> { + // Duplicate one RSC stream into two. + // - one for SSR (ReactClient.createFromReadableStream below) + // - another for browser hydration payload by injecting . + const [rscStream1, rscStream2] = rscStream.tee(); + + // Deserialize RSC stream back to React VDOM + let payload: Promise | undefined; + function SsrRoot() { + // Deserialization needs to be kicked off inside ReactDOMServer context + // for ReactDOMServer preinit/preloading to work + payload ??= createFromReadableStream(rscStream1); + return React.use(payload).root; + } + + // Render HTML (traditional SSR) + const bootstrapScriptContent = await import.meta.viteRsc.loadBootstrapScriptContent("index"); + + let htmlStream: ReadableStream; + let status: number | undefined; + + try { + htmlStream = await renderToReadableStream(, { + bootstrapScriptContent: options?.debugNoJS ? undefined : bootstrapScriptContent, + nonce: options?.nonce, + formState: options?.formState, + }); + } catch { + // fallback to render an empty shell and run pure CSR on browser, + // which can replay server component error and trigger error boundary. + status = 500; + htmlStream = await renderToReadableStream( + + + + + , + { + bootstrapScriptContent: + `self.__NO_HYDRATE=1;` + (options?.debugNoJS ? "" : bootstrapScriptContent), + nonce: options?.nonce, + } + ); + } + + let responseStream: ReadableStream = htmlStream; + if (!options?.debugNoJS) { + // Initial RSC stream is injected in HTML stream as + // using utility made by devongovett https://github.com/devongovett/rsc-html-stream + responseStream = responseStream.pipeThrough( + injectRSCPayload(rscStream2, { + nonce: options?.nonce, + }) + ); + } + + return { stream: responseStream, status }; +} +``` + +The SSR entry handles the rendering pipeline. It loads the RSC entry module, duplicates the RSC stream (one for SSR, one for hydration), deserializes the stream back to React VDOM, and renders it to HTML. The RSC payload is injected into the HTML for client hydration. + +## 2. Root Server Component + +```tsx [app/root.tsx] +import "./index.css"; // css import is automatically injected in exported server components +import viteLogo from "./assets/vite.svg"; +import { getServerCounter, updateServerCounter } from "./action.tsx"; +import reactLogo from "./assets/react.svg"; +import nitroLogo from "./assets/nitro.svg"; +import { ClientCounter } from "./client.tsx"; + +export function Root(props: { url: URL }) { + return ( + + + {/* eslint-disable-next-line unicorn/text-encoding-identifier-case */} + + + + Nitro + Vite + RSC + + + + + + ); +} + +function App(props: { url: URL }) { + return ( +
+ +

Vite + RSC + Nitro

+
+ +
+
+
+ +
+
+
Request URL: {props.url?.href}
+
    +
  • + Edit src/client.tsx to test client HMR. +
  • +
  • + Edit src/root.tsx to test server HMR. +
  • +
  • + Visit{" "} + + _.rsc + {" "} + to view RSC stream payload. +
  • +
  • + Visit{" "} + + ?__nojs + {" "} + to test server action without js enabled. +
  • +
+
+ ); +} +``` + +Server components run only on the server. They can import CSS directly, use server-side data, and call server actions. The `ClientCounter` component is imported but runs on the client because it has the `"use client"` directive. + +## 3. Client Component + +```tsx [app/client.tsx] +"use client"; + +import React from "react"; + +export function ClientCounter() { + const [count, setCount] = React.useState(0); + + return ; +} +``` + +The `"use client"` directive marks this as a client component. It hydrates on the browser and handles interactive state. Server components can import and render client components, but client components cannot import server components. diff --git a/examples/vite-rsc/app/action.tsx b/examples/vite-rsc/app/action.tsx new file mode 100644 index 0000000000..6b5029dcb5 --- /dev/null +++ b/examples/vite-rsc/app/action.tsx @@ -0,0 +1,11 @@ +"use server"; + +let serverCounter = 0; + +export async function getServerCounter() { + return serverCounter; +} + +export async function updateServerCounter(change: number) { + serverCounter += change; +} diff --git a/examples/vite-rsc/app/assets/nitro.svg b/examples/vite-rsc/app/assets/nitro.svg new file mode 100644 index 0000000000..d6450f9467 --- /dev/null +++ b/examples/vite-rsc/app/assets/nitro.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/vite-rsc/app/assets/react.svg b/examples/vite-rsc/app/assets/react.svg new file mode 100644 index 0000000000..6c87de9bb3 --- /dev/null +++ b/examples/vite-rsc/app/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/vite-rsc/app/assets/vite.svg b/examples/vite-rsc/app/assets/vite.svg new file mode 100644 index 0000000000..e7b8dfb1b2 --- /dev/null +++ b/examples/vite-rsc/app/assets/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/vite-rsc/app/client.tsx b/examples/vite-rsc/app/client.tsx new file mode 100644 index 0000000000..ac69d863b5 --- /dev/null +++ b/examples/vite-rsc/app/client.tsx @@ -0,0 +1,9 @@ +"use client"; + +import React from "react"; + +export function ClientCounter() { + const [count, setCount] = React.useState(0); + + return ; +} diff --git a/examples/vite-rsc/app/framework/entry.browser.tsx b/examples/vite-rsc/app/framework/entry.browser.tsx new file mode 100644 index 0000000000..cce683560e --- /dev/null +++ b/examples/vite-rsc/app/framework/entry.browser.tsx @@ -0,0 +1,139 @@ +import { + createFromReadableStream, + createFromFetch, + setServerCallback, + createTemporaryReferenceSet, + encodeReply, +} from "@vitejs/plugin-rsc/browser"; +import React from "react"; +import { createRoot, hydrateRoot } from "react-dom/client"; +import { rscStream } from "rsc-html-stream/client"; +import { GlobalErrorBoundary } from "./error-boundary"; +import type { RscPayload } from "./entry.rsc"; +import { createRscRenderRequest } from "./request"; + +async function main() { + // Stash `setPayload` function to trigger re-rendering + // from outside of `BrowserRoot` component (e.g. server function call, navigation, hmr) + let setPayload: (v: RscPayload) => void; + + // Deserialize RSC stream back to React VDOM for CSR + const initialPayload = await createFromReadableStream( + // Initial RSC stream is injected in SSR stream as + rscStream + ); + + // Browser root component to (re-)render RSC payload as state + function BrowserRoot() { + const [payload, setPayload_] = React.useState(initialPayload); + + React.useEffect(() => { + setPayload = (v) => React.startTransition(() => setPayload_(v)); + }, [setPayload_]); + + // Re-fetch/render on client side navigation + React.useEffect(() => { + return listenNavigation(() => fetchRscPayload()); + }, []); + + return payload.root; + } + + // Re-fetch RSC and trigger re-rendering + async function fetchRscPayload() { + const renderRequest = createRscRenderRequest(globalThis.location.href); + const payload = await createFromFetch(fetch(renderRequest)); + setPayload(payload); + } + + // Register a handler which will be internally called by React + // on server function request after hydration. + setServerCallback(async (id, args) => { + const temporaryReferences = createTemporaryReferenceSet(); + const renderRequest = createRscRenderRequest(globalThis.location.href, { + id, + body: await encodeReply(args, { temporaryReferences }), + }); + const payload = await createFromFetch(fetch(renderRequest), { + temporaryReferences, + }); + setPayload(payload); + const { ok, data } = payload.returnValue!; + if (!ok) throw data; + return data; + }); + + // Hydration + const browserRoot = ( + + + + + + ); + if ("__NO_HYDRATE" in globalThis) { + createRoot(document).render(browserRoot); + } else { + hydrateRoot(document, browserRoot, { + formState: initialPayload.formState, + }); + } + + // Implement server HMR by triggering re-fetch/render of RSC upon server code change + if (import.meta.hot) { + import.meta.hot.on("rsc:update", () => { + fetchRscPayload(); + }); + } +} + +// A little helper to setup events interception for client side navigation +function listenNavigation(onNavigation: () => void) { + globalThis.addEventListener("popstate", onNavigation); + + const oldPushState = globalThis.history.pushState; + globalThis.history.pushState = function (...args) { + const res = oldPushState.apply(this, args); + onNavigation(); + return res; + }; + + const oldReplaceState = globalThis.history.replaceState; + globalThis.history.replaceState = function (...args) { + const res = oldReplaceState.apply(this, args); + onNavigation(); + return res; + }; + + function onClick(e: MouseEvent) { + const link = (e.target as Element).closest("a"); + if ( + link && + link instanceof HTMLAnchorElement && + link.href && + (!link.target || link.target === "_self") && + link.origin === location.origin && + !link.hasAttribute("download") && + e.button === 0 && // left clicks only + !e.metaKey && // open in new tab (mac) + !e.ctrlKey && // open in new tab (windows) + !e.altKey && // download + !e.shiftKey && + !e.defaultPrevented + ) { + e.preventDefault(); + history.pushState(null, "", link.href); + } + } + document.addEventListener("click", onClick); + + return () => { + document.removeEventListener("click", onClick); + globalThis.removeEventListener("popstate", onNavigation); + globalThis.history.pushState = oldPushState; + globalThis.history.replaceState = oldReplaceState; + }; +} + +// eslint-disable-next-line unicorn/prefer-top-level-await +main(); diff --git a/examples/vite-rsc/app/framework/entry.rsc.tsx b/examples/vite-rsc/app/framework/entry.rsc.tsx new file mode 100644 index 0000000000..9006ec40ae --- /dev/null +++ b/examples/vite-rsc/app/framework/entry.rsc.tsx @@ -0,0 +1,127 @@ +import { + renderToReadableStream, + createTemporaryReferenceSet, + decodeReply, + loadServerAction, + decodeAction, + decodeFormState, +} from "@vitejs/plugin-rsc/rsc"; +import type { ReactFormState } from "react-dom/client"; +import { Root } from "../root.tsx"; +import { parseRenderRequest } from "./request.tsx"; + +// The schema of payload which is serialized into RSC stream on rsc environment +// and deserialized on ssr/client environments. +export type RscPayload = { + // this demo renders/serializes/deserializes entire root html element + // but this mechanism can be changed to render/fetch different parts of components + // based on your own route conventions. + root: React.ReactNode; + + // Server action return value of non-progressive enhancement case + returnValue?: { ok: boolean; data: unknown }; + + // Server action form state (e.g. useActionState) of progressive enhancement case + formState?: ReactFormState; +}; + +// The plugin by default assumes `rsc` entry having default export of request handler. +// however, how server entries are executed can be customized by registering own server handler. +export default async function handler(request: Request): Promise { + // Differentiate RSC, SSR, action, etc. + const renderRequest = parseRenderRequest(request); + request = renderRequest.request; + + // Handle server function request + let returnValue: RscPayload["returnValue"] | undefined; + let formState: ReactFormState | undefined; + let temporaryReferences: unknown | undefined; + let actionStatus: number | undefined; + + if (renderRequest.isAction === true) { + if (renderRequest.actionId) { + // Action is called via `ReactClient.setServerCallback`. + const contentType = request.headers.get("content-type"); + const body = contentType?.startsWith("multipart/form-data") + ? await request.formData() + : await request.text(); + temporaryReferences = createTemporaryReferenceSet(); + const args = await decodeReply(body, { temporaryReferences }); + const action = await loadServerAction(renderRequest.actionId); + try { + // eslint-disable-next-line prefer-spread + const data = await action.apply(null, args); + returnValue = { ok: true, data }; + } catch (error_) { + returnValue = { ok: false, data: error_ }; + actionStatus = 500; + } + } else { + // Otherwise server function is called via `
` + // before hydration (e.g. when JavaScript is disabled). + // aka progressive enhancement. + const formData = await request.formData(); + const decodedAction = await decodeAction(formData); + try { + const result = await decodedAction(); + formState = await decodeFormState(result, formData); + } catch { + // there's no single general obvious way to surface this error, + // so explicitly return classic 500 response. + return new Response("Internal Server Error: server action failed", { + status: 500, + }); + } + } + } + + // Serialization from React VDOM tree to RSC stream. + // We render RSC stream after handling server function request + // so that new render reflects updated state from server function call + // to achieve single round trip to mutate and fetch from server. + const rscPayload: RscPayload = { + root: , + formState, + returnValue, + }; + + const rscOptions = { temporaryReferences }; + const rscStream = renderToReadableStream(rscPayload, rscOptions); + + // Respond RSC stream without HTML rendering as decided by `RenderRequest` + if (renderRequest.isRsc) { + return new Response(rscStream, { + status: actionStatus, + headers: { + "content-type": "text/x-component;charset=utf-8", + }, + }); + } + + // Delegate to SSR environment for HTML rendering. + // The plugin provides `loadModule` helper to allow loading SSR environment entry module + // in RSC environment. however this can be customized by implementing own runtime communication + // e.g. `@cloudflare/vite-plugin`'s service binding. + const ssrEntryModule = await import.meta.viteRsc.loadModule( + "ssr", + "index" + ); + + const ssrResult = await ssrEntryModule.renderHTML(rscStream, { + formState, + // Allow quick simulation of JavaScript disabled browser + debugNoJS: renderRequest.url.searchParams.has("__nojs"), + }); + + // Respond HTML + return new Response(ssrResult.stream, { + status: ssrResult.status, + headers: { + "Content-Type": "text/html", + }, + }); +} + +if (import.meta.hot) { + import.meta.hot.accept(); +} diff --git a/examples/vite-rsc/app/framework/entry.ssr.tsx b/examples/vite-rsc/app/framework/entry.ssr.tsx new file mode 100644 index 0000000000..bfefb51c91 --- /dev/null +++ b/examples/vite-rsc/app/framework/entry.ssr.tsx @@ -0,0 +1,82 @@ +import { createFromReadableStream } from "@vitejs/plugin-rsc/ssr"; +import React from "react"; +import type { ReactFormState } from "react-dom/client"; +import { renderToReadableStream } from "react-dom/server.edge"; +import { injectRSCPayload } from "rsc-html-stream/server"; +import type { RscPayload } from "./entry.rsc"; + +export default { + fetch: async (request: Request) => { + const rscEntryModule = await import.meta.viteRsc.loadModule( + "rsc", + "index" + ); + return rscEntryModule.default(request); + }, +}; + +export async function renderHTML( + rscStream: ReadableStream, + options: { + formState?: ReactFormState; + nonce?: string; + debugNoJS?: boolean; + } +): Promise<{ stream: ReadableStream; status?: number }> { + // Duplicate one RSC stream into two. + // - one for SSR (ReactClient.createFromReadableStream below) + // - another for browser hydration payload by injecting . + const [rscStream1, rscStream2] = rscStream.tee(); + + // Deserialize RSC stream back to React VDOM + let payload: Promise | undefined; + function SsrRoot() { + // Deserialization needs to be kicked off inside ReactDOMServer context + // for ReactDOMServer preinit/preloading to work + payload ??= createFromReadableStream(rscStream1); + return React.use(payload).root; + } + + // Render HTML (traditional SSR) + const bootstrapScriptContent = await import.meta.viteRsc.loadBootstrapScriptContent("index"); + + let htmlStream: ReadableStream; + let status: number | undefined; + + try { + htmlStream = await renderToReadableStream(, { + bootstrapScriptContent: options?.debugNoJS ? undefined : bootstrapScriptContent, + nonce: options?.nonce, + formState: options?.formState, + }); + } catch { + // fallback to render an empty shell and run pure CSR on browser, + // which can replay server component error and trigger error boundary. + status = 500; + htmlStream = await renderToReadableStream( + + + + + , + { + bootstrapScriptContent: + `self.__NO_HYDRATE=1;` + (options?.debugNoJS ? "" : bootstrapScriptContent), + nonce: options?.nonce, + } + ); + } + + let responseStream: ReadableStream = htmlStream; + if (!options?.debugNoJS) { + // Initial RSC stream is injected in HTML stream as + // using utility made by devongovett https://github.com/devongovett/rsc-html-stream + responseStream = responseStream.pipeThrough( + injectRSCPayload(rscStream2, { + nonce: options?.nonce, + }) + ); + } + + return { stream: responseStream, status }; +} diff --git a/examples/vite-rsc/app/framework/error-boundary.tsx b/examples/vite-rsc/app/framework/error-boundary.tsx new file mode 100644 index 0000000000..fbc7b22122 --- /dev/null +++ b/examples/vite-rsc/app/framework/error-boundary.tsx @@ -0,0 +1,75 @@ +"use client"; + +import React from "react"; + +// Minimal ErrorBoundary example to handle errors globally on browser +export function GlobalErrorBoundary(props: { children?: React.ReactNode }) { + return {props.children}; +} + +// https://github.com/vercel/next.js/blob/33f8428f7066bf8b2ec61f025427ceb2a54c4bdf/packages/next/src/client/components/error-boundary.tsx +// https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary +class ErrorBoundary extends React.Component<{ + children?: React.ReactNode; + errorComponent: React.FC<{ + error: Error; + reset: () => void; + }>; +}> { + override state: { error?: Error } = {}; + + static getDerivedStateFromError(error: Error) { + return { error }; + } + + reset = () => { + this.setState({ error: null }); + }; + + override render() { + const error = this.state.error; + if (error) { + return ; + } + return this.props.children; + } +} + +// https://github.com/vercel/next.js/blob/677c9b372faef680d17e9ba224743f44e1107661/packages/next/src/build/webpack/loaders/next-app-loader.ts#L73 +// https://github.com/vercel/next.js/blob/677c9b372faef680d17e9ba224743f44e1107661/packages/next/src/client/components/error-boundary.tsx#L145 +function DefaultGlobalErrorPage(props: { error: Error; reset: () => void }) { + return ( + + + Unexpected Error + + +

Caught an unexpected error

+
+          Error:{" "}
+          {import.meta.env.DEV && "message" in props.error ? props.error.message : "(Unknown)"}
+        
+ + + + ); +} diff --git a/examples/vite-rsc/app/framework/request.tsx b/examples/vite-rsc/app/framework/request.tsx new file mode 100644 index 0000000000..d68a29547c --- /dev/null +++ b/examples/vite-rsc/app/framework/request.tsx @@ -0,0 +1,58 @@ +// Framework conventions (arbitrary choices for this demo): +// - Use `_.rsc` URL suffix to differentiate RSC requests from SSR requests +// - Use `x-rsc-action` header to pass server action ID +const URL_POSTFIX = "_.rsc"; +const HEADER_ACTION_ID = "x-rsc-action"; + +// Parsed request information used to route between RSC/SSR rendering and action handling. +// Created by parseRenderRequest() from incoming HTTP requests. +type RenderRequest = { + isRsc: boolean; // true if request should return RSC payload (via _.rsc suffix) + isAction: boolean; // true if this is a server action call (POST request) + actionId?: string; // server action ID from x-rsc-action header + request: Request; // normalized Request with _.rsc suffix removed from URL + url: URL; // normalized URL with _.rsc suffix removed +}; + +export function createRscRenderRequest( + urlString: string, + action?: { id: string; body: BodyInit } +): Request { + const url = new URL(urlString); + url.pathname += URL_POSTFIX; + const headers = new Headers(); + if (action) { + headers.set(HEADER_ACTION_ID, action.id); + } + return new Request(url.toString(), { + method: action ? "POST" : "GET", + headers, + body: action?.body, + }); +} + +export function parseRenderRequest(request: Request): RenderRequest { + const url = new URL(request.url); + const isAction = request.method === "POST"; + if (url.pathname.endsWith(URL_POSTFIX)) { + url.pathname = url.pathname.slice(0, -URL_POSTFIX.length); + const actionId = request.headers.get(HEADER_ACTION_ID) || undefined; + if (request.method === "POST" && !actionId) { + throw new Error("Missing action id header for RSC action request"); + } + return { + isRsc: true, + isAction, + actionId, + request: new Request(url, request), + url, + }; + } else { + return { + isRsc: false, + isAction, + request, + url, + }; + } +} diff --git a/examples/vite-rsc/app/index.css b/examples/vite-rsc/app/index.css new file mode 100644 index 0000000000..f4d2128c01 --- /dev/null +++ b/examples/vite-rsc/app/index.css @@ -0,0 +1,112 @@ +:root { + font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} + +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.react:hover { + filter: drop-shadow(0 0 2em #61dafbaa); +} + +@keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +@media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } +} + +.card { + padding: 1rem; +} + +.read-the-docs { + color: #888; + text-align: left; +} diff --git a/examples/vite-rsc/app/root.tsx b/examples/vite-rsc/app/root.tsx new file mode 100644 index 0000000000..be38084b18 --- /dev/null +++ b/examples/vite-rsc/app/root.tsx @@ -0,0 +1,74 @@ +import "./index.css"; // css import is automatically injected in exported server components +import viteLogo from "./assets/vite.svg"; +import { getServerCounter, updateServerCounter } from "./action.tsx"; +import reactLogo from "./assets/react.svg"; +import nitroLogo from "./assets/nitro.svg"; +import { ClientCounter } from "./client.tsx"; + +export function Root(props: { url: URL }) { + return ( + + + {/* eslint-disable-next-line unicorn/text-encoding-identifier-case */} + + + + Nitro + Vite + RSC + + + + + + ); +} + +function App(props: { url: URL }) { + return ( +
+ +

Vite + RSC + Nitro

+
+ +
+
+ + + +
+
Request URL: {props.url?.href}
+
    +
  • + Edit src/client.tsx to test client HMR. +
  • +
  • + Edit src/root.tsx to test server HMR. +
  • +
  • + Visit{" "} + + _.rsc + {" "} + to view RSC stream payload. +
  • +
  • + Visit{" "} + + ?__nojs + {" "} + to test server action without js enabled. +
  • +
+
+ ); +} diff --git a/examples/vite-rsc/package.json b/examples/vite-rsc/package.json new file mode 100644 index 0000000000..1bab1e0dba --- /dev/null +++ b/examples/vite-rsc/package.json @@ -0,0 +1,25 @@ +{ + "name": "@vitejs/plugin-rsc-examples-starter", + "version": "0.0.0", + "private": true, + "license": "MIT", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "react": "^19.2.4", + "react-dom": "^19.2.4" + }, + "devDependencies": { + "@types/react": "^19.2.13", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^5.1.3", + "@vitejs/plugin-rsc": "^0.5.19", + "nitro": "latest", + "rsc-html-stream": "^0.0.7", + "vite": "beta" + } +} diff --git a/examples/vite-rsc/tsconfig.json b/examples/vite-rsc/tsconfig.json new file mode 100644 index 0000000000..a7b38dc3ca --- /dev/null +++ b/examples/vite-rsc/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "nitro/tsconfig", + "compilerOptions": { + "lib": ["ESNext", "DOM", "DOM.Iterable"], + "types": ["vite/client", "@vitejs/plugin-rsc/types"], + "jsx": "react-jsx" + } +} diff --git a/examples/vite-rsc/vite.config.ts b/examples/vite-rsc/vite.config.ts new file mode 100644 index 0000000000..53e06b1199 --- /dev/null +++ b/examples/vite-rsc/vite.config.ts @@ -0,0 +1,29 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +import rsc from "@vitejs/plugin-rsc"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [ + nitro(), + rsc({ + serverHandler: false, + entries: { + ssr: "./app/framework/entry.ssr.tsx", + rsc: "./app/framework/entry.rsc.tsx", + }, + }), + react(), + ], + + environments: { + client: { + build: { + rollupOptions: { + input: { index: "./app/framework/entry.browser.tsx" }, + }, + }, + }, + }, +}); diff --git a/examples/vite-ssr-html/README.md b/examples/vite-ssr-html/README.md new file mode 100644 index 0000000000..201bc2a689 --- /dev/null +++ b/examples/vite-ssr-html/README.md @@ -0,0 +1,16 @@ +This example renders an HTML template with server-side data and streams the response word by word. It demonstrates how to use Nitro's Vite SSR integration without a framework. + +## Overview + +1. **Add the Nitro Vite plugin** to enable SSR +2. **Create an HTML template** with a `` comment where server content goes +3. **Create a server entry** that fetches data and returns a stream +4. **Add API routes** for server-side data + +## How It Works + +The `index.html` file contains an `` comment that marks where server-rendered content will be inserted. Nitro replaces this comment with the output from your server entry. + +The server entry exports an object with a `fetch` method. It calls the `/quote` API route using Nitro's internal fetch, then returns a `ReadableStream` that emits the quote text word by word with a 50ms delay between each word. + +The quote route fetches a JSON file of quotes from GitHub, caches the result, and returns a random quote. The server entry calls this route to get content for the page. diff --git a/examples/vite-ssr-html/app/entry-server.ts b/examples/vite-ssr-html/app/entry-server.ts new file mode 100644 index 0000000000..89a5a9eee4 --- /dev/null +++ b/examples/vite-ssr-html/app/entry-server.ts @@ -0,0 +1,29 @@ +import { fetch } from "nitro"; + +export default { + async fetch() { + const quote = (await fetch("/quote").then((res) => res.json())) as { + text: string; + }; + return tokenizedStream(quote.text, 50); + }, +}; + +function tokenizedStream(text: string, delay: number): ReadableStream { + const tokens = text.split(" "); + return new ReadableStream({ + start(controller) { + let index = 0; + function push() { + if (index < tokens.length) { + const word = tokens[index++] + (index < tokens.length ? " " : ""); + controller.enqueue(new TextEncoder().encode(word)); + setTimeout(push, delay); + } else { + controller.close(); + } + } + push(); + }, + }); +} diff --git a/examples/vite-ssr-html/index.html b/examples/vite-ssr-html/index.html new file mode 100644 index 0000000000..857a2a86ff --- /dev/null +++ b/examples/vite-ssr-html/index.html @@ -0,0 +1,94 @@ + + + + + + Nitro Quotes + + + +
+
+
+ +
+
+ +
+
+ Powered by + Vite + and + Nitro v3. +
+
+ + + + diff --git a/examples/vite-ssr-html/package.json b/examples/vite-ssr-html/package.json new file mode 100644 index 0000000000..c643f95e91 --- /dev/null +++ b/examples/vite-ssr-html/package.json @@ -0,0 +1,14 @@ +{ + "type": "module", + "scripts": { + "build": "vite build", + "dev": "vite dev", + "preview": "vite preview" + }, + "devDependencies": { + "@tailwindcss/vite": "^4.1.18", + "nitro": "latest", + "tailwindcss": "^4.1.18", + "vite": "beta" + } +} diff --git a/examples/vite-ssr-html/routes/quote.ts b/examples/vite-ssr-html/routes/quote.ts new file mode 100644 index 0000000000..c012a48bdb --- /dev/null +++ b/examples/vite-ssr-html/routes/quote.ts @@ -0,0 +1,19 @@ +const QUOTES_URL = + "https://github.com/JamesFT/Database-Quotes-JSON/raw/refs/heads/master/quotes.json"; + +let _quotes: Promise | undefined; + +function getQuotes() { + return (_quotes ??= fetch(QUOTES_URL).then((res) => res.json())) as Promise< + { quoteText: string; quoteAuthor: string }[] + >; +} + +export default async function quotesHandler() { + const quotes = await getQuotes(); + const randomQuote = quotes[Math.floor(Math.random() * quotes.length)]; + return Response.json({ + text: randomQuote.quoteText, + author: randomQuote.quoteAuthor, + }); +} diff --git a/examples/vite-ssr-html/tsconfig.json b/examples/vite-ssr-html/tsconfig.json new file mode 100644 index 0000000000..4b886bd47e --- /dev/null +++ b/examples/vite-ssr-html/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "nitro/tsconfig" +} diff --git a/examples/vite-ssr-html/vite.config.ts b/examples/vite-ssr-html/vite.config.ts new file mode 100644 index 0000000000..8640b2d672 --- /dev/null +++ b/examples/vite-ssr-html/vite.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +import tailwindcss from "@tailwindcss/vite"; + +export default defineConfig({ + plugins: [ + nitro({ + serverDir: "./", + }), + tailwindcss(), + ], +}); diff --git a/examples/vite-ssr-preact/README.md b/examples/vite-ssr-preact/README.md new file mode 100644 index 0000000000..37ebb134a4 --- /dev/null +++ b/examples/vite-ssr-preact/README.md @@ -0,0 +1,113 @@ +Set up server-side rendering (SSR) with Preact, Vite, and Nitro. This setup enables streaming HTML responses, automatic asset management, and client hydration. + +## Overview + +1. Add the Nitro Vite plugin to your Vite config +2. Configure client and server entry points +3. Create a server entry that renders your app to HTML +4. Create a client entry that hydrates the server-rendered HTML + +## 1. Configure Vite + +Add the Nitro and Preact plugins to your Vite config. Define the `client` environment with your client entry point: + +```js [vite.config.mjs] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; +import preact from "@preact/preset-vite"; + +export default defineConfig({ + plugins: [nitro(), preact()], + environments: { + client: { + build: { + rollupOptions: { + input: "./src/entry-client.tsx", + }, + }, + }, + }, +}); +``` + +The `environments.client` configuration tells Vite which file to use as the browser entry point. Nitro automatically detects the server entry from files named `entry-server` or `server` in common directories. + +## 2. Create the App Component + +Create a shared Preact component that runs on both server and client: + +```tsx [src/app.tsx] +import { useState } from "preact/hooks"; + +export function App() { + const [count, setCount] = useState(0); + return ; +} +``` + +## 3. Create the Server Entry + +The server entry renders your Preact app to a streaming HTML response using `preact-render-to-string/stream`: + +```tsx [src/entry-server.tsx] +import "./styles.css"; +import { renderToReadableStream } from "preact-render-to-string/stream"; +import { App } from "./app.jsx"; + +import clientAssets from "./entry-client?assets=client"; +import serverAssets from "./entry-server?assets=ssr"; + +export default { + async fetch(request: Request) { + const url = new URL(request.url); + const htmlStream = renderToReadableStream(); + return new Response(htmlStream, { + headers: { "Content-Type": "text/html;charset=utf-8" }, + }); + }, +}; + +function Root(props: { url: URL }) { + const assets = clientAssets.merge(serverAssets); + return ( + + + + {assets.css.map((attr: any) => ( + + ))} + {assets.js.map((attr: any) => ( + + ))} + + + +``` + +## 3. Create the App Entry + +Create the main entry that initializes TanStack Router: + +```tsx [src/main.tsx] +import { StrictMode } from "react"; +import ReactDOM from "react-dom/client"; +import { RouterProvider, createRouter } from "@tanstack/react-router"; + +// Import the generated route tree +import { routeTree } from "./routeTree.gen.ts"; + +// Create a new router instance +const router = createRouter({ routeTree }); + +// Register the router instance for type safety +declare module "@tanstack/react-router" { + interface Register { + router: typeof router; + } +} + +// Render the app +const rootElement = document.querySelector("#root")!; +if (!rootElement.innerHTML) { + const root = ReactDOM.createRoot(rootElement); + root.render( + + + + ); +} +``` + +The `routeTree.gen.ts` file is auto-generated from your `routes/` directory structure. The `Register` interface declaration provides full type inference for route paths and params. The `!rootElement.innerHTML` check prevents re-rendering during hot module replacement. + +## 4. Create the Root Route + +The root route (`__root.tsx`) defines your app's layout: + +```tsx [src/routes/__root.tsx] +import { createRootRoute, Link, Outlet } from "@tanstack/react-router"; +import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; + +const RootLayout = () => ( + <> +
+ + Home + +
+
+ + + +); + +export const Route = createRootRoute({ component: RootLayout }); +``` + +Use `Link` for type-safe navigation with active state styling. The `Outlet` component renders child routes. Include `TanStackRouterDevtools` for development tools (automatically removed in production). + +## 5. Create Page Routes + +Page routes use `createFileRoute` and can include loaders: + +```tsx [src/routes/index.tsx] +import { createFileRoute } from "@tanstack/react-router"; + +export const Route = createFileRoute("/")({ + loader: async () => { + const r = await fetch("/api/hello"); + return r.json(); + }, + component: Index, +}); + +function Index() { + const r = Route.useLoaderData(); + + return ( +
+

{JSON.stringify(r)}

+
+ ); +} +``` + +Fetch data before rendering with the `loader` function—data is available via `Route.useLoaderData()`. File paths determine URL paths: `routes/index.tsx` maps to `/`, `routes/about.tsx` to `/about`, and `routes/users/$id.tsx` to `/users/:id`. diff --git a/examples/vite-ssr-tsr-react/index.html b/examples/vite-ssr-tsr-react/index.html new file mode 100644 index 0000000000..7cc8fce45f --- /dev/null +++ b/examples/vite-ssr-tsr-react/index.html @@ -0,0 +1,13 @@ + + + + + + Nitro + TanStack Router + React + + + +
+ + + diff --git a/examples/vite-ssr-tsr-react/package.json b/examples/vite-ssr-tsr-react/package.json new file mode 100644 index 0000000000..3a5832186f --- /dev/null +++ b/examples/vite-ssr-tsr-react/package.json @@ -0,0 +1,20 @@ +{ + "type": "module", + "scripts": { + "build": "vite build", + "dev": "vite dev", + "preview": "vite preview" + }, + "devDependencies": { + "@tanstack/react-router": "^1.158.1", + "@tanstack/react-router-devtools": "^1.158.1", + "@tanstack/router-plugin": "^1.158.1", + "@types/react": "^19.2.13", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^5.1.3", + "nitro": "latest", + "react": "^19.2.4", + "react-dom": "^19.2.4", + "vite": "beta" + } +} diff --git a/examples/vite-ssr-tsr-react/src/assets/main.css b/examples/vite-ssr-tsr-react/src/assets/main.css new file mode 100644 index 0000000000..32cef36b5f --- /dev/null +++ b/examples/vite-ssr-tsr-react/src/assets/main.css @@ -0,0 +1,96 @@ +:root { + font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { + font-weight: 500; + color: #ff2056; + text-decoration: inherit; +} +a:hover { + color: #ff637e; +} + +body { + margin: 0; + display: flex; + flex-direction: column; + place-items: center; + justify-content: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; + transition: transform 300ms; +} +.logo:hover { + transform: scale(1.1); +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} diff --git a/examples/vite-ssr-tsr-react/src/main.tsx b/examples/vite-ssr-tsr-react/src/main.tsx new file mode 100644 index 0000000000..421c9ddfaa --- /dev/null +++ b/examples/vite-ssr-tsr-react/src/main.tsx @@ -0,0 +1,27 @@ +import { StrictMode } from "react"; +import ReactDOM from "react-dom/client"; +import { RouterProvider, createRouter } from "@tanstack/react-router"; + +// Import the generated route tree +import { routeTree } from "./routeTree.gen.ts"; + +// Create a new router instance +const router = createRouter({ routeTree }); + +// Register the router instance for type safety +declare module "@tanstack/react-router" { + interface Register { + router: typeof router; + } +} + +// Render the app +const rootElement = document.querySelector("#root")!; +if (!rootElement.innerHTML) { + const root = ReactDOM.createRoot(rootElement); + root.render( + + + + ); +} diff --git a/examples/vite-ssr-tsr-react/src/routeTree.gen.ts b/examples/vite-ssr-tsr-react/src/routeTree.gen.ts new file mode 100644 index 0000000000..d204c269b3 --- /dev/null +++ b/examples/vite-ssr-tsr-react/src/routeTree.gen.ts @@ -0,0 +1,59 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +import { Route as rootRouteImport } from './routes/__root' +import { Route as IndexRouteImport } from './routes/index' + +const IndexRoute = IndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => rootRouteImport, +} as any) + +export interface FileRoutesByFullPath { + '/': typeof IndexRoute +} +export interface FileRoutesByTo { + '/': typeof IndexRoute +} +export interface FileRoutesById { + __root__: typeof rootRouteImport + '/': typeof IndexRoute +} +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: '/' + fileRoutesByTo: FileRoutesByTo + to: '/' + id: '__root__' | '/' + fileRoutesById: FileRoutesById +} +export interface RootRouteChildren { + IndexRoute: typeof IndexRoute +} + +declare module '@tanstack/react-router' { + interface FileRoutesByPath { + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof IndexRouteImport + parentRoute: typeof rootRouteImport + } + } +} + +const rootRouteChildren: RootRouteChildren = { + IndexRoute: IndexRoute, +} +export const routeTree = rootRouteImport + ._addFileChildren(rootRouteChildren) + ._addFileTypes() diff --git a/examples/vite-ssr-tsr-react/src/routes/__root.tsx b/examples/vite-ssr-tsr-react/src/routes/__root.tsx new file mode 100644 index 0000000000..e5daecfefa --- /dev/null +++ b/examples/vite-ssr-tsr-react/src/routes/__root.tsx @@ -0,0 +1,17 @@ +import { createRootRoute, Link, Outlet } from "@tanstack/react-router"; +import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; + +const RootLayout = () => ( + <> +
+ + Home + +
+
+ + + +); + +export const Route = createRootRoute({ component: RootLayout }); diff --git a/examples/vite-ssr-tsr-react/src/routes/index.tsx b/examples/vite-ssr-tsr-react/src/routes/index.tsx new file mode 100644 index 0000000000..3f65932d06 --- /dev/null +++ b/examples/vite-ssr-tsr-react/src/routes/index.tsx @@ -0,0 +1,19 @@ +import { createFileRoute } from "@tanstack/react-router"; + +export const Route = createFileRoute("/")({ + loader: async () => { + const r = await fetch("/api/hello"); + return r.json(); + }, + component: Index, +}); + +function Index() { + const r = Route.useLoaderData(); + + return ( +
+

{JSON.stringify(r)}

+
+ ); +} diff --git a/examples/vite-ssr-tsr-react/tsconfig.json b/examples/vite-ssr-tsr-react/tsconfig.json new file mode 100644 index 0000000000..4a93148579 --- /dev/null +++ b/examples/vite-ssr-tsr-react/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "nitro/tsconfig", + "compilerOptions": { + "baseUrl": ".", + "jsx": "react-jsx", + "paths": { + "@/*": ["sec/*"] + } + } +} diff --git a/examples/vite-ssr-tsr-react/vite.config.mjs b/examples/vite-ssr-tsr-react/vite.config.mjs new file mode 100644 index 0000000000..a10866292e --- /dev/null +++ b/examples/vite-ssr-tsr-react/vite.config.mjs @@ -0,0 +1,8 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; +import react from "@vitejs/plugin-react"; +import { tanstackRouter } from "@tanstack/router-plugin/vite"; + +export default defineConfig({ + plugins: [tanstackRouter({ target: "react", autoCodeSplitting: true }), react(), nitro()], +}); diff --git a/examples/vite-ssr-tss-react/.gitignore b/examples/vite-ssr-tss-react/.gitignore new file mode 100644 index 0000000000..6ab0517d9f --- /dev/null +++ b/examples/vite-ssr-tss-react/.gitignore @@ -0,0 +1,20 @@ +node_modules +package-lock.json +yarn.lock + +.DS_Store +.cache +.env +.vercel +.output +.nitro +/build/ +/api/ +/server/build +/public/build# Sentry Config File +.env.sentry-build-plugin +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ +.tanstack \ No newline at end of file diff --git a/examples/vite-ssr-tss-react/README.md b/examples/vite-ssr-tss-react/README.md new file mode 100644 index 0000000000..c3808957d4 --- /dev/null +++ b/examples/vite-ssr-tss-react/README.md @@ -0,0 +1,153 @@ +Set up TanStack Start with Nitro for a full-stack React framework experience with server-side rendering, file-based routing, and integrated API routes. + +## Overview + +1. Add the Nitro Vite plugin to your Vite config +2. Create a server entry using TanStack Start's server handler +3. Configure the router with default components +4. Define routes and API endpoints using file-based routing + +## 1. Configure Vite + +Add the Nitro, React, TanStack Start, and Tailwind plugins to your Vite config: + +```js [vite.config.mjs] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; +import { tanstackStart } from "@tanstack/react-start/plugin/vite"; +import viteReact from "@vitejs/plugin-react"; +import viteTsConfigPaths from "vite-tsconfig-paths"; +import tailwindcss from "@tailwindcss/vite"; + +export default defineConfig({ + plugins: [ + viteTsConfigPaths({ projects: ["./tsconfig.json"] }), + tanstackStart(), + viteReact(), + tailwindcss(), + nitro(), + ], + environments: { + ssr: { build: { rollupOptions: { input: "./server.ts" } } }, + }, +}); +``` + +The `tanstackStart()` plugin provides full SSR integration with automatic client entry handling. Use `viteTsConfigPaths()` to enable path aliases like `~/` from tsconfig. The `environments.ssr` option points to the server entry file. + +## 2. Create the Server Entry + +Create a server entry that uses TanStack Start's handler: + +```ts [server.ts] +import handler, { createServerEntry } from "@tanstack/react-start/server-entry"; + +export default createServerEntry({ + fetch(request) { + return handler.fetch(request); + }, +}); +``` + +TanStack Start handles SSR automatically. The `createServerEntry` wrapper integrates with Nitro's server entry format, and the `handler.fetch` processes all incoming requests. + +## 3. Configure the Router + +Create a router factory function with default error and not-found components: + +```tsx [src/router.tsx] +import { createRouter } from "@tanstack/react-router"; +import { routeTree } from "./routeTree.gen.ts"; + +export function getRouter() { + const router = createRouter({ + routeTree, + defaultPreload: "intent", + defaultErrorComponent: () =>
Internal Server Error
, + defaultNotFoundComponent: () =>
Not Found
, + scrollRestoration: true, + }); + return router; +} +``` + +The router factory configures preloading behavior, scroll restoration, and default error/not-found components. + +## 4. Create the Root Route + +The root route defines your HTML shell with head management and scripts: + +```tsx [src/routes/__root.tsx] +/// +import { HeadContent, Link, Scripts, createRootRoute } from "@tanstack/react-router"; +import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; +import * as React from "react"; +import appCss from "~/styles/app.css?url"; + +export const Route = createRootRoute({ + head: () => ({ + meta: [ + { charSet: "utf8" }, + { name: "viewport", content: "width=device-width, initial-scale=1" }, + ], + links: [{ rel: "stylesheet", href: appCss }], + scripts: [{ src: "/customScript.js", type: "text/javascript" }], + }), + errorComponent: () =>

500: Internal Server Error

, + notFoundComponent: () =>

404: Page Not Found

, + shellComponent: RootDocument, +}); + +function RootDocument({ children }: { children: React.ReactNode }) { + return ( + + + + + +
+ + Home + {" "} + + 404 + +
+
+ {children} + + + + + ); +} +``` + +Define meta tags, stylesheets, and scripts in the `head()` function. The `shellComponent` provides the HTML document shell that wraps all pages. Use `HeadContent` to render the head configuration and `Scripts` to inject the client-side JavaScript for hydration. + +## 5. Create Page Routes + +Page routes define your application pages: + +```tsx [src/routes/index.tsx] +import { createFileRoute } from "@tanstack/react-router"; + +export const Route = createFileRoute("/")({ component: Home }); + +function Home() { + return ( +
+

Welcome Home!

+ /api/test +
+ ); +} +``` + +## API Routes + +TanStack Start supports API routes alongside page routes. Create files in `src/routes/api/` to define server endpoints that Nitro serves automatically. diff --git a/examples/vite-ssr-tss-react/package.json b/examples/vite-ssr-tss-react/package.json new file mode 100644 index 0000000000..6694b36d2d --- /dev/null +++ b/examples/vite-ssr-tss-react/package.json @@ -0,0 +1,29 @@ +{ + "type": "module", + "scripts": { + "build": "vite build", + "dev": "vite dev", + "start": "node .output/server/index.mjs" + }, + "dependencies": { + "@tanstack/react-router": "^1.158.1", + "@tanstack/react-router-devtools": "^1.158.1", + "@tanstack/react-start": "^1.158.3", + "nitro": "latest", + "react": "^19.2.4", + "react-dom": "^19.2.4", + "tailwind-merge": "^3.4.0", + "zod": "^4.3.6" + }, + "devDependencies": { + "@tailwindcss/vite": "^4.1.18", + "@types/node": "latest", + "@types/react": "^19.2.13", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^5.1.3", + "tailwindcss": "^4.1.18", + "typescript": "^5.9.3", + "vite": "beta", + "vite-tsconfig-paths": "^6.0.5" + } +} diff --git a/examples/vite-ssr-tss-react/server.ts b/examples/vite-ssr-tss-react/server.ts new file mode 100644 index 0000000000..eba235906e --- /dev/null +++ b/examples/vite-ssr-tss-react/server.ts @@ -0,0 +1,7 @@ +import handler, { createServerEntry } from "@tanstack/react-start/server-entry"; + +export default createServerEntry({ + fetch(request) { + return handler.fetch(request); + }, +}); diff --git a/examples/vite-ssr-tss-react/src/routeTree.gen.ts b/examples/vite-ssr-tss-react/src/routeTree.gen.ts new file mode 100644 index 0000000000..d82f37e31e --- /dev/null +++ b/examples/vite-ssr-tss-react/src/routeTree.gen.ts @@ -0,0 +1,86 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +import { Route as rootRouteImport } from './routes/__root' +import { Route as IndexRouteImport } from './routes/index' +import { Route as ApiTestRouteImport } from './routes/api/test' + +const IndexRoute = IndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => rootRouteImport, +} as any) +const ApiTestRoute = ApiTestRouteImport.update({ + id: '/api/test', + path: '/api/test', + getParentRoute: () => rootRouteImport, +} as any) + +export interface FileRoutesByFullPath { + '/': typeof IndexRoute + '/api/test': typeof ApiTestRoute +} +export interface FileRoutesByTo { + '/': typeof IndexRoute + '/api/test': typeof ApiTestRoute +} +export interface FileRoutesById { + __root__: typeof rootRouteImport + '/': typeof IndexRoute + '/api/test': typeof ApiTestRoute +} +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: '/' | '/api/test' + fileRoutesByTo: FileRoutesByTo + to: '/' | '/api/test' + id: '__root__' | '/' | '/api/test' + fileRoutesById: FileRoutesById +} +export interface RootRouteChildren { + IndexRoute: typeof IndexRoute + ApiTestRoute: typeof ApiTestRoute +} + +declare module '@tanstack/react-router' { + interface FileRoutesByPath { + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof IndexRouteImport + parentRoute: typeof rootRouteImport + } + '/api/test': { + id: '/api/test' + path: '/api/test' + fullPath: '/api/test' + preLoaderRoute: typeof ApiTestRouteImport + parentRoute: typeof rootRouteImport + } + } +} + +const rootRouteChildren: RootRouteChildren = { + IndexRoute: IndexRoute, + ApiTestRoute: ApiTestRoute, +} +export const routeTree = rootRouteImport + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +import type { getRouter } from './router.tsx' +import type { createStart } from '@tanstack/react-start' +declare module '@tanstack/react-start' { + interface Register { + ssr: true + router: Awaited> + } +} diff --git a/examples/vite-ssr-tss-react/src/router.tsx b/examples/vite-ssr-tss-react/src/router.tsx new file mode 100644 index 0000000000..eb9f5f19d2 --- /dev/null +++ b/examples/vite-ssr-tss-react/src/router.tsx @@ -0,0 +1,13 @@ +import { createRouter } from "@tanstack/react-router"; +import { routeTree } from "./routeTree.gen.ts"; + +export function getRouter() { + const router = createRouter({ + routeTree, + defaultPreload: "intent", + defaultErrorComponent: () =>
Internal Server Error
, + defaultNotFoundComponent: () =>
Not Found
, + scrollRestoration: true, + }); + return router; +} diff --git a/examples/vite-ssr-tss-react/src/routes/__root.tsx b/examples/vite-ssr-tss-react/src/routes/__root.tsx new file mode 100644 index 0000000000..551690bb13 --- /dev/null +++ b/examples/vite-ssr-tss-react/src/routes/__root.tsx @@ -0,0 +1,47 @@ +/// +import { HeadContent, Link, Scripts, createRootRoute } from "@tanstack/react-router"; +import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; +import * as React from "react"; +import appCss from "~/styles/app.css?url"; + +export const Route = createRootRoute({ + head: () => ({ + meta: [ + { charSet: "utf8" }, + { name: "viewport", content: "width=device-width, initial-scale=1" }, + ], + links: [{ rel: "stylesheet", href: appCss }], + scripts: [{ src: "/customScript.js", type: "text/javascript" }], + }), + errorComponent: () =>

500: Internal Server Error

, + notFoundComponent: () =>

404: Page Not Found

, + shellComponent: RootDocument, +}); + +function RootDocument({ children }: { children: React.ReactNode }) { + return ( + + + + + +
+ + Home + {" "} + + 404 + +
+
+ {children} + + + + + ); +} diff --git a/examples/vite-ssr-tss-react/src/routes/api/test.ts b/examples/vite-ssr-tss-react/src/routes/api/test.ts new file mode 100644 index 0000000000..6ac0233b29 --- /dev/null +++ b/examples/vite-ssr-tss-react/src/routes/api/test.ts @@ -0,0 +1,19 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { createMiddleware, json } from "@tanstack/react-start"; + +const testMiddleware = createMiddleware().server(async ({ next }) => { + const result = await next(); + result.response.headers.set("x-test", "true"); + return result; +}); + +export const Route = createFileRoute("/api/test")({ + server: { + middleware: [testMiddleware], + handlers: { + GET: async ({ request }) => { + return json({ api: "works!" }); + }, + }, + }, +}); diff --git a/examples/vite-ssr-tss-react/src/routes/index.tsx b/examples/vite-ssr-tss-react/src/routes/index.tsx new file mode 100644 index 0000000000..fedef2c807 --- /dev/null +++ b/examples/vite-ssr-tss-react/src/routes/index.tsx @@ -0,0 +1,12 @@ +import { createFileRoute } from "@tanstack/react-router"; + +export const Route = createFileRoute("/")({ component: Home }); + +function Home() { + return ( +
+

Welcome Home!

+ /api/test +
+ ); +} diff --git a/examples/vite-ssr-tss-react/src/styles/app.css b/examples/vite-ssr-tss-react/src/styles/app.css new file mode 100644 index 0000000000..0e97467f18 --- /dev/null +++ b/examples/vite-ssr-tss-react/src/styles/app.css @@ -0,0 +1,30 @@ +@import "tailwindcss"; + +@layer base { + *, + ::after, + ::before, + ::backdrop, + ::file-selector-button { + border-color: var(--color-gray-200, currentcolor); + } +} + +@layer base { + html { + color-scheme: light dark; + } + + * { + @apply border-gray-200 dark:border-gray-800; + } + + html, + body { + @apply text-gray-900 bg-gray-50 dark:bg-gray-950 dark:text-gray-200; + } + + .using-mouse * { + outline: none !important; + } +} diff --git a/examples/vite-ssr-tss-react/tsconfig.json b/examples/vite-ssr-tss-react/tsconfig.json new file mode 100644 index 0000000000..d8a92f74e5 --- /dev/null +++ b/examples/vite-ssr-tss-react/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "nitro/tsconfig", + "compilerOptions": { + "baseUrl": ".", + "jsx": "react-jsx", + "paths": { + "~/*": ["./src/*"] + } + } +} diff --git a/examples/vite-ssr-tss-react/vite.config.mjs b/examples/vite-ssr-tss-react/vite.config.mjs new file mode 100644 index 0000000000..6cf34f0a64 --- /dev/null +++ b/examples/vite-ssr-tss-react/vite.config.mjs @@ -0,0 +1,19 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; +import { tanstackStart } from "@tanstack/react-start/plugin/vite"; +import viteReact from "@vitejs/plugin-react"; +import viteTsConfigPaths from "vite-tsconfig-paths"; +import tailwindcss from "@tailwindcss/vite"; + +export default defineConfig({ + plugins: [ + viteTsConfigPaths({ projects: ["./tsconfig.json"] }), + tanstackStart(), + viteReact(), + tailwindcss(), + nitro(), + ], + environments: { + ssr: { build: { rollupOptions: { input: "./server.ts" } } }, + }, +}); diff --git a/examples/vite-ssr-vue-router/README.md b/examples/vite-ssr-vue-router/README.md new file mode 100644 index 0000000000..b4ad7ac154 --- /dev/null +++ b/examples/vite-ssr-vue-router/README.md @@ -0,0 +1,241 @@ +Set up server-side rendering (SSR) with Vue, Vue Router, Vite, and Nitro. This setup enables per-route code splitting, head management with unhead, and client hydration. + +## Overview + +1. Add the Nitro Vite plugin to your Vite config +2. Define routes with lazy-loaded components +3. Create a server entry that renders your app with router support +4. Create a client entry that hydrates and takes over routing +5. Create page components + +## 1. Configure Vite + +Add the Nitro and Vue plugins to your Vite config. Define both `client` and `ssr` environments: + +```js [vite.config.mjs] +import vue from "@vitejs/plugin-vue"; +import { defineConfig } from "vite"; +import devtoolsJson from "vite-plugin-devtools-json"; +import { nitro } from "nitro/vite"; + +export default defineConfig((_env) => ({ + plugins: [patchVueExclude(vue(), /\?assets/), devtoolsJson(), nitro()], + environments: { + client: { build: { rollupOptions: { input: "./app/entry-client.ts" } } }, + ssr: { build: { rollupOptions: { input: "./app/entry-server.ts" } } }, + }, +})); + +// Workaround https://github.com/vitejs/vite-plugin-vue/issues/677 +function patchVueExclude(plugin, exclude) { + const original = plugin.transform.handler; + plugin.transform.handler = function (...args) { + if (exclude.test(args[1])) return; + return original.call(this, ...args); + }; + return plugin; +} +``` + +The `patchVueExclude` helper prevents the Vue plugin from processing asset imports (files with `?assets` query parameter). + +## 2. Define Routes + +Create route definitions with lazy-loaded components and asset metadata: + +```ts [app/routes.ts] +import type { RouteRecordRaw } from "vue-router"; + +export const routes: RouteRecordRaw[] = [ + { + path: "/", + name: "app", + component: () => import("./app.vue"), + meta: { + assets: () => import("./app.vue?assets"), + }, + children: [ + { + path: "/", + name: "home", + component: () => import("./pages/index.vue"), + meta: { + assets: () => import("./pages/index.vue?assets"), + }, + }, + { + path: "/about", + name: "about", + component: () => import("./pages/about.vue"), + meta: { + assets: () => import("./pages/about.vue?assets"), + }, + }, + { + path: "/:catchAll(.*)", + name: "not-found", + component: () => import("./pages/not-found.vue"), + meta: { + assets: () => import("./pages/not-found.vue?assets"), + }, + }, + ], + }, +]; +``` + +Use dynamic imports for lazy-loaded components to enable code splitting. The `meta.assets` function loads route-specific CSS and JS chunks. Define child routes under a root layout component for nested routing. + +## 3. Create the Server Entry + +The server entry renders your Vue app with router support and head management: + +```ts [app/entry-server.ts] +import { createSSRApp } from "vue"; +import { renderToString } from "vue/server-renderer"; +import { RouterView, createMemoryHistory, createRouter } from "vue-router"; +import { createHead, transformHtmlTemplate } from "unhead/server"; + +import { routes } from "./routes.ts"; + +import clientAssets from "./entry-client.ts?assets=client"; + +async function handler(request: Request): Promise { + const app = createSSRApp(RouterView); + const router = createRouter({ history: createMemoryHistory(), routes }); + app.use(router); + + const url = new URL(request.url); + const href = url.href.slice(url.origin.length); + + await router.push(href); + await router.isReady(); + + const assets = clientAssets.merge( + ...(await Promise.all( + router.currentRoute.value.matched + .map((to) => to.meta.assets) + .filter(Boolean) + .map((fn) => (fn as any)().then((m: any) => m.default)) + )) + ); + + const head = createHead(); + + head.push({ + link: [ + ...assets.css.map((attrs: any) => ({ rel: "stylesheet", ...attrs })), + ...assets.js.map((attrs: any) => ({ rel: "modulepreload", ...attrs })), + ], + script: [{ type: "module", src: clientAssets.entry }], + }); + + const renderedApp = await renderToString(app); + + const html = await transformHtmlTemplate(head, htmlTemplate(renderedApp)); + + return new Response(html, { + headers: { "Content-Type": "text/html;charset=utf-8" }, + }); +} + +function htmlTemplate(body: string): string { + return /* html */ ` + + + + + Vue Router Custom Framework + + +
${body}
+ +`; +} + +export default { + fetch: handler, +}; +``` + +The server uses `createMemoryHistory()` since there's no browser URL bar—the router navigates to the requested URL before rendering. Assets are loaded dynamically based on matched routes, ensuring only the CSS and JS needed for the current page are included. The `unhead` library manages `` elements, injecting stylesheets and scripts via `transformHtmlTemplate`. + +## 4. Create the Client Entry + +The client entry hydrates the server-rendered HTML and takes over routing: + +```ts [app/entry-client.ts] +import { createSSRApp } from "vue"; +import { RouterView, createRouter, createWebHistory } from "vue-router"; +import { routes } from "./routes.ts"; + +async function main() { + const app = createSSRApp(RouterView); + const router = createRouter({ history: createWebHistory(), routes }); + app.use(router); + + await router.isReady(); + app.mount("#root"); +} + +// eslint-disable-next-line unicorn/prefer-top-level-await +main(); +``` + +The client entry creates a Vue app with `createWebHistory()` for browser-based routing. After the router is ready, it mounts to the `#root` element and hydrates the server-rendered HTML. + +## 5. Create the Root Component + +The root component provides navigation and renders child routes: + +```vue [app/app.vue] + + + + + +``` diff --git a/examples/vite-ssr-vue-router/app/app.vue b/examples/vite-ssr-vue-router/app/app.vue new file mode 100644 index 0000000000..2363e361a0 --- /dev/null +++ b/examples/vite-ssr-vue-router/app/app.vue @@ -0,0 +1,49 @@ + + + + + diff --git a/examples/vite-ssr-vue-router/app/entry-client.ts b/examples/vite-ssr-vue-router/app/entry-client.ts new file mode 100644 index 0000000000..35c9b00b7c --- /dev/null +++ b/examples/vite-ssr-vue-router/app/entry-client.ts @@ -0,0 +1,15 @@ +import { createSSRApp } from "vue"; +import { RouterView, createRouter, createWebHistory } from "vue-router"; +import { routes } from "./routes.ts"; + +async function main() { + const app = createSSRApp(RouterView); + const router = createRouter({ history: createWebHistory(), routes }); + app.use(router); + + await router.isReady(); + app.mount("#root"); +} + +// eslint-disable-next-line unicorn/prefer-top-level-await +main(); diff --git a/examples/vite-ssr-vue-router/app/entry-server.ts b/examples/vite-ssr-vue-router/app/entry-server.ts new file mode 100644 index 0000000000..ce07e50a56 --- /dev/null +++ b/examples/vite-ssr-vue-router/app/entry-server.ts @@ -0,0 +1,65 @@ +import { createSSRApp } from "vue"; +import { renderToString } from "vue/server-renderer"; +import { RouterView, createMemoryHistory, createRouter } from "vue-router"; +import { createHead, transformHtmlTemplate } from "unhead/server"; + +import { routes } from "./routes.ts"; + +import clientAssets from "./entry-client.ts?assets=client"; + +async function handler(request: Request): Promise { + const app = createSSRApp(RouterView); + const router = createRouter({ history: createMemoryHistory(), routes }); + app.use(router); + + const url = new URL(request.url); + const href = url.href.slice(url.origin.length); + + await router.push(href); + await router.isReady(); + + const assets = clientAssets.merge( + ...(await Promise.all( + router.currentRoute.value.matched + .map((to) => to.meta.assets) + .filter(Boolean) + .map((fn) => (fn as any)().then((m: any) => m.default)) + )) + ); + + const head = createHead(); + + head.push({ + link: [ + ...assets.css.map((attrs: any) => ({ rel: "stylesheet", ...attrs })), + ...assets.js.map((attrs: any) => ({ rel: "modulepreload", ...attrs })), + ], + script: [{ type: "module", src: clientAssets.entry }], + }); + + const renderedApp = await renderToString(app); + + const html = await transformHtmlTemplate(head, htmlTemplate(renderedApp)); + + return new Response(html, { + headers: { "Content-Type": "text/html;charset=utf-8" }, + }); +} + +function htmlTemplate(body: string): string { + return /* html */ ` + + + + + Vue Router Custom Framework + + +
${body}
+ +`; +} + +export default { + fetch: handler, +}; diff --git a/examples/vite-ssr-vue-router/app/pages/about.vue b/examples/vite-ssr-vue-router/app/pages/about.vue new file mode 100644 index 0000000000..70cde26af9 --- /dev/null +++ b/examples/vite-ssr-vue-router/app/pages/about.vue @@ -0,0 +1,9 @@ + diff --git a/examples/vite-ssr-vue-router/app/pages/index.vue b/examples/vite-ssr-vue-router/app/pages/index.vue new file mode 100644 index 0000000000..90ef1a3ca4 --- /dev/null +++ b/examples/vite-ssr-vue-router/app/pages/index.vue @@ -0,0 +1,49 @@ + + + + + diff --git a/examples/vite-ssr-vue-router/app/pages/not-found.vue b/examples/vite-ssr-vue-router/app/pages/not-found.vue new file mode 100644 index 0000000000..199773af27 --- /dev/null +++ b/examples/vite-ssr-vue-router/app/pages/not-found.vue @@ -0,0 +1,5 @@ + diff --git a/examples/vite-ssr-vue-router/app/routes.ts b/examples/vite-ssr-vue-router/app/routes.ts new file mode 100644 index 0000000000..7b5d5e0de1 --- /dev/null +++ b/examples/vite-ssr-vue-router/app/routes.ts @@ -0,0 +1,38 @@ +import type { RouteRecordRaw } from "vue-router"; + +export const routes: RouteRecordRaw[] = [ + { + path: "/", + name: "app", + component: () => import("./app.vue"), + meta: { + assets: () => import("./app.vue?assets"), + }, + children: [ + { + path: "/", + name: "home", + component: () => import("./pages/index.vue"), + meta: { + assets: () => import("./pages/index.vue?assets"), + }, + }, + { + path: "/about", + name: "about", + component: () => import("./pages/about.vue"), + meta: { + assets: () => import("./pages/about.vue?assets"), + }, + }, + { + path: "/:catchAll(.*)", + name: "not-found", + component: () => import("./pages/not-found.vue"), + meta: { + assets: () => import("./pages/not-found.vue?assets"), + }, + }, + ], + }, +]; diff --git a/examples/vite-ssr-vue-router/app/shims.d.ts b/examples/vite-ssr-vue-router/app/shims.d.ts new file mode 100644 index 0000000000..d77b62be1d --- /dev/null +++ b/examples/vite-ssr-vue-router/app/shims.d.ts @@ -0,0 +1,5 @@ +declare module "*.vue" { + import type { DefineComponent } from "vue"; + const component: DefineComponent<{}, {}, any>; + export default component; +} diff --git a/examples/vite-ssr-vue-router/app/styles.css b/examples/vite-ssr-vue-router/app/styles.css new file mode 100644 index 0000000000..68314d9bd2 --- /dev/null +++ b/examples/vite-ssr-vue-router/app/styles.css @@ -0,0 +1,49 @@ +* { + box-sizing: border-box; +} + +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + background: #f5f5f5; + color: #333; +} + +main { + max-width: 800px; + margin: 0 auto; + padding: 2rem; +} + +h1 { + font-size: 2.5rem; + margin-bottom: 0.5rem; +} + +.card { + background: white; + border-radius: 8px; + padding: 2rem; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + margin: 2rem 0; +} + +button { + background: rgb(83, 91, 242); + color: white; + border: none; + padding: 0.5rem 1rem; + border-radius: 4px; + font-size: 1rem; + cursor: pointer; +} + +button:hover { + background: #535bf2; +} + +.subtitle { + color: #666; + font-size: 1.1rem; + margin-bottom: 2rem; +} diff --git a/examples/vite-ssr-vue-router/package.json b/examples/vite-ssr-vue-router/package.json new file mode 100644 index 0000000000..d3b42b8061 --- /dev/null +++ b/examples/vite-ssr-vue-router/package.json @@ -0,0 +1,17 @@ +{ + "type": "module", + "scripts": { + "build": "vite build", + "dev": "vite dev", + "preview": "vite preview" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^6.0.4", + "nitro": "latest", + "unhead": "^2.1.3", + "vite": "beta", + "vite-plugin-devtools-json": "^1.0.0", + "vue": "^3.5.27", + "vue-router": "^4.6.4" + } +} diff --git a/examples/vite-ssr-vue-router/tsconfig.json b/examples/vite-ssr-vue-router/tsconfig.json new file mode 100644 index 0000000000..4b886bd47e --- /dev/null +++ b/examples/vite-ssr-vue-router/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "nitro/tsconfig" +} diff --git a/examples/vite-ssr-vue-router/vite.config.mjs b/examples/vite-ssr-vue-router/vite.config.mjs new file mode 100644 index 0000000000..577118e51f --- /dev/null +++ b/examples/vite-ssr-vue-router/vite.config.mjs @@ -0,0 +1,22 @@ +import vue from "@vitejs/plugin-vue"; +import { defineConfig } from "vite"; +import devtoolsJson from "vite-plugin-devtools-json"; +import { nitro } from "nitro/vite"; + +export default defineConfig((_env) => ({ + plugins: [patchVueExclude(vue(), /\?assets/), devtoolsJson(), nitro()], + environments: { + client: { build: { rollupOptions: { input: "./app/entry-client.ts" } } }, + ssr: { build: { rollupOptions: { input: "./app/entry-server.ts" } } }, + }, +})); + +// Workaround https://github.com/vitejs/vite-plugin-vue/issues/677 +function patchVueExclude(plugin, exclude) { + const original = plugin.transform.handler; + plugin.transform.handler = function (...args) { + if (exclude.test(args[1])) return; + return original.call(this, ...args); + }; + return plugin; +} diff --git a/examples/vite-trpc/.gitignore b/examples/vite-trpc/.gitignore new file mode 100644 index 0000000000..f06235c460 --- /dev/null +++ b/examples/vite-trpc/.gitignore @@ -0,0 +1,2 @@ +node_modules +dist diff --git a/examples/vite-trpc/README.md b/examples/vite-trpc/README.md new file mode 100644 index 0000000000..87d2f9075f --- /dev/null +++ b/examples/vite-trpc/README.md @@ -0,0 +1,162 @@ +Set up tRPC with Vite and Nitro for end-to-end typesafe APIs without code generation. This example builds a counter with server-side rendering for the initial value and client-side updates. + +## Overview + +1. Configure Vite with the Nitro plugin and route tRPC requests +2. Create a tRPC router with procedures +3. Create an HTML page with server-side rendering and client interactivity + +## 1. Configure Vite + +Add the Nitro plugin and configure the `/trpc/**` route to point to your tRPC handler: + +```ts [vite.config.ts] +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ + plugins: [ + nitro({ + routes: { + "/trpc/**": "./server/trpc.ts", + }, + }), + ], +}); +``` + +The `routes` option maps URL patterns to handler files. All requests to `/trpc/*` are handled by the tRPC router. + +## 2. Create the tRPC Router + +Define your tRPC router with procedures and export it as a fetch handler: + +```ts [server/trpc.ts] +import { initTRPC } from "@trpc/server"; +import { fetchRequestHandler } from "@trpc/server/adapters/fetch"; + +let counter = 0; + +const t = initTRPC.create(); + +export const appRouter = t.router({ + get: t.procedure.query(() => { + return { value: counter }; + }), + + inc: t.procedure.mutation(() => { + counter++; + return { value: counter }; + }), +}); + +export type AppRouter = typeof appRouter; + +export default { + async fetch(request: Request): Promise { + return fetchRequestHandler({ + endpoint: "/trpc", + req: request, + router: appRouter, + }); + }, +}; +``` + +Define procedures using `t.procedure.query()` for read operations and `t.procedure.mutation()` for write operations. Export the `AppRouter` type so clients get full type inference. The default export uses tRPC's fetch adapter to handle incoming requests. + +## 3. Create the HTML Page + +Create an HTML page with server-side rendering and client-side interactivity: + +```html [index.html] + + + + + tRPC Counter + + + +
+
Counter
+
+ +
+ +
+ + + + +``` + +The ` + + + + + + + diff --git a/examples/vite-trpc/package.json b/examples/vite-trpc/package.json new file mode 100644 index 0000000000..237db1b07f --- /dev/null +++ b/examples/vite-trpc/package.json @@ -0,0 +1,15 @@ +{ + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "devDependencies": { + "@trpc/client": "^11.9.0", + "@trpc/server": "^11.9.0", + "nitro": "latest", + "vite": "beta", + "zod": "^4.3.6" + } +} diff --git a/examples/vite-trpc/server/trpc.ts b/examples/vite-trpc/server/trpc.ts new file mode 100644 index 0000000000..86cb85def9 --- /dev/null +++ b/examples/vite-trpc/server/trpc.ts @@ -0,0 +1,29 @@ +import { initTRPC } from "@trpc/server"; +import { fetchRequestHandler } from "@trpc/server/adapters/fetch"; + +let counter = 0; + +const t = initTRPC.create(); + +export const appRouter = t.router({ + get: t.procedure.query(() => { + return { value: counter }; + }), + + inc: t.procedure.mutation(() => { + counter++; + return { value: counter }; + }), +}); + +export type AppRouter = typeof appRouter; + +export default { + async fetch(request: Request): Promise { + return fetchRequestHandler({ + endpoint: "/trpc", + req: request, + router: appRouter, + }); + }, +}; diff --git a/examples/vite-trpc/tsconfig.json b/examples/vite-trpc/tsconfig.json new file mode 100644 index 0000000000..d1bf59a34b --- /dev/null +++ b/examples/vite-trpc/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "nitro/tsconfig", + "compilerOptions": {} +} diff --git a/examples/vite-trpc/vite.config.ts b/examples/vite-trpc/vite.config.ts new file mode 100644 index 0000000000..67b5d72233 --- /dev/null +++ b/examples/vite-trpc/vite.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ + plugins: [ + nitro({ + routes: { + "/trpc/**": "./server/trpc.ts", + }, + }), + ], +}); diff --git a/examples/websocket/README.md b/examples/websocket/README.md new file mode 100644 index 0000000000..8e966e83ac --- /dev/null +++ b/examples/websocket/README.md @@ -0,0 +1,34 @@ +This example implements a simple chat room using WebSockets. Clients connect, send messages, and receive messages from other users in real-time. The server broadcasts messages to all connected clients using pub/sub channels. + +## WebSocket Handler + +Create a WebSocket route using `defineWebSocketHandler`. + +```ts [routes/_ws.ts] +import { defineWebSocketHandler } from "nitro"; + +export default defineWebSocketHandler({ + open(peer) { + peer.send({ user: "server", message: `Welcome ${peer}!` }); + peer.publish("chat", { user: "server", message: `${peer} joined!` }); + peer.subscribe("chat"); + }, + message(peer, message) { + if (message.text().includes("ping")) { + peer.send({ user: "server", message: "pong" }); + } else { + const msg = { + user: peer.toString(), + message: message.toString(), + }; + peer.send(msg); // echo + peer.publish("chat", msg); + } + }, + close(peer) { + peer.publish("chat", { user: "server", message: `${peer} left!` }); + }, +}); +``` + +Different hooks are exposed by `defineWebSocketHandler()` to integrate with different parts of the websocket lifecycle. diff --git a/examples/websocket/index.html b/examples/websocket/index.html new file mode 100644 index 0000000000..fb7ead4f21 --- /dev/null +++ b/examples/websocket/index.html @@ -0,0 +1,170 @@ + + + CrossWS Test Page + + + + + +
+ +
+
+
+

{{ message.user }}

+
+ Avatar +
+

+

{{ message.text }}

+
+
+

{{ message.date }}

+
+
+
+ + +
+
+ +
+
+ + + + +
+
+
+ + +` diff --git a/examples/websocket/nitro.config.ts b/examples/websocket/nitro.config.ts index 477a3c4b8b..8d3b7a04fb 100644 --- a/examples/websocket/nitro.config.ts +++ b/examples/websocket/nitro.config.ts @@ -1,6 +1,7 @@ -export default defineNitroConfig({ - compatibilityDate: "2025-03-01", - experimental: { - websocket: true, - }, +import { defineConfig } from "nitro"; + +export default defineConfig({ + serverDir: "./", + renderer: { static: true }, + features: { websocket: true }, }); diff --git a/examples/websocket/package.json b/examples/websocket/package.json index ec68efc465..736abd40ad 100644 --- a/examples/websocket/package.json +++ b/examples/websocket/package.json @@ -1,11 +1,10 @@ { - "name": "example-websocket", - "private": true, + "type": "module", "scripts": { "dev": "nitro dev", "build": "nitro build" }, "devDependencies": { - "nitropack": "latest" + "nitro": "latest" } } diff --git a/examples/websocket/routes/_ws.ts b/examples/websocket/routes/_ws.ts index 073e901f97..032e3818c8 100644 --- a/examples/websocket/routes/_ws.ts +++ b/examples/websocket/routes/_ws.ts @@ -1,3 +1,5 @@ +import { defineWebSocketHandler } from "nitro"; + export default defineWebSocketHandler({ open(peer) { peer.send({ user: "server", message: `Welcome ${peer}!` }); diff --git a/examples/websocket/routes/index.ts b/examples/websocket/routes/index.ts deleted file mode 100644 index e199e1e59c..0000000000 --- a/examples/websocket/routes/index.ts +++ /dev/null @@ -1,191 +0,0 @@ -export default defineEventHandler(() => { - return /* html */ ` - - - CrossWS Test Page - - - - - -
- -
-
-
-

{{ message.user }}

-
- Avatar -
-

-

{{ message.text }}

-
-
-

{{ message.date }}

-
-
-
- - -
-
- -
-
- - - - -
-
-
- - `; -}); diff --git a/examples/websocket/tsconfig.json b/examples/websocket/tsconfig.json index 43008af1c7..4b886bd47e 100644 --- a/examples/websocket/tsconfig.json +++ b/examples/websocket/tsconfig.json @@ -1,3 +1,3 @@ { - "extends": "./.nitro/types/tsconfig.json" + "extends": "nitro/tsconfig" } diff --git a/examples/websocket/vite.config.ts b/examples/websocket/vite.config.ts new file mode 100644 index 0000000000..34d3353e1c --- /dev/null +++ b/examples/websocket/vite.config.ts @@ -0,0 +1,4 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ plugins: [nitro()] }); diff --git a/lib/h3.d.mts b/lib/h3.d.mts new file mode 100644 index 0000000000..2371d1877e --- /dev/null +++ b/lib/h3.d.mts @@ -0,0 +1 @@ +export * from "h3"; diff --git a/lib/h3.mjs b/lib/h3.mjs new file mode 100644 index 0000000000..2371d1877e --- /dev/null +++ b/lib/h3.mjs @@ -0,0 +1 @@ +export * from "h3"; diff --git a/lib/tsconfig.json b/lib/tsconfig.json new file mode 100644 index 0000000000..cf018e94e0 --- /dev/null +++ b/lib/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "Bundler", + "moduleDetection": "force", + "isolatedModules": true, + "verbatimModuleSyntax": true, + + "allowJs": true, + "allowImportingTsExtensions": true, + "strict": true, + "noEmit": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, + "noImplicitOverride": true, + "resolvePackageJsonImports": true, + + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + } +} diff --git a/lib/vite.types.d.mts b/lib/vite.types.d.mts new file mode 100644 index 0000000000..2664de2700 --- /dev/null +++ b/lib/vite.types.d.mts @@ -0,0 +1,26 @@ +// Based on https://github.com/hi-ogawa/vite-plugin-fullstack/blob/main/types/query.d.ts + +type ImportAssetsResult = ImportAssetsResultRaw & { + merge(...args: ImportAssetsResultRaw[]): ImportAssetsResult; +}; + +type ImportAssetsResultRaw = { + entry?: string; + js: { href: string }[]; + css: { href: string; "data-vite-dev-id"?: string }[]; +}; + +declare module "*?assets" { + const assets: ImportAssetsResult; + export default assets; +} + +declare module "*?assets=client" { + const assets: ImportAssetsResult; + export default assets; +} + +declare module "*?assets=ssr" { + const assets: ImportAssetsResult; + export default assets; +} diff --git a/lib/vite.types.mjs b/lib/vite.types.mjs new file mode 100644 index 0000000000..6f0b2bad6d --- /dev/null +++ b/lib/vite.types.mjs @@ -0,0 +1,2 @@ +// eslint-disable-next-line unicorn/require-module-specifiers +export {}; diff --git a/package.json b/package.json index 75d0692b94..9ae7d3ce2d 100644 --- a/package.json +++ b/package.json @@ -1,244 +1,232 @@ { - "name": "nitropack", - "version": "2.11.6", + "name": "nitro", + "version": "3.0.260311-beta", "description": "Build and Deploy Universal JavaScript Servers", - "repository": "nitrojs/nitro", + "keywords": [ + "api-routes", + "full-stack", + "h3", + "nitro", + "server", + "typescript", + "vite", + "vite-plugin", + "web" + ], + "homepage": "https://nitro.build", "license": "MIT", - "type": "module", - "exports": { - "./cli": { - "types": "./cli.d.ts", - "import": "./dist/cli/index.mjs" - }, - "./config": { - "types": "./config.d.ts", - "import": "./dist/config/index.mjs" - }, - ".": { - "types": "./dist/core/index.d.ts", - "import": "./dist/core/index.mjs" - }, - "./core": { - "types": "./dist/core/index.d.ts", - "import": "./dist/core/index.mjs" - }, - "./kit": { - "types": "./kit.d.ts", - "import": "./dist/kit/index.mjs" - }, - "./meta": { - "types": "./dist/meta/index.d.ts", - "import": "./dist/meta/index.mjs" - }, - "./presets": { - "types": "./presets.d.ts", - "import": "./dist/presets/index.mjs" - }, - "./presets/*": { - "types": "./dist/presets/*.d.ts", - "import": "./dist/presets/*.mjs" - }, - "./rollup": { - "types": "./rollup.d.ts", - "import": "./dist/rollup/index.mjs" - }, - "./runtime": { - "types": "./runtime.d.ts", - "import": "./dist/runtime/index.mjs" - }, - "./runtime/meta": { - "types": "./runtime-meta.d.ts", - "import": "./runtime-meta.mjs" - }, - "./runtime/*": { - "types": "./dist/runtime/*.d.ts", - "import": "./dist/runtime/*.mjs" - }, - "./dist/runtime/*": { - "types": "./dist/runtime/*.d.ts", - "import": "./dist/runtime/*.mjs" - }, - "./types": { - "types": "./types.d.ts", - "import": "./dist/types/index.mjs" - }, - "./package.json": "./package.json" - }, - "main": "./dist/core/index.mjs", - "types": "./dist/core/index.d.ts", + "repository": "nitrojs/nitro", "bin": { - "nitro": "./dist/cli/index.mjs", - "nitropack": "./dist/cli/index.mjs" + "nitro": "./dist/cli/index.mjs" }, "files": [ "dist", - "*.d.ts", - "runtime-meta.*" + "lib", + "skills" ], + "type": "module", + "types": "./lib/index.d.mts", + "imports": { + "#nitro/runtime/*": "./dist/runtime/internal/*.mjs", + "#nitro/virtual/*": "./dist/runtime/virtual/*.mjs" + }, + "exports": { + ".": "./dist/runtime/nitro.mjs", + "./app": "./dist/runtime/app.mjs", + "./builder": "./dist/builder.mjs", + "./cache": "./dist/runtime/cache.mjs", + "./config": "./dist/runtime/config.mjs", + "./context": "./dist/runtime/context.mjs", + "./database": "./dist/runtime/database.mjs", + "./h3": "./lib/h3.mjs", + "./meta": "./dist/runtime/meta.mjs", + "./package.json": "./package.json", + "./runtime-config": "./dist/runtime/runtime-config.mjs", + "./storage": "./dist/runtime/storage.mjs", + "./task": "./dist/runtime/task.mjs", + "./tsconfig": "./lib/tsconfig.json", + "./types": "./dist/types/index.mjs", + "./vite": "./dist/vite.mjs", + "./vite/runtime": "./dist/runtime/vite.mjs", + "./vite/types": "./lib/vite.types.mjs" + }, "scripts": { - "build": "pnpm gen-presets && unbuild", - "dev": "pnpm nitro dev playground", - "dev:build": "pnpm nitro build playground", + "build": "pnpm gen-presets && obuild", + "dev": "pnpm -C playground dev", + "dev:build": "pnpm -C playground build", "dev:start": "node playground/.output/server/index.mjs", - "gen-mirror": "pnpm jiti scripts/gen-mirror.ts", - "gen-node-compat": "pnpm node-ts scripts/gen-node-compat.ts", - "gen-presets": "pnpm jiti scripts/gen-presets.ts", - "lint": "eslint --cache . && prettier -c .", - "lint:fix": "eslint --cache --fix . && prettier -w .", - "nitro": "jiti ./src/cli/index.ts", - "node-ts": "node --disable-warning=ExperimentalWarning --experimental-strip-types", - "prepack": "pnpm build", - "release": "pnpm test && pnpm build && changelogen --release && pnpm publish && git push --follow-tags", - "stub": "unbuild --stub", - "test": "pnpm lint && pnpm vitest run", - "test:fixture:types": "pnpm stub && jiti ./test/scripts/gen-fixture-types.ts && cd test/fixture && tsc --noEmit", - "test:types": "tsc --noEmit && pnpm test:fixture:types" - }, - "resolutions": { - "nitropack": "link:." + "gen-node-compat": "node scripts/gen-node-compat.ts", + "gen-presets": "obuild --stub && node ./scripts/gen-presets.ts", + "lint": "oxlint . && oxfmt --check .", + "format": "automd && oxlint --fix . && oxfmt .", + "nitro": "node ./src/cli/index.ts", + "release": "node ./scripts/release.js", + "stub": "obuild --stub", + "test": "pnpm lint && pnpm typecheck && pnpm test:rollup && pnpm test:rolldown", + "test:rolldown": "NITRO_BUILDER=rolldown pnpm vitest", + "test:rollup": "NITRO_BUILDER=rollup pnpm vitest", + "typecheck": "tsgo --noEmit --skipLibCheck" }, "dependencies": { - "@cloudflare/kv-asset-handler": "^0.3.4", - "@netlify/functions": "3.0.0", - "@rollup/plugin-alias": "^5.1.1", - "@rollup/plugin-commonjs": "^28.0.3", + "consola": "^3.4.2", + "crossws": "^0.4.4", + "db0": "^0.3.4", + "env-runner": "^0.1.6", + "h3": "^2.0.1-rc.16", + "hookable": "^6.0.1", + "nf3": "^0.3.11", + "ocache": "^0.1.2", + "ofetch": "^2.0.0-alpha.3", + "ohash": "^2.0.11", + "rolldown": "^1.0.0-rc.9", + "srvx": "^0.11.9", + "unenv": "^2.0.0-rc.24", + "unstorage": "^2.0.0-alpha.6" + }, + "devDependencies": { + "@azure/functions": "^3.5.1", + "@azure/static-web-apps-cli": "^2.0.8", + "@cloudflare/workers-types": "^4.20260313.1", + "@deno/types": "^0.0.1", + "@hiogawa/vite-plugin-fullstack": "^0.0.11", + "@netlify/edge-functions": "^3.0.4", + "@netlify/functions": "^5.1.3", + "@rollup/plugin-alias": "^6.0.0", + "@rollup/plugin-commonjs": "^29.0.2", "@rollup/plugin-inject": "^5.0.5", "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^16.0.0", - "@rollup/plugin-replace": "^6.0.2", - "@rollup/plugin-terser": "^0.4.4", - "@types/http-proxy": "^1.17.16", - "@vercel/nft": "^0.29.2", - "archiver": "^7.0.1", - "c12": "^3.0.2", - "chokidar": "^4.0.3", - "citty": "^0.1.6", - "compatx": "^0.1.8", - "confbox": "^0.2.1", - "consola": "^3.4.0", + "@rollup/plugin-node-resolve": "^16.0.3", + "@rollup/plugin-replace": "^6.0.3", + "@scalar/api-reference": "^1.48.7", + "@types/aws-lambda": "^8.10.161", + "@types/estree": "^1.0.8", + "@types/etag": "^1.8.4", + "@types/http-proxy": "^1.17.17", + "@types/node": "^25.5.0", + "@types/node-fetch": "^2.6.13", + "@types/semver": "^7.7.1", + "@types/xml2js": "^0.4.14", + "@typescript/native-preview": "latest", + "@vitest/coverage-v8": "^4.1.0", + "automd": "^0.4.3", + "c12": "^4.0.0-beta.3", + "changelogen": "^0.6.2", + "chokidar": "^5.0.0", + "citty": "^0.2.1", + "compatx": "^0.2.0", + "confbox": "^0.2.4", "cookie-es": "^2.0.0", - "croner": "^9.0.0", - "crossws": "^0.3.4", - "db0": "^0.3.1", + "croner": "^10.0.1", "defu": "^6.1.4", - "destr": "^2.0.3", - "dot-prop": "^9.0.0", - "esbuild": "^0.25.0", + "destr": "^2.0.5", + "dot-prop": "^10.1.0", + "edge-runtime": "^4.0.1", "escape-string-regexp": "^5.0.0", "etag": "^1.8.1", - "exsolve": "^1.0.4", - "fs-extra": "^11.3.0", - "globby": "^14.1.0", + "execa": "^9.6.1", + "expect-type": "^1.3.0", + "exsolve": "^1.0.8", + "get-port-please": "^3.2.0", + "giget": "^3.1.2", "gzip-size": "^7.0.0", - "h3": "^1.15.1", - "hookable": "^5.5.3", - "httpxy": "^0.1.7", - "ioredis": "^5.6.0", - "jiti": "^2.4.2", + "httpxy": "^0.3.1", "klona": "^2.0.6", - "knitwork": "^1.2.0", - "listhen": "^1.9.0", - "magic-string": "^0.30.17", - "magicast": "^0.3.5", - "mime": "^4.0.6", - "mlly": "^1.7.4", - "node-fetch-native": "^1.6.6", - "node-mock-http": "^1.0.0", - "ofetch": "^1.4.1", - "ohash": "^2.0.11", - "openapi-typescript": "^7.6.1", + "knitwork": "^1.3.0", + "magic-string": "^0.30.21", + "mdzilla": "^0.0.6", + "mime": "^4.1.0", + "miniflare": "^4.20260312.0", + "mlly": "^1.8.1", + "nypm": "^0.6.5", + "obuild": "^0.4.32", + "oxfmt": "^0.40.0", + "oxlint": "^1.55.0", "pathe": "^2.0.3", - "perfect-debounce": "^1.0.0", - "pkg-types": "^2.1.0", - "pretty-bytes": "^6.1.1", - "radix3": "^1.1.2", - "rollup": "^4.35.0", - "rollup-plugin-visualizer": "^5.14.0", + "perfect-debounce": "^2.1.0", + "pkg-types": "^2.3.0", + "pretty-bytes": "^7.1.0", + "react": "^19.2.4", + "rendu": "^0.0.7", + "rollup": "^4.59.0", + "rou3": "^0.8.1", "scule": "^1.3.0", - "semver": "^7.7.1", + "semver": "^7.7.4", "serve-placeholder": "^2.0.2", - "serve-static": "^1.16.2", - "source-map": "^0.7.4", - "std-env": "^3.8.1", - "ufo": "^1.5.4", - "ultrahtml": "^1.5.3", + "source-map": "^0.7.6", + "std-env": "^4.0.0", + "tinyglobby": "^0.2.15", + "tsconfck": "^3.1.6", + "typescript": "^5.9.3", + "ufo": "^1.6.3", + "ultrahtml": "^1.6.0", "uncrypto": "^0.1.3", - "unctx": "^2.4.1", - "unenv": "^2.0.0-rc.14", - "unimport": "^4.1.2", - "unplugin-utils": "^0.2.4", - "unstorage": "^1.15.0", + "unctx": "^2.5.0", + "unimport": "^6.0.1", "untyped": "^2.0.0", - "unwasm": "^0.3.9", - "youch": "^4.1.0-beta.6", - "youch-core": "^0.3.2" - }, - "devDependencies": { - "@azure/functions": "^3.5.1", - "@azure/static-web-apps-cli": "^2.0.4", - "@cloudflare/workers-types": "^4.20250303.0", - "@deno/types": "^0.0.1", - "@netlify/edge-functions": "^2.11.1", - "@scalar/api-reference": "^1.25.130", - "@types/archiver": "^6.0.3", - "@types/aws-lambda": "^8.10.147", - "@types/estree": "^1.0.6", - "@types/etag": "^1.8.3", - "@types/fs-extra": "^11.0.4", - "@types/node-fetch": "^2.6.12", - "@types/semver": "^7.5.8", - "@types/serve-static": "^1.15.7", - "@types/xml2js": "^0.4.14", - "@vitest/coverage-v8": "^3.0.8", - "automd": "^0.4.0", - "changelogen": "^0.6.1", - "edge-runtime": "^4.0.1", - "eslint": "^9.22.0", - "eslint-config-unjs": "^0.4.2", - "execa": "^9.5.2", - "expect-type": "^1.2.0", - "firebase-admin": "^12.7.0", - "firebase-functions": "^4.9.0", - "get-port-please": "^3.1.2", - "miniflare": "^3.20250224.0", - "ohash-v1": "npm:ohash@^1.1.6", - "prettier": "^3.5.3", - "typescript": "^5.8.2", - "unbuild": "^3.5.0", - "undici": "^7.4.0", - "vitest": "^3.0.8", - "xml2js": "^0.6.2" + "unwasm": "^0.5.3", + "vite": "^8.0.0", + "vite7": "npm:vite@^7.3.1", + "vitest": "^4.1.0", + "wrangler": "^4.73.0", + "xml2js": "^0.6.2", + "youch": "^4.1.0", + "youch-core": "^0.3.3", + "zephyr-agent": "^0.1.15" }, "peerDependencies": { - "xml2js": "^0.6.2" + "dotenv": "*", + "giget": "*", + "jiti": "^2.6.1", + "rollup": "^4.59.0", + "vite": "^7 || ^8 || >=8.0.0-0", + "xml2js": "^0.6.2", + "zephyr-agent": "^0.1.15" }, "peerDependenciesMeta": { + "dotenv": { + "optional": true + }, + "rollup": { + "optional": true + }, + "vite": { + "optional": true + }, "xml2js": { "optional": true + }, + "giget": { + "optional": true + }, + "jiti": { + "optional": true + }, + "zephyr-agent": { + "optional": true } }, - "packageManager": "pnpm@10.3.0", + "resolutions": { + "nitro": "link:.", + "rolldown": "^1.0.0-rc.8", + "vite": "^8.0.0-beta.18" + }, "engines": { - "node": "^16.11.0 || >=17.0.0" + "node": "^20.19.0 || >=22.12.0" }, - "pnpm": { - "peerDependencyRules": { - "ignoreMissing": [ - "react", - "@types/react", - "react-dom", - "@algolia/client-search" - ] + "packageManager": "pnpm@10.32.0", + "compatiblePackages": { + "schemaVersion": 1, + "vite": { + "type": "compatible", + "versions": "^7 || ^8 || >=8.0.0-0" + }, + "rollup": { + "type": "compatible", + "versions": "^4" }, - "onlyBuiltDependencies": [ - "@parcel/watcher", - "esbuild", - "workerd" - ], - "ignoredBuiltDependencies": [ - "keytar", - "protobufjs", - "vue-demi" - ] + "rolldown": { + "type": "compatible", + "versions": ">=1.0.0-beta.0" + } } } diff --git a/playground/nitro.config.ts b/playground/nitro.config.ts index 5787a5ed6c..4d63605a93 100644 --- a/playground/nitro.config.ts +++ b/playground/nitro.config.ts @@ -1,5 +1,5 @@ -import { defineNitroConfig } from "nitropack/config"; +import { defineConfig } from "nitro"; -export default defineNitroConfig({ - compatibilityDate: "2025-03-01", +export default defineConfig({ + serverDir: "./server", }); diff --git a/playground/package.json b/playground/package.json new file mode 100644 index 0000000000..5a90ed39fa --- /dev/null +++ b/playground/package.json @@ -0,0 +1,14 @@ +{ + "name": "nitro-playground", + "version": "1.0.0", + "type": "module", + "scripts": { + "build": "vite build", + "dev": "vite dev", + "preview": "vite preview" + }, + "devDependencies": { + "nitro": "latest", + "vite": "beta" + } +} diff --git a/playground/public/test.txt b/playground/public/test.txt deleted file mode 100644 index ddb75e75d6..0000000000 --- a/playground/public/test.txt +++ /dev/null @@ -1 +0,0 @@ -Test works! diff --git a/playground/routes/index.ts b/playground/routes/index.ts deleted file mode 100644 index fecf90a83a..0000000000 --- a/playground/routes/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default eventHandler(async (event) => { - return {}; -}); diff --git a/playground/server.ts b/playground/server.ts new file mode 100644 index 0000000000..7d810949a2 --- /dev/null +++ b/playground/server.ts @@ -0,0 +1,5 @@ +export default { + fetch(req: Request) { + return new Response("Hello from Nitro playground!"); + }, +}; diff --git a/playground/tsconfig.json b/playground/tsconfig.json index 43008af1c7..4b886bd47e 100644 --- a/playground/tsconfig.json +++ b/playground/tsconfig.json @@ -1,3 +1,3 @@ { - "extends": "./.nitro/types/tsconfig.json" + "extends": "nitro/tsconfig" } diff --git a/playground/vite.config.ts b/playground/vite.config.ts new file mode 100644 index 0000000000..dc884054e6 --- /dev/null +++ b/playground/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ + plugins: [nitro()], +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d4c8bb22dd..6d2884281d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,418 +5,779 @@ settings: excludeLinksFromLockfile: false overrides: - nitropack: link:. + nitro: link:. + rolldown: ^1.0.0-rc.8 + vite: ^8.0.0-beta.18 importers: .: dependencies: - '@cloudflare/kv-asset-handler': + consola: + specifier: ^3.4.2 + version: 3.4.2 + crossws: + specifier: ^0.4.4 + version: 0.4.4(srvx@0.11.9) + db0: specifier: ^0.3.4 version: 0.3.4 + dotenv: + specifier: '*' + version: 17.3.1 + env-runner: + specifier: ^0.1.6 + version: 0.1.6(miniflare@4.20260312.0) + h3: + specifier: ^2.0.1-rc.16 + version: 2.0.1-rc.16(crossws@0.4.4(srvx@0.11.9)) + hookable: + specifier: ^6.0.1 + version: 6.0.1 + jiti: + specifier: ^2.6.1 + version: 2.6.1 + nf3: + specifier: ^0.3.11 + version: 0.3.11 + ocache: + specifier: ^0.1.2 + version: 0.1.2 + ofetch: + specifier: ^2.0.0-alpha.3 + version: 2.0.0-alpha.3 + ohash: + specifier: ^2.0.11 + version: 2.0.11 + rolldown: + specifier: ^1.0.0-rc.8 + version: 1.0.0-rc.9 + srvx: + specifier: ^0.11.9 + version: 0.11.9 + unenv: + specifier: ^2.0.0-rc.24 + version: 2.0.0-rc.24 + unstorage: + specifier: ^2.0.0-alpha.6 + version: 2.0.0-alpha.6(@azure/identity@4.13.0)(chokidar@5.0.0)(db0@0.3.4)(ofetch@2.0.0-alpha.3) + devDependencies: + '@azure/functions': + specifier: ^3.5.1 + version: 3.5.1 + '@azure/static-web-apps-cli': + specifier: ^2.0.8 + version: 2.0.8 + '@cloudflare/workers-types': + specifier: ^4.20260313.1 + version: 4.20260313.1 + '@deno/types': + specifier: ^0.0.1 + version: 0.0.1 + '@hiogawa/vite-plugin-fullstack': + specifier: ^0.0.11 + version: 0.0.11(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) + '@netlify/edge-functions': + specifier: ^3.0.4 + version: 3.0.4 '@netlify/functions': - specifier: 3.0.0 - version: 3.0.0 + specifier: ^5.1.3 + version: 5.1.3 '@rollup/plugin-alias': - specifier: ^5.1.1 - version: 5.1.1(rollup@4.35.0) + specifier: ^6.0.0 + version: 6.0.0(rollup@4.59.0) '@rollup/plugin-commonjs': - specifier: ^28.0.3 - version: 28.0.3(rollup@4.35.0) + specifier: ^29.0.2 + version: 29.0.2(rollup@4.59.0) '@rollup/plugin-inject': specifier: ^5.0.5 - version: 5.0.5(rollup@4.35.0) + version: 5.0.5(rollup@4.59.0) '@rollup/plugin-json': specifier: ^6.1.0 - version: 6.1.0(rollup@4.35.0) + version: 6.1.0(rollup@4.59.0) '@rollup/plugin-node-resolve': - specifier: ^16.0.0 - version: 16.0.0(rollup@4.35.0) + specifier: ^16.0.3 + version: 16.0.3(rollup@4.59.0) '@rollup/plugin-replace': - specifier: ^6.0.2 - version: 6.0.2(rollup@4.35.0) - '@rollup/plugin-terser': - specifier: ^0.4.4 - version: 0.4.4(rollup@4.35.0) + specifier: ^6.0.3 + version: 6.0.3(rollup@4.59.0) + '@scalar/api-reference': + specifier: ^1.48.7 + version: 1.48.7(axios@1.13.6(debug@4.4.3))(jwt-decode@4.0.0)(tailwindcss@4.2.1)(typescript@5.9.3) + '@types/aws-lambda': + specifier: ^8.10.161 + version: 8.10.161 + '@types/estree': + specifier: ^1.0.8 + version: 1.0.8 + '@types/etag': + specifier: ^1.8.4 + version: 1.8.4 '@types/http-proxy': - specifier: ^1.17.16 - version: 1.17.16 - '@vercel/nft': - specifier: ^0.29.2 - version: 0.29.2(rollup@4.35.0) - archiver: - specifier: ^7.0.1 - version: 7.0.1 + specifier: ^1.17.17 + version: 1.17.17 + '@types/node': + specifier: ^25.5.0 + version: 25.5.0 + '@types/node-fetch': + specifier: ^2.6.13 + version: 2.6.13 + '@types/semver': + specifier: ^7.7.1 + version: 7.7.1 + '@types/xml2js': + specifier: ^0.4.14 + version: 0.4.14 + '@typescript/native-preview': + specifier: latest + version: 7.0.0-dev.20260314.1 + '@vitest/coverage-v8': + specifier: ^4.1.0 + version: 4.1.0(vitest@4.1.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@25.5.0)(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))) + automd: + specifier: ^0.4.3 + version: 0.4.3(magicast@0.5.2) c12: - specifier: ^3.0.2 - version: 3.0.2(magicast@0.3.5) + specifier: ^4.0.0-beta.3 + version: 4.0.0-beta.3(chokidar@5.0.0)(dotenv@17.3.1)(giget@3.1.2)(jiti@2.6.1)(magicast@0.5.2) + changelogen: + specifier: ^0.6.2 + version: 0.6.2(magicast@0.5.2) chokidar: - specifier: ^4.0.3 - version: 4.0.3 + specifier: ^5.0.0 + version: 5.0.0 citty: - specifier: ^0.1.6 - version: 0.1.6 - compatx: - specifier: ^0.1.8 - version: 0.1.8 - confbox: specifier: ^0.2.1 version: 0.2.1 - consola: - specifier: ^3.4.0 - version: 3.4.0 + compatx: + specifier: ^0.2.0 + version: 0.2.0 + confbox: + specifier: ^0.2.4 + version: 0.2.4 cookie-es: specifier: ^2.0.0 version: 2.0.0 croner: - specifier: ^9.0.0 - version: 9.0.0 - crossws: - specifier: ^0.3.4 - version: 0.3.4 - db0: - specifier: ^0.3.1 - version: 0.3.1 + specifier: ^10.0.1 + version: 10.0.1 defu: specifier: ^6.1.4 version: 6.1.4 destr: - specifier: ^2.0.3 - version: 2.0.3 + specifier: ^2.0.5 + version: 2.0.5 dot-prop: - specifier: ^9.0.0 - version: 9.0.0 - esbuild: - specifier: ^0.25.0 - version: 0.25.0 + specifier: ^10.1.0 + version: 10.1.0 + edge-runtime: + specifier: ^4.0.1 + version: 4.0.1 escape-string-regexp: specifier: ^5.0.0 version: 5.0.0 etag: specifier: ^1.8.1 version: 1.8.1 + execa: + specifier: ^9.6.1 + version: 9.6.1 + expect-type: + specifier: ^1.3.0 + version: 1.3.0 exsolve: - specifier: ^1.0.4 - version: 1.0.4 - fs-extra: - specifier: ^11.3.0 - version: 11.3.0 - globby: - specifier: ^14.1.0 - version: 14.1.0 + specifier: ^1.0.8 + version: 1.0.8 + get-port-please: + specifier: ^3.2.0 + version: 3.2.0 + giget: + specifier: ^3.1.2 + version: 3.1.2 gzip-size: specifier: ^7.0.0 version: 7.0.0 - h3: - specifier: ^1.15.1 - version: 1.15.1 - hookable: - specifier: ^5.5.3 - version: 5.5.3 httpxy: - specifier: ^0.1.7 - version: 0.1.7 - ioredis: - specifier: ^5.6.0 - version: 5.6.0 - jiti: - specifier: ^2.4.2 - version: 2.4.2 + specifier: ^0.3.1 + version: 0.3.1 klona: specifier: ^2.0.6 version: 2.0.6 knitwork: - specifier: ^1.2.0 - version: 1.2.0 - listhen: - specifier: ^1.9.0 - version: 1.9.0 + specifier: ^1.3.0 + version: 1.3.0 magic-string: - specifier: ^0.30.17 - version: 0.30.17 - magicast: - specifier: ^0.3.5 - version: 0.3.5 + specifier: ^0.30.21 + version: 0.30.21 + mdzilla: + specifier: ^0.0.6 + version: 0.0.6 mime: - specifier: ^4.0.6 - version: 4.0.6 + specifier: ^4.1.0 + version: 4.1.0 + miniflare: + specifier: ^4.20260312.0 + version: 4.20260312.0 mlly: - specifier: ^1.7.4 - version: 1.7.4 - node-fetch-native: - specifier: ^1.6.6 - version: 1.6.6 - node-mock-http: - specifier: ^1.0.0 - version: 1.0.0 - ofetch: - specifier: ^1.4.1 - version: 1.4.1 - ohash: - specifier: ^2.0.11 - version: 2.0.11 - openapi-typescript: - specifier: ^7.6.1 - version: 7.6.1(typescript@5.8.2) + specifier: ^1.8.1 + version: 1.8.1 + nypm: + specifier: ^0.6.5 + version: 0.6.5 + obuild: + specifier: ^0.4.32 + version: 0.4.32(@typescript/native-preview@7.0.0-dev.20260314.1)(chokidar@5.0.0)(dotenv@17.3.1)(giget@3.1.2)(jiti@2.6.1)(magicast@0.5.2)(picomatch@4.0.3)(rollup@4.59.0)(typescript@5.9.3) + oxfmt: + specifier: ^0.40.0 + version: 0.40.0 + oxlint: + specifier: ^1.55.0 + version: 1.55.0 pathe: specifier: ^2.0.3 version: 2.0.3 perfect-debounce: - specifier: ^1.0.0 - version: 1.0.0 - pkg-types: specifier: ^2.1.0 version: 2.1.0 + pkg-types: + specifier: ^2.3.0 + version: 2.3.0 pretty-bytes: - specifier: ^6.1.1 - version: 6.1.1 - radix3: - specifier: ^1.1.2 - version: 1.1.2 + specifier: ^7.1.0 + version: 7.1.0 + react: + specifier: ^19.2.4 + version: 19.2.4 + rendu: + specifier: ^0.0.7 + version: 0.0.7 rollup: - specifier: ^4.35.0 - version: 4.35.0 - rollup-plugin-visualizer: - specifier: ^5.14.0 - version: 5.14.0(rollup@4.35.0) + specifier: ^4.59.0 + version: 4.59.0 + rou3: + specifier: ^0.8.1 + version: 0.8.1 scule: specifier: ^1.3.0 version: 1.3.0 semver: - specifier: ^7.7.1 - version: 7.7.1 + specifier: ^7.7.4 + version: 7.7.4 serve-placeholder: specifier: ^2.0.2 version: 2.0.2 - serve-static: - specifier: ^1.16.2 - version: 1.16.2 source-map: - specifier: ^0.7.4 - version: 0.7.4 + specifier: ^0.7.6 + version: 0.7.6 std-env: - specifier: ^3.8.1 - version: 3.8.1 + specifier: ^4.0.0 + version: 4.0.0 + tinyglobby: + specifier: ^0.2.15 + version: 0.2.15 + tsconfck: + specifier: ^3.1.6 + version: 3.1.6(typescript@5.9.3) + typescript: + specifier: ^5.9.3 + version: 5.9.3 ufo: - specifier: ^1.5.4 - version: 1.5.4 + specifier: ^1.6.3 + version: 1.6.3 ultrahtml: - specifier: ^1.5.3 - version: 1.5.3 + specifier: ^1.6.0 + version: 1.6.0 uncrypto: specifier: ^0.1.3 version: 0.1.3 unctx: - specifier: ^2.4.1 - version: 2.4.1 - unenv: - specifier: ^2.0.0-rc.14 - version: 2.0.0-rc.14 + specifier: ^2.5.0 + version: 2.5.0 unimport: - specifier: ^4.1.2 - version: 4.1.2 - unplugin-utils: - specifier: ^0.2.4 - version: 0.2.4 - unstorage: - specifier: ^1.15.0 - version: 1.15.0(@azure/identity@4.7.0)(db0@0.3.1)(ioredis@5.6.0) + specifier: ^6.0.1 + version: 6.0.1 untyped: specifier: ^2.0.0 version: 2.0.0 unwasm: - specifier: ^0.3.9 - version: 0.3.9 - youch: - specifier: ^4.1.0-beta.6 - version: 4.1.0-beta.6 - youch-core: - specifier: ^0.3.2 - version: 0.3.2 - devDependencies: - '@azure/functions': - specifier: ^3.5.1 - version: 3.5.1 - '@azure/static-web-apps-cli': - specifier: ^2.0.4 - version: 2.0.4 - '@cloudflare/workers-types': - specifier: ^4.20250303.0 - version: 4.20250303.0 - '@deno/types': - specifier: ^0.0.1 - version: 0.0.1 - '@netlify/edge-functions': - specifier: ^2.11.1 - version: 2.11.1 - '@scalar/api-reference': - specifier: ^1.25.130 - version: 1.25.130(@hyperjump/browser@1.2.0)(axios@1.8.2)(change-case@5.4.4)(jwt-decode@4.0.0)(tailwindcss@4.0.12)(typescript@5.8.2) - '@types/archiver': - specifier: ^6.0.3 - version: 6.0.3 - '@types/aws-lambda': - specifier: ^8.10.147 - version: 8.10.147 - '@types/estree': - specifier: ^1.0.6 - version: 1.0.6 - '@types/etag': - specifier: ^1.8.3 - version: 1.8.3 - '@types/fs-extra': - specifier: ^11.0.4 - version: 11.0.4 - '@types/node-fetch': - specifier: ^2.6.12 - version: 2.6.12 - '@types/semver': - specifier: ^7.5.8 - version: 7.5.8 - '@types/serve-static': - specifier: ^1.15.7 - version: 1.15.7 - '@types/xml2js': - specifier: ^0.4.14 - version: 0.4.14 - '@vitest/coverage-v8': - specifier: ^3.0.8 - version: 3.0.8(vitest@3.0.8(@edge-runtime/vm@5.0.0)(@types/debug@4.1.12)(@types/node@22.13.10)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.0)) - automd: - specifier: ^0.4.0 - version: 0.4.0(magicast@0.3.5) - changelogen: - specifier: ^0.6.1 - version: 0.6.1(magicast@0.3.5) - edge-runtime: - specifier: ^4.0.1 - version: 4.0.1 - eslint: - specifier: ^9.22.0 - version: 9.22.0(jiti@2.4.2) - eslint-config-unjs: - specifier: ^0.4.2 - version: 0.4.2(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) - execa: - specifier: ^9.5.2 - version: 9.5.2 - expect-type: - specifier: ^1.2.0 - version: 1.2.0 - firebase-admin: - specifier: ^12.7.0 - version: 12.7.0 - firebase-functions: - specifier: ^4.9.0 - version: 4.9.0(firebase-admin@12.7.0) - get-port-please: - specifier: ^3.1.2 - version: 3.1.2 - miniflare: - specifier: ^3.20250224.0 - version: 3.20250224.0 - ohash-v1: - specifier: npm:ohash@^1.1.6 - version: ohash@1.1.6 - prettier: - specifier: ^3.5.3 - version: 3.5.3 - typescript: - specifier: ^5.8.2 - version: 5.8.2 - unbuild: - specifier: ^3.5.0 - version: 3.5.0(typescript@5.8.2)(vue@3.5.13(typescript@5.8.2)) - undici: - specifier: ^7.4.0 - version: 7.4.0 + specifier: ^0.5.3 + version: 0.5.3 + vite: + specifier: ^8.0.0-beta.18 + version: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + vite7: + specifier: npm:vite@^7.3.1 + version: vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.2) vitest: - specifier: ^3.0.8 - version: 3.0.8(@edge-runtime/vm@5.0.0)(@types/debug@4.1.12)(@types/node@22.13.10)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.0) + specifier: ^4.1.0 + version: 4.1.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@25.5.0)(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) + wrangler: + specifier: ^4.73.0 + version: 4.73.0(@cloudflare/workers-types@4.20260313.1) xml2js: specifier: ^0.6.2 version: 0.6.2 + youch: + specifier: ^4.1.0 + version: 4.1.0 + youch-core: + specifier: ^0.3.3 + version: 0.3.3 + zephyr-agent: + specifier: ^0.1.15 + version: 0.1.15(https-proxy-agent@7.0.6) examples/api-routes: devDependencies: - nitropack: + nitro: specifier: link:../.. version: link:../.. examples/auto-imports: devDependencies: - nitropack: + nitro: specifier: link:../.. version: link:../.. examples/cached-handler: devDependencies: - nitropack: + nitro: specifier: link:../.. version: link:../.. examples/custom-error-handler: devDependencies: - nitropack: + nitro: specifier: link:../.. version: link:../.. examples/database: devDependencies: - nitropack: + nitro: specifier: link:../.. version: link:../.. - examples/graceful-shutdown: + examples/elysia: devDependencies: - nitropack: + elysia: + specifier: ^1.4.22 + version: 1.4.27(@sinclair/typebox@0.34.48)(exact-mirror@0.2.7(@sinclair/typebox@0.34.48))(file-type@21.3.2)(openapi-types@12.1.3)(typescript@5.9.3) + nitro: + specifier: link:../.. + version: link:../.. + + examples/express: + devDependencies: + '@types/express': + specifier: ^5.0.6 + version: 5.0.6 + express: + specifier: ^5.2.1 + version: 5.2.1 + nitro: + specifier: link:../.. + version: link:../.. + + examples/fastify: + devDependencies: + fastify: + specifier: ^5.7.4 + version: 5.8.2 + nitro: specifier: link:../.. version: link:../.. examples/hello-world: devDependencies: - nitropack: + nitro: + specifier: link:../.. + version: link:../.. + + examples/hono: + devDependencies: + hono: + specifier: ^4.11.8 + version: 4.12.8 + nitro: + specifier: link:../.. + version: link:../.. + + examples/import-alias: + devDependencies: + nitro: specifier: link:../.. version: link:../.. examples/middleware: devDependencies: - nitropack: + nitro: + specifier: link:../.. + version: link:../.. + + examples/mono-jsx: + devDependencies: + mono-jsx: + specifier: latest + version: 0.9.10 + nitro: specifier: link:../.. version: link:../.. examples/nano-jsx: devDependencies: nano-jsx: - specifier: ^0.0.37 - version: 0.0.37 - nitropack: + specifier: ^0.2.1 + version: 0.2.1 + nitro: specifier: link:../.. version: link:../.. examples/plugins: devDependencies: - nitropack: + nitro: specifier: link:../.. version: link:../.. examples/renderer: devDependencies: - nitropack: + nitro: + specifier: link:../.. + version: link:../.. + + examples/runtime-config: + devDependencies: + nitro: + specifier: link:../.. + version: link:../.. + + examples/server-fetch: + devDependencies: + nitro: + specifier: link:../.. + version: link:../.. + + examples/shiki: + devDependencies: + nitro: + specifier: link:../.. + version: link:../.. + shiki: + specifier: ^3.22.0 + version: 3.23.0 + + examples/virtual-routes: + devDependencies: + nitro: + specifier: link:../.. + version: link:../.. + + examples/vite-nitro-plugin: + devDependencies: + nitro: + specifier: link:../.. + version: link:../.. + vite: + specifier: ^8.0.0-beta.18 + version: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + + examples/vite-rsc: + dependencies: + react: + specifier: ^19.2.4 + version: 19.2.4 + react-dom: + specifier: ^19.2.4 + version: 19.2.4(react@19.2.4) + devDependencies: + '@types/react': + specifier: ^19.2.13 + version: 19.2.14 + '@types/react-dom': + specifier: ^19.2.3 + version: 19.2.3(@types/react@19.2.14) + '@vitejs/plugin-react': + specifier: ^5.1.3 + version: 5.2.0(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) + '@vitejs/plugin-rsc': + specifier: ^0.5.19 + version: 0.5.21(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) + nitro: + specifier: link:../.. + version: link:../.. + rsc-html-stream: + specifier: ^0.0.7 + version: 0.0.7 + vite: + specifier: ^8.0.0-beta.18 + version: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + + examples/vite-ssr-html: + devDependencies: + '@tailwindcss/vite': + specifier: ^4.1.18 + version: 4.2.1(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) + nitro: + specifier: link:../.. + version: link:../.. + tailwindcss: + specifier: ^4.1.18 + version: 4.2.1 + vite: + specifier: ^8.0.0-beta.18 + version: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + + examples/vite-ssr-preact: + devDependencies: + '@preact/preset-vite': + specifier: ^2.10.3 + version: 2.10.3(@babel/core@7.29.0)(preact@10.29.0)(rollup@4.59.0)(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) + '@tailwindcss/vite': + specifier: ^4.1.18 + version: 4.2.1(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) + nitro: + specifier: link:../.. + version: link:../.. + preact: + specifier: ^10.28.3 + version: 10.29.0 + preact-render-to-string: + specifier: ^6.6.5 + version: 6.6.6(preact@10.29.0) + tailwindcss: + specifier: ^4.1.18 + version: 4.2.1 + vite: + specifier: ^8.0.0-beta.18 + version: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + + examples/vite-ssr-react: + devDependencies: + '@types/react': + specifier: ^19.2.13 + version: 19.2.14 + '@types/react-dom': + specifier: ^19.2.3 + version: 19.2.3(@types/react@19.2.14) + '@vitejs/plugin-react': + specifier: ^5.1.3 + version: 5.2.0(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) + nitro: + specifier: link:../.. + version: link:../.. + react: + specifier: ^19.2.4 + version: 19.2.4 + react-dom: + specifier: ^19.2.4 + version: 19.2.4(react@19.2.4) + react-refresh: + specifier: ^0.18.0 + version: 0.18.0 + vite: + specifier: ^8.0.0-beta.18 + version: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + + examples/vite-ssr-solid: + devDependencies: + nitro: + specifier: link:../.. + version: link:../.. + solid-js: + specifier: ^1.9.11 + version: 1.9.11 + vite: + specifier: ^8.0.0-beta.18 + version: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + vite-plugin-solid: + specifier: ^2.11.10 + version: 2.11.11(solid-js@1.9.11)(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) + + examples/vite-ssr-tsr-react: + devDependencies: + '@tanstack/react-router': + specifier: ^1.158.1 + version: 1.167.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-router-devtools': + specifier: ^1.158.1 + version: 1.166.7(@tanstack/react-router@1.167.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.167.0)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-plugin': + specifier: ^1.158.1 + version: 1.166.9(@tanstack/react-router@1.167.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite-plugin-solid@2.11.11(solid-js@1.9.11)(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) + '@types/react': + specifier: ^19.2.13 + version: 19.2.14 + '@types/react-dom': + specifier: ^19.2.3 + version: 19.2.3(@types/react@19.2.14) + '@vitejs/plugin-react': + specifier: ^5.1.3 + version: 5.2.0(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) + nitro: + specifier: link:../.. + version: link:../.. + react: + specifier: ^19.2.4 + version: 19.2.4 + react-dom: + specifier: ^19.2.4 + version: 19.2.4(react@19.2.4) + vite: + specifier: ^8.0.0-beta.18 + version: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + + examples/vite-ssr-tss-react: + dependencies: + '@tanstack/react-router': + specifier: ^1.158.1 + version: 1.167.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-router-devtools': + specifier: ^1.158.1 + version: 1.166.7(@tanstack/react-router@1.167.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.167.0)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-start': + specifier: ^1.158.3 + version: 1.166.11(crossws@0.4.4(srvx@0.11.9))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite-plugin-solid@2.11.11(solid-js@1.9.11)(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) + nitro: + specifier: link:../.. + version: link:../.. + react: + specifier: ^19.2.4 + version: 19.2.4 + react-dom: + specifier: ^19.2.4 + version: 19.2.4(react@19.2.4) + tailwind-merge: + specifier: ^3.4.0 + version: 3.5.0 + zod: + specifier: ^4.3.6 + version: 4.3.6 + devDependencies: + '@tailwindcss/vite': + specifier: ^4.1.18 + version: 4.2.1(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) + '@types/node': + specifier: latest + version: 25.5.0 + '@types/react': + specifier: ^19.2.13 + version: 19.2.14 + '@types/react-dom': + specifier: ^19.2.3 + version: 19.2.3(@types/react@19.2.14) + '@vitejs/plugin-react': + specifier: ^5.1.3 + version: 5.2.0(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) + tailwindcss: + specifier: ^4.1.18 + version: 4.2.1 + typescript: + specifier: ^5.9.3 + version: 5.9.3 + vite: + specifier: ^8.0.0-beta.18 + version: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + vite-tsconfig-paths: + specifier: ^6.0.5 + version: 6.1.1(typescript@5.9.3)(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) + + examples/vite-ssr-vue-router: + devDependencies: + '@vitejs/plugin-vue': + specifier: ^6.0.4 + version: 6.0.5(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.30(typescript@5.9.3)) + nitro: + specifier: link:../.. + version: link:../.. + unhead: + specifier: ^2.1.3 + version: 2.1.12 + vite: + specifier: ^8.0.0-beta.18 + version: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + vite-plugin-devtools-json: + specifier: ^1.0.0 + version: 1.0.0(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) + vue: + specifier: ^3.5.27 + version: 3.5.30(typescript@5.9.3) + vue-router: + specifier: ^4.6.4 + version: 4.6.4(vue@3.5.30(typescript@5.9.3)) + + examples/vite-trpc: + devDependencies: + '@trpc/client': + specifier: ^11.9.0 + version: 11.12.0(@trpc/server@11.12.0(typescript@5.9.3))(typescript@5.9.3) + '@trpc/server': + specifier: ^11.9.0 + version: 11.12.0(typescript@5.9.3) + nitro: specifier: link:../.. version: link:../.. + vite: + specifier: ^8.0.0-beta.18 + version: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + zod: + specifier: ^4.3.6 + version: 4.3.6 examples/websocket: devDependencies: - nitropack: + nitro: specifier: link:../.. version: link:../.. + playground: + devDependencies: + nitro: + specifier: link:.. + version: link:.. + vite: + specifier: ^8.0.0-beta.18 + version: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + + test/fixture: + devDependencies: + mono-jsx: + specifier: ^0.8.2 + version: 0.8.2 + nitro: + specifier: link:../.. + version: link:../.. + + test/minimal: + devDependencies: + nitro: + specifier: link:../.. + version: link:../.. + vite: + specifier: ^8.0.0-beta.18 + version: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + packages: - '@ampproject/remapping@2.3.0': - resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} - engines: {node: '>=6.0.0'} + '@ai-sdk/gateway@3.0.13': + resolution: {integrity: sha512-g7nE4PFtngOZNZSy1lOPpkC+FAiHxqBJXqyRMEG7NUrEVZlz5goBdtHg1YgWRJIX776JTXAmbOI5JreAKVAsVA==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/provider-utils@4.0.5': + resolution: {integrity: sha512-Ow/X/SEkeExTTc1x+nYLB9ZHK2WUId8+9TlkamAx7Tl9vxU+cKzWx2dwjgMHeCN6twrgwkLrrtqckQeO4mxgVA==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/provider@3.0.2': + resolution: {integrity: sha512-HrEmNt/BH/hkQ7zpi2o6N3k1ZR1QTb7z85WYhYygiTxOQuaml4CMtHCWRbric5WPU+RNsYI7r1EpyVQMKO1pYw==} + engines: {node: '>=18'} + + '@ai-sdk/vue@3.0.33': + resolution: {integrity: sha512-czM9Js3a7f+Eo35gjEYEeJYUoPvMg5Dfi4bOLyDBghLqn0gaVg8yTmTaSuHCg+3K/+1xPjyXd4+2XcQIohWWiQ==} + engines: {node: '>=18'} + peerDependencies: + vue: ^3.3.4 '@azure/abort-controller@1.1.0': resolution: {integrity: sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw==} @@ -434,17 +795,17 @@ packages: resolution: {integrity: sha512-wQyuhL8WQsLkW/KMdik8bLJIJCz3Z6mg/+AKm0KedgK73SKhicSqYP+ed3t+43tLlRFltcrmGKMcHLQ+Jhv/6A==} engines: {node: '>=14.0.0'} - '@azure/arm-subscriptions@5.1.0': - resolution: {integrity: sha512-6BeOF2eQWNLq22ch7xP9RxYnPjtGev54OUCGggKOWoOvmesK7jUZbIyLk8JeXDT21PEl7iyYnxw78gxJ7zBxQw==} - engines: {node: '>=14.0.0'} + '@azure/arm-subscriptions@5.1.1': + resolution: {integrity: sha512-DR/H2nfKtHNqfpuJ4L/B4irX1nX77QizulmfrxcLNZmkfinm0SdZpypXSvzaI5rHZSXfhXNUfBvMfi+jMkjWtw==} + engines: {node: '>=20.0.0'} - '@azure/core-auth@1.9.0': - resolution: {integrity: sha512-FPwHpZywuyasDSLMqJ6fhbOK3TqUdviZNF8OqRGA4W5Ewib2lEEZ+pBsYcBa88B2NGO/SEnYPGhyBqNlE8ilSw==} - engines: {node: '>=18.0.0'} + '@azure/core-auth@1.10.1': + resolution: {integrity: sha512-ykRMW8PjVAn+RS6ww5cmK9U2CyH9p4Q88YJwvUslfuMmN98w/2rdGRLPqJYObapBCdzBVeDgYWdJnFPFb7qzpg==} + engines: {node: '>=20.0.0'} - '@azure/core-client@1.9.3': - resolution: {integrity: sha512-/wGw8fJ4mdpJ1Cum7s1S+VQyXt1ihwKLzfabS1O/RDADnmzVc01dHn44qD0BvGH6KlZNzOMW95tEpKqhkCChPA==} - engines: {node: '>=18.0.0'} + '@azure/core-client@1.10.1': + resolution: {integrity: sha512-Nh5PhEOeY6PrnxNPsEHRr9eimxLwgLlpmguQaHKBinFYA/RU9+kOYVOQqOrTsCL+KSxrLLl1gD8Dk5BFW/7l/w==} + engines: {node: '>=20.0.0'} '@azure/core-lro@2.7.2': resolution: {integrity: sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw==} @@ -454,133 +815,264 @@ packages: resolution: {integrity: sha512-YKWi9YuCU04B55h25cnOYZHxXYtEvQEbKST5vqRga7hWY9ydd3FZHdeQF8pyh+acWZvppw13M/LMGx0LABUVMA==} engines: {node: '>=18.0.0'} - '@azure/core-rest-pipeline@1.19.1': - resolution: {integrity: sha512-zHeoI3NCs53lLBbWNzQycjnYKsA1CVKlnzSNuSFcUDwBp8HHVObePxrM7HaX+Ha5Ks639H7chNC9HOaIhNS03w==} - engines: {node: '>=18.0.0'} + '@azure/core-rest-pipeline@1.23.0': + resolution: {integrity: sha512-Evs1INHo+jUjwHi1T6SG6Ua/LHOQBCLuKEEE6efIpt4ZOoNonaT1kP32GoOcdNDbfqsD2445CPri3MubBy5DEQ==} + engines: {node: '>=20.0.0'} - '@azure/core-tracing@1.2.0': - resolution: {integrity: sha512-UKTiEJPkWcESPYJz3X5uKRYyOcJD+4nYph+KpfdPRnQJVrZfk0KJgdnaAWKfhsBBtAf/D58Az4AvCJEmWgIBAg==} - engines: {node: '>=18.0.0'} + '@azure/core-tracing@1.3.1': + resolution: {integrity: sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ==} + engines: {node: '>=20.0.0'} - '@azure/core-util@1.11.0': - resolution: {integrity: sha512-DxOSLua+NdpWoSqULhjDyAZTXFdP/LKkqtYuxxz1SCN289zk3OG8UOpnCQAz/tygyACBtWp/BoO72ptK7msY8g==} - engines: {node: '>=18.0.0'} + '@azure/core-util@1.13.1': + resolution: {integrity: sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A==} + engines: {node: '>=20.0.0'} '@azure/functions@3.5.1': resolution: {integrity: sha512-6UltvJiuVpvHSwLcK/Zc6NfUwlkDLOFFx97BHCJzlWNsfiWwzwmTsxJXg4kE/LemKTHxPpfoPE+kOJ8hAdiKFQ==} - '@azure/identity@4.7.0': - resolution: {integrity: sha512-6z/S2KorkbKaZ0DgZFVRdu7RCuATmMSTjKpuhj7YpjxkJ0vnJ7kTM3cpNgzFgk9OPYfZ31wrBEtC/iwAS4jQDA==} - engines: {node: '>=18.0.0'} + '@azure/identity@4.13.0': + resolution: {integrity: sha512-uWC0fssc+hs1TGGVkkghiaFkkS7NkTxfnCH+Hdg+yTehTpMcehpok4PgUKKdyCH+9ldu6FhiHRv84Ntqj1vVcw==} + engines: {node: '>=20.0.0'} - '@azure/logger@1.1.4': - resolution: {integrity: sha512-4IXXzcCdLdlXuCG+8UKEwLA1T1NHqUfanhXYHiQTn+6sfWCZXduqbtXDGceg3Ce5QxTGo7EqmbV6Bi+aqKuClQ==} - engines: {node: '>=18.0.0'} + '@azure/logger@1.3.0': + resolution: {integrity: sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==} + engines: {node: '>=20.0.0'} - '@azure/msal-browser@4.5.1': - resolution: {integrity: sha512-vcva6qA4ytVjg52Ew+RxXGKRuoDMdvNOwT+kECNC36kujYalFQe9B5SNud4WVa/Zk12KFa0bkOHFnjP8cgDv3A==} + '@azure/msal-browser@4.29.1': + resolution: {integrity: sha512-1Vrt27du1cl4QHkzLc6L4aeXqliPIDIs5l/1I4hWWMXkXccY/EznJT1+pBdoVze0azTAI8sCyq5B4cBVYG1t9w==} engines: {node: '>=0.8.0'} - '@azure/msal-common@14.16.0': - resolution: {integrity: sha512-1KOZj9IpcDSwpNiQNjt0jDYZpQvNZay7QAEi/5DLubay40iGYtLzya/jbjRPLyOTZhEKyL1MzPuw2HqBCjceYA==} + '@azure/msal-common@14.16.1': + resolution: {integrity: sha512-nyxsA6NA4SVKh5YyRpbSXiMr7oQbwark7JU9LMeg6tJYTSPyAGkdx61wPT4gyxZfxlSxMMEyAsWaubBlNyIa1w==} engines: {node: '>=0.8.0'} - '@azure/msal-common@15.2.0': - resolution: {integrity: sha512-HiYfGAKthisUYqHG1nImCf/uzcyS31wng3o+CycWLIM9chnYJ9Lk6jZ30Y6YiYYpTQ9+z/FGUpiKKekd3Arc0A==} + '@azure/msal-common@15.16.1': + resolution: {integrity: sha512-qxUG9TCl+TVSSX58onVDHDWrvT5CE0+NeeUAbkQqaESpSm79u5IePLnPWMMjCUnUR2zJd4+Bt9vioVRzLmJb2g==} engines: {node: '>=0.8.0'} - '@azure/msal-node@3.2.3': - resolution: {integrity: sha512-0eaPqBIWEAizeYiXdeHb09Iq0tvHJ17ztvNEaLdr/KcJJhJxbpkkEQf09DB+vKlFE0tzYi7j4rYLTXtES/InEQ==} + '@azure/msal-node@3.8.9': + resolution: {integrity: sha512-jZ0pw/BbdEUWGhomCaAiVDfXRI/9K56m5hTNqB/CzcbZEYhXm5qpK1cDngN1iXfwSfmUMorOUQ2FC0dyuQ9uRg==} engines: {node: '>=16'} - '@azure/static-web-apps-cli@2.0.4': - resolution: {integrity: sha512-jWt49kl2HMj+gZCjMTyZneoGaavdCLpanZPKQCAnxJ1bxOcN0c/ZpTkD+IO0wFmUkO21zkw5jVV4X7EbNEeMdg==} + '@azure/static-web-apps-cli@2.0.8': + resolution: {integrity: sha512-C3P5I+4oHZ0ns3uEdYZPZHfQu29os8nxfdWRvvgm9bTLfn3m3+eIzTKch6gIRUSGk1Mk8uKegvsQxZfJ1nic7Q==} engines: {node: '>=18.0.0', npm: '>=9.0.0'} hasBin: true - '@babel/code-frame@7.26.2': - resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.0': + resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + engines: {node: '>=6.9.0'} + + '@babel/generator@8.0.0-rc.2': + resolution: {integrity: sha512-oCQ1IKPwkzCeJzAPb7Fv8rQ9k5+1sG8mf2uoHiMInPYvkRfrDJxbTIbH51U+jstlkghus0vAi3EBvkfvEsYNLQ==} + engines: {node: ^20.19.0 || >=22.12.0} + + '@babel/helper-annotate-as-pure@7.27.3': + resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.28.6': + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@7.25.9': - resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.25.9': - resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + '@babel/helper-module-imports@7.18.6': + resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} engines: {node: '>=6.9.0'} - '@babel/parser@7.26.9': - resolution: {integrity: sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==} + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.28.6': + resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@8.0.0-rc.2': + resolution: {integrity: sha512-noLx87RwlBEMrTzncWd/FvTxoJ9+ycHNg0n8yyYydIoDsLZuxknKgWRJUqcrVkNrJ74uGyhWQzQaS3q8xfGAhQ==} + engines: {node: ^20.19.0 || >=22.12.0} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@8.0.0-rc.2': + resolution: {integrity: sha512-xExUBkuXWJjVuIbO7z6q7/BA9bgfJDEhVL0ggrggLMbg0IzCUWGT1hZGE8qUH7Il7/RD/a6cZ3AAFrrlp1LF/A==} + engines: {node: ^20.19.0 || >=22.12.0} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.28.6': + resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.0': + resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/runtime@7.26.9': - resolution: {integrity: sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==} + '@babel/parser@8.0.0-rc.2': + resolution: {integrity: sha512-29AhEtcq4x8Dp3T72qvUMZHx0OMXCj4Jy/TEReQa+KWLln524Cj1fWb3QFi0l/xSpptQBR6y9RNEXuxpFvwiUQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + '@babel/plugin-syntax-jsx@7.28.6': + resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.28.6': + resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-development@7.27.1': + resolution: {integrity: sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-self@7.27.1': + resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.27.1': + resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx@7.28.6': + resolution: {integrity: sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 - '@babel/types@7.26.9': - resolution: {integrity: sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==} + '@babel/runtime@7.28.6': + resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} engines: {node: '>=6.9.0'} + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} + + '@babel/types@8.0.0-rc.2': + resolution: {integrity: sha512-91gAaWRznDwSX4E2tZ1YjBuIfnQVOFDCQ2r0Toby0gu4XEbyF623kXLMA8d4ZbCu+fINcrudkmEcwSUHgDDkNw==} + engines: {node: ^20.19.0 || >=22.12.0} + '@bcoe/v8-coverage@1.0.2': resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} - '@cloudflare/kv-asset-handler@0.3.4': - resolution: {integrity: sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==} - engines: {node: '>=16.13'} + '@borewit/text-codec@0.2.2': + resolution: {integrity: sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==} + + '@cloudflare/kv-asset-handler@0.4.2': + resolution: {integrity: sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ==} + engines: {node: '>=18.0.0'} + + '@cloudflare/unenv-preset@2.15.0': + resolution: {integrity: sha512-EGYmJaGZKWl+X8tXxcnx4v2bOZSjQeNI5dWFeXivgX9+YCT69AkzHHwlNbVpqtEUTbew8eQurpyOpeN8fg00nw==} + peerDependencies: + unenv: 2.0.0-rc.24 + workerd: 1.20260301.1 || ~1.20260302.1 || ~1.20260303.1 || ~1.20260304.1 || >1.20260305.0 <2.0.0-0 + peerDependenciesMeta: + workerd: + optional: true - '@cloudflare/workerd-darwin-64@1.20250224.0': - resolution: {integrity: sha512-sBbaAF2vgQ9+T50ik1ihekdepStBp0w4fvNghBfXIw1iWqfNWnypcjDMmi/7JhXJt2uBxBrSlXCvE5H7Gz+kbw==} + '@cloudflare/workerd-darwin-64@1.20260312.1': + resolution: {integrity: sha512-HUAtDWaqUduS6yasV6+NgsK7qBpP1qGU49ow/Wb117IHjYp+PZPUGReDYocpB4GOMRoQlvdd4L487iFxzdARpw==} engines: {node: '>=16'} cpu: [x64] os: [darwin] - '@cloudflare/workerd-darwin-arm64@1.20250224.0': - resolution: {integrity: sha512-naetGefgjAaDbEacpwaVruJXNwxmRRL7v3ppStgEiqAlPmTpQ/Edjn2SQ284QwOw3MvaVPHrWcaTBupUpkqCyg==} + '@cloudflare/workerd-darwin-arm64@1.20260312.1': + resolution: {integrity: sha512-DOn7TPTHSxJYfi4m4NYga/j32wOTqvJf/pY4Txz5SDKWIZHSTXFyGz2K4B+thoPWLop/KZxGoyTv7db0mk/qyw==} engines: {node: '>=16'} cpu: [arm64] os: [darwin] - '@cloudflare/workerd-linux-64@1.20250224.0': - resolution: {integrity: sha512-BtUvuj91rgB06TUAkLYvedghUA8nDFiLcY3GC7MXmWhxCxGmY4PWkrKq/+uHjrhwknCcXrE4aFsM28ja8EcAGA==} + '@cloudflare/workerd-linux-64@1.20260312.1': + resolution: {integrity: sha512-TdkIh3WzPXYHuvz7phAtFEEvAxvFd30tHrm4gsgpw0R0F5b8PtoM3hfL2uY7EcBBWVYUBtkY2ahDYFfufnXw/g==} engines: {node: '>=16'} cpu: [x64] os: [linux] - '@cloudflare/workerd-linux-arm64@1.20250224.0': - resolution: {integrity: sha512-Gr4MPNi+BvwjfWF7clx0dJY2Vm4suaW5FtAQwrfqJmPtN5zb/BP16VZxxnFRMy377dP7ycoxpKfZZ6Q8RVGvbA==} + '@cloudflare/workerd-linux-arm64@1.20260312.1': + resolution: {integrity: sha512-kNauZhL569Iy94t844OMwa1zP6zKFiL3xiJ4tGLS+TFTEfZ3pZsRH6lWWOtkXkjTyCmBEOog0HSEKjIV4oAffw==} engines: {node: '>=16'} cpu: [arm64] os: [linux] - '@cloudflare/workerd-windows-64@1.20250224.0': - resolution: {integrity: sha512-x2iF1CsmYmmPEorWb1GRpAAouX5rRjmhuHMC259ojIlozR4G0LarlB9XfmeLEvtw537Ea0kJ6SOhjvUcWzxSvA==} + '@cloudflare/workerd-windows-64@1.20260312.1': + resolution: {integrity: sha512-5dBrlSK+nMsZy5bYQpj8t9iiQNvCRlkm9GGvswJa9vVU/1BNO4BhJMlqOLWT24EmFyApZ+kaBiPJMV8847NDTg==} engines: {node: '>=16'} cpu: [x64] os: [win32] - '@cloudflare/workers-types@4.20250303.0': - resolution: {integrity: sha512-O7F7nRT4bbmwHf3gkRBLfJ7R6vHIJ/oZzWdby6obOiw2yavUfp/AIwS7aO2POu5Cv8+h3TXS3oHs3kKCZLraUA==} + '@cloudflare/workers-types@4.20260313.1': + resolution: {integrity: sha512-jMEeX3RKfOSVqqXRKr/ulgglcTloeMzSH3FdzIfqJHtvc12/ELKd5Ldsg8ZHahKX/4eRxYdw3kbzb8jLXbq/jQ==} - '@codemirror/autocomplete@6.18.6': - resolution: {integrity: sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==} + '@codemirror/autocomplete@6.20.1': + resolution: {integrity: sha512-1cvg3Vz1dSSToCNlJfRA2WSI4ht3K+WplO0UMOgmUYPivCyy2oueZY6Lx7M9wThm7SDUBViRmuT+OG/i8+ON9A==} - '@codemirror/commands@6.8.0': - resolution: {integrity: sha512-q8VPEFaEP4ikSlt6ZxjB3zW72+7osfAYW9i8Zu943uqbKuz6utc1+F170hyLUCUltXORjQXRyYQNfkckzA/bPQ==} + '@codemirror/commands@6.10.3': + resolution: {integrity: sha512-JFRiqhKu+bvSkDLI+rUhJwSxQxYb759W5GBezE8Uc8mHLqC9aV/9aTC7yJSqCtB3F00pylrLCwnyS91Ap5ej4Q==} '@codemirror/lang-css@6.3.1': resolution: {integrity: sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==} - '@codemirror/lang-html@6.4.9': - resolution: {integrity: sha512-aQv37pIMSlueybId/2PVSP6NPnmurFDVmZwzc7jszd2KAF8qd4VBbvNYPXWQq90WIARjsdVkPbw29pszmHws3Q==} + '@codemirror/lang-html@6.4.11': + resolution: {integrity: sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw==} - '@codemirror/lang-javascript@6.2.3': - resolution: {integrity: sha512-8PR3vIWg7pSu7ur8A07pGiYHgy3hHj+mRYRCSG8q+mPIrl0F02rgpGv+DsQTHRTc30rydOsf5PZ7yjKFg2Ackw==} + '@codemirror/lang-javascript@6.2.5': + resolution: {integrity: sha512-zD4e5mS+50htS7F+TYjBPsiIFGanfVqg4HyUz6WNFikgOPf2BgKlx+TQedI1w6n/IqRBVBbBWmGFdLB/7uxO4A==} - '@codemirror/lang-json@6.0.1': - resolution: {integrity: sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==} + '@codemirror/lang-json@6.0.2': + resolution: {integrity: sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==} '@codemirror/lang-xml@6.1.0': resolution: {integrity: sha512-3z0blhicHLfwi2UgkZYRPioSgVTo9PV5GP5ducFH6FaHy0IAJRg+ixj5gTR1gnT/glAIC8xv4w2VL1LoZfs+Jg==} @@ -588,20 +1080,17 @@ packages: '@codemirror/lang-yaml@6.1.2': resolution: {integrity: sha512-dxrfG8w5Ce/QbT7YID7mWZFKhdhsaTNOYjOkSIMt1qmC4VQnXSDSYVHHHn8k6kJUfIhtLo8t1JJgltlxWdsITw==} - '@codemirror/language@6.10.8': - resolution: {integrity: sha512-wcP8XPPhDH2vTqf181U8MbZnW+tDyPYy0UzVOa+oHORjyT+mhhom9vBd7dApJwoDz9Nb/a8kHjJIsuA/t8vNFw==} - - '@codemirror/lint@6.8.4': - resolution: {integrity: sha512-u4q7PnZlJUojeRe8FJa/njJcMctISGgPQ4PnWsd9268R4ZTtU+tfFYmwkBvgcrK2+QQ8tYFVALVb5fVJykKc5A==} + '@codemirror/language@6.12.2': + resolution: {integrity: sha512-jEPmz2nGGDxhRTg3lTpzmIyGKxz3Gp3SJES4b0nAuE5SWQoKdT5GoQ69cwMmFd+wvFUhYirtDTr0/DRHpQAyWg==} - '@codemirror/search@6.5.10': - resolution: {integrity: sha512-RMdPdmsrUf53pb2VwflKGHEe1XVM07hI7vV2ntgw1dmqhimpatSJKva4VA9h4TLUDOD4EIF02201oZurpnEFsg==} + '@codemirror/lint@6.9.5': + resolution: {integrity: sha512-GElsbU9G7QT9xXhpUg1zWGmftA/7jamh+7+ydKRuT0ORpWS3wOSP0yT1FOlIZa7mIJjpVPipErsyvVqB9cfTFA==} - '@codemirror/state@6.5.2': - resolution: {integrity: sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==} + '@codemirror/state@6.6.0': + resolution: {integrity: sha512-4nbvra5R5EtiCzr9BTHiTLc+MLXK2QGiAVYMyi8PkQd3SR+6ixar/Q/01Fa21TBIDOZXgeWV4WppsQolSreAPQ==} - '@codemirror/view@6.36.4': - resolution: {integrity: sha512-ZQ0V5ovw/miKEXTvjgzRyjnrk9TwriUB1k4R5p7uNnHR9Hus+D1SXHGdJshijEzPFjU25xea/7nhIeSqYFKdbA==} + '@codemirror/view@6.40.0': + resolution: {integrity: sha512-WA0zdU7xfF10+5I3HhUUq3kqOx3KjqmtQ9lqZjfK7jtYk4G72YW9rezcSywpaUMCWOMlq+6E0pO1IWg1TNIhtg==} '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} @@ -626,677 +1115,975 @@ packages: resolution: {integrity: sha512-NKBGBSIKUG584qrS1tyxVpX/AKJKQw5HgjYEnPLC0QsTw79JrGn+qUr8CXFb955Iy7GUdiiUv1rJ6JBGvaKb6w==} engines: {node: '>=18'} - '@esbuild/aix-ppc64@0.24.2': - resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==} + '@emnapi/core@1.9.0': + resolution: {integrity: sha512-0DQ98G9ZQZOxfUcQn1waV2yS8aWdZ6kJMbYCJB3oUBecjWYO1fqJ+a1DRfPF3O5JEkwqwP1A9QEN/9mYm2Yd0w==} + + '@emnapi/runtime@1.9.0': + resolution: {integrity: sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw==} + + '@emnapi/wasi-threads@1.2.0': + resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==} + + '@esbuild/aix-ppc64@0.27.3': + resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.25.0': - resolution: {integrity: sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==} + '@esbuild/aix-ppc64@0.27.4': + resolution: {integrity: sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.24.2': - resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==} + '@esbuild/android-arm64@0.27.3': + resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.25.0': - resolution: {integrity: sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==} + '@esbuild/android-arm64@0.27.4': + resolution: {integrity: sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.24.2': - resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==} + '@esbuild/android-arm@0.27.3': + resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-arm@0.25.0': - resolution: {integrity: sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==} + '@esbuild/android-arm@0.27.4': + resolution: {integrity: sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.24.2': - resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==} + '@esbuild/android-x64@0.27.3': + resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/android-x64@0.25.0': - resolution: {integrity: sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==} + '@esbuild/android-x64@0.27.4': + resolution: {integrity: sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.24.2': - resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==} + '@esbuild/darwin-arm64@0.27.3': + resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.25.0': - resolution: {integrity: sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==} + '@esbuild/darwin-arm64@0.27.4': + resolution: {integrity: sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.24.2': - resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==} + '@esbuild/darwin-x64@0.27.3': + resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.25.0': - resolution: {integrity: sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==} + '@esbuild/darwin-x64@0.27.4': + resolution: {integrity: sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.24.2': - resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==} + '@esbuild/freebsd-arm64@0.27.3': + resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.25.0': - resolution: {integrity: sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==} + '@esbuild/freebsd-arm64@0.27.4': + resolution: {integrity: sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.24.2': - resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==} + '@esbuild/freebsd-x64@0.27.3': + resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.0': - resolution: {integrity: sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==} + '@esbuild/freebsd-x64@0.27.4': + resolution: {integrity: sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.24.2': - resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==} + '@esbuild/linux-arm64@0.27.3': + resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.25.0': - resolution: {integrity: sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==} + '@esbuild/linux-arm64@0.27.4': + resolution: {integrity: sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.24.2': - resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==} + '@esbuild/linux-arm@0.27.3': + resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.25.0': - resolution: {integrity: sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==} + '@esbuild/linux-arm@0.27.4': + resolution: {integrity: sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.24.2': - resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==} + '@esbuild/linux-ia32@0.27.3': + resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.25.0': - resolution: {integrity: sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==} + '@esbuild/linux-ia32@0.27.4': + resolution: {integrity: sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.24.2': - resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==} + '@esbuild/linux-loong64@0.27.3': + resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.25.0': - resolution: {integrity: sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==} + '@esbuild/linux-loong64@0.27.4': + resolution: {integrity: sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.24.2': - resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==} + '@esbuild/linux-mips64el@0.27.3': + resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.25.0': - resolution: {integrity: sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==} + '@esbuild/linux-mips64el@0.27.4': + resolution: {integrity: sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.24.2': - resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==} + '@esbuild/linux-ppc64@0.27.3': + resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.25.0': - resolution: {integrity: sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==} + '@esbuild/linux-ppc64@0.27.4': + resolution: {integrity: sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.24.2': - resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==} + '@esbuild/linux-riscv64@0.27.3': + resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.25.0': - resolution: {integrity: sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==} + '@esbuild/linux-riscv64@0.27.4': + resolution: {integrity: sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.24.2': - resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==} + '@esbuild/linux-s390x@0.27.3': + resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.25.0': - resolution: {integrity: sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==} + '@esbuild/linux-s390x@0.27.4': + resolution: {integrity: sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.24.2': - resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==} + '@esbuild/linux-x64@0.27.3': + resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.25.0': - resolution: {integrity: sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==} + '@esbuild/linux-x64@0.27.4': + resolution: {integrity: sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.24.2': - resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==} + '@esbuild/netbsd-arm64@0.27.3': + resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-arm64@0.25.0': - resolution: {integrity: sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==} + '@esbuild/netbsd-arm64@0.27.4': + resolution: {integrity: sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.24.2': - resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==} + '@esbuild/netbsd-x64@0.27.3': + resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.0': - resolution: {integrity: sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==} + '@esbuild/netbsd-x64@0.27.4': + resolution: {integrity: sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.24.2': - resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==} + '@esbuild/openbsd-arm64@0.27.3': + resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-arm64@0.25.0': - resolution: {integrity: sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==} + '@esbuild/openbsd-arm64@0.27.4': + resolution: {integrity: sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.24.2': - resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==} + '@esbuild/openbsd-x64@0.27.3': + resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.0': - resolution: {integrity: sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==} + '@esbuild/openbsd-x64@0.27.4': + resolution: {integrity: sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/sunos-x64@0.24.2': - resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==} + '@esbuild/openharmony-arm64@0.27.3': + resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/openharmony-arm64@0.27.4': + resolution: {integrity: sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.27.3': + resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.25.0': - resolution: {integrity: sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==} + '@esbuild/sunos-x64@0.27.4': + resolution: {integrity: sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.24.2': - resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==} + '@esbuild/win32-arm64@0.27.3': + resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.25.0': - resolution: {integrity: sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==} + '@esbuild/win32-arm64@0.27.4': + resolution: {integrity: sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.24.2': - resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==} + '@esbuild/win32-ia32@0.27.3': + resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.25.0': - resolution: {integrity: sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==} + '@esbuild/win32-ia32@0.27.4': + resolution: {integrity: sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.24.2': - resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==} + '@esbuild/win32-x64@0.27.3': + resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} engines: {node: '>=18'} cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.25.0': - resolution: {integrity: sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==} + '@esbuild/win32-x64@0.27.4': + resolution: {integrity: sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==} engines: {node: '>=18'} cpu: [x64] os: [win32] - '@eslint-community/eslint-utils@4.4.1': - resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@fastify/ajv-compiler@4.0.5': + resolution: {integrity: sha512-KoWKW+MhvfTRWL4qrhUwAAZoaChluo0m0vbiJlGMt2GXvL4LVPQEjt8kSpHI3IBq5Rez8fg+XeH3cneztq+C7A==} + + '@fastify/error@4.2.0': + resolution: {integrity: sha512-RSo3sVDXfHskiBZKBPRgnQTtIqpi/7zhJOEmAxCiBcM7d0uwdGdxLlsCaLzGs8v8NnxIRlfG0N51p5yFaOentQ==} + + '@fastify/fast-json-stringify-compiler@5.0.3': + resolution: {integrity: sha512-uik7yYHkLr6fxd8hJSZ8c+xF4WafPK+XzneQDPU+D10r5X19GW8lJcom2YijX2+qtFF1ENJlHXKFM9ouXNJYgQ==} + + '@fastify/forwarded@3.0.1': + resolution: {integrity: sha512-JqDochHFqXs3C3Ml3gOY58zM7OqO9ENqPo0UqAjAjH8L01fRZqwX9iLeX34//kiJubF7r2ZQHtBRU36vONbLlw==} + + '@fastify/merge-json-schemas@0.2.1': + resolution: {integrity: sha512-OA3KGBCy6KtIvLf8DINC5880o5iBlDX4SxzLQS8HorJAbqluzLRn80UXU0bxZn7UOFhFgpRJDasfwn9nG4FG4A==} + + '@fastify/proxy-addr@5.1.0': + resolution: {integrity: sha512-INS+6gh91cLUjB+PVHfu1UqcB76Sqtpyp7bnL+FYojhjygvOPA9ctiD/JDKsyD9Xgu4hUhCSJBPig/w7duNajw==} + + '@floating-ui/core@1.7.5': + resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} + + '@floating-ui/dom@1.7.6': + resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} + + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + + '@floating-ui/utils@0.2.11': + resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} + + '@floating-ui/vue@1.1.9': + resolution: {integrity: sha512-BfNqNW6KA83Nexspgb9DZuz578R7HT8MZw1CfK9I6Ah4QReNWEJsXWHN+SdmOVLNGmTPDi+fDT535Df5PzMLbQ==} + + '@hapi/hoek@9.3.0': + resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} + + '@hapi/topo@5.1.0': + resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} + + '@headlessui/tailwindcss@0.2.2': + resolution: {integrity: sha512-xNe42KjdyA4kfUKLLPGzME9zkH7Q3rOZ5huFihWNWOQFxnItxPB3/67yBI8/qBfY8nwBRx5GHn4VprsoluVMGw==} + engines: {node: '>=10'} peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + tailwindcss: ^3.0 || ^4.0 - '@eslint-community/regexpp@4.12.1': - resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + '@headlessui/vue@1.7.23': + resolution: {integrity: sha512-JzdCNqurrtuu0YW6QaDtR2PIYCKPUWq28csDyMvN4zmGccmE7lz40Is6hc3LA4HFeCI7sekZ/PQMTNmn9I/4Wg==} + engines: {node: '>=10'} + peerDependencies: + vue: ^3.2.0 - '@eslint/config-array@0.19.2': - resolution: {integrity: sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@hiogawa/vite-plugin-fullstack@0.0.11': + resolution: {integrity: sha512-PEA5TmioqP0aqbWUA2upmgmjap7sqrHFo3+xx2+/B15vBD3uWeeWvJbCeaxjRGbnjPXpxJTZstZv8m0UB8FUQw==} + peerDependencies: + vite: ^8.0.0-beta.18 - '@eslint/config-helpers@0.1.0': - resolution: {integrity: sha512-kLrdPDJE1ckPo94kmPPf9Hfd0DU0Jw6oKYrhe+pwSC0iTUInmTa+w6fw8sGgcfkFJGNdWOUeOaDM4quW4a7OkA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} - '@eslint/core@0.12.0': - resolution: {integrity: sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] - '@eslint/eslintrc@3.3.0': - resolution: {integrity: sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] - '@eslint/js@9.22.0': - resolution: {integrity: sha512-vLFajx9o8d1/oL2ZkpMYbkLv8nDB6yaIwFNt7nI4+I80U/z03SxmfOMsLbvWr3p7C+Wnoh//aOu2pQW8cS0HCQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] - '@eslint/object-schema@2.1.6': - resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] - '@eslint/plugin-kit@0.2.7': - resolution: {integrity: sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + libc: [glibc] - '@fastify/busboy@2.1.1': - resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} - engines: {node: '>=14'} + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + libc: [glibc] - '@fastify/busboy@3.1.1': - resolution: {integrity: sha512-5DGmA8FTdB2XbDeEwc/5ZXBl6UbBAyBOOLlPuBnZ/N1SwdH9Ii+cOX3tBROlDgcTXxjOYnLMVoKk9+FXAw0CJw==} + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] - '@firebase/app-check-interop-types@0.3.2': - resolution: {integrity: sha512-LMs47Vinv2HBMZi49C09dJxp0QT5LwDzFaVGf/+ITHe3BlIhUiLNttkATSXplc89A2lAaeTqjgqVkiRfUGyQiQ==} + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] - '@firebase/app-types@0.9.2': - resolution: {integrity: sha512-oMEZ1TDlBz479lmABwWsWjzHwheQKiAgnuKxE0pz0IXCVx7/rtlkx1fQ6GfgK24WCrxDKMplZrT50Kh04iMbXQ==} + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] - '@firebase/auth-interop-types@0.2.3': - resolution: {integrity: sha512-Fc9wuJGgxoxQeavybiuwgyi+0rssr76b+nHpj+eGhXFYAdudMWyfBHvFL/I5fEHniUM/UQdFzi9VXJK2iZF7FQ==} + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + libc: [glibc] - '@firebase/component@0.6.9': - resolution: {integrity: sha512-gm8EUEJE/fEac86AvHn8Z/QW8BvR56TBw3hMW0O838J/1mThYQXAIQBgUv75EqlCZfdawpWLrKt1uXvp9ciK3Q==} + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + libc: [musl] - '@firebase/database-compat@1.0.8': - resolution: {integrity: sha512-OpeWZoPE3sGIRPBKYnW9wLad25RaWbGyk7fFQe4xnJQKRzlynWeFBSRRAoLE2Old01WXwskUiucNqUUVlFsceg==} + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + libc: [musl] - '@firebase/database-types@1.0.5': - resolution: {integrity: sha512-fTlqCNwFYyq/C6W7AJ5OCuq5CeZuBEsEwptnVxlNPkWCo5cTTyukzAHRSO/jaQcItz33FfYrrFk1SJofcu2AaQ==} + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [glibc] - '@firebase/database@1.0.8': - resolution: {integrity: sha512-dzXALZeBI1U5TXt6619cv0+tgEhJiwlUtQ55WNZY7vGAjv7Q1QioV969iYwt1AQQ0ovHnEW0YW9TiBfefLvErg==} + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + libc: [glibc] - '@firebase/logger@0.4.2': - resolution: {integrity: sha512-Q1VuA5M1Gjqrwom6I6NUU4lQXdo9IAQieXlujeHZWvRt1b7qQ0KwBaNAjgxG27jgF9/mUwsNmO8ptBCGVYhB0A==} + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] - '@firebase/util@1.10.0': - resolution: {integrity: sha512-xKtx4A668icQqoANRxyDLBLz51TAbDP9KRfpbKGxiCAW346d0BeJe5vN6/hKxxmWwnZ0mautyv39JxviwwQMOQ==} + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] - '@floating-ui/core@1.6.9': - resolution: {integrity: sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==} + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + libc: [glibc] - '@floating-ui/dom@1.6.13': - resolution: {integrity: sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==} + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [glibc] - '@floating-ui/utils@0.2.9': - resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==} + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [musl] - '@floating-ui/vue@1.1.6': - resolution: {integrity: sha512-XFlUzGHGv12zbgHNk5FN2mUB7ROul3oG2ENdTpWdE+qMFxyNxWSRmsoyhiEnpmabNm6WnUvR1OvJfUfN4ojC1A==} + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [musl] - '@google-cloud/firestore@7.11.0': - resolution: {integrity: sha512-88uZ+jLsp1aVMj7gh3EKYH1aulTAMFAp8sH/v5a9w8q8iqSG27RiWLoxSAFr/XocZ9hGiWH1kEnBw+zl3xAgNA==} - engines: {node: '>=14.0.0'} + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] - '@google-cloud/paginator@5.0.2': - resolution: {integrity: sha512-DJS3s0OVH4zFDB1PzjxAsHqJT6sKVbRwwML0ZBP9PbU7Yebtu/7SWMRzvO2J3nUi9pRNITCfu4LJeooM2w4pjg==} - engines: {node: '>=14.0.0'} + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] - '@google-cloud/projectify@4.0.0': - resolution: {integrity: sha512-MmaX6HeSvyPbWGwFq7mXdo0uQZLGBYCwziiLIGq5JVX+/bdI3SAq6bP98trV5eTWfLuvsMcIC1YJOF2vfteLFA==} - engines: {node: '>=14.0.0'} + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] - '@google-cloud/promisify@4.1.0': - resolution: {integrity: sha512-G/FQx5cE/+DqBbOpA5jKsegGwdPniU6PuIEMt+qxWgFxvxuFOzVmp6zYchtYuwAWV5/8Dgs0yAmjvNZv3uXLQg==} - engines: {node: '>=18'} + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] - '@google-cloud/storage@7.15.2': - resolution: {integrity: sha512-+2k+mcQBb9zkaXMllf2wwR/rI07guAx+eZLWsGTDihW2lJRGfiqB7xu1r7/s4uvSP/T+nAumvzT5TTscwHKJ9A==} - engines: {node: '>=14'} + '@internationalized/date@3.12.0': + resolution: {integrity: sha512-/PyIMzK29jtXaGU23qTvNZxvBXRtKbNnGDFD+PY6CZw/Y8Ex8pFUzkuCJCG9aOqmShjqhS9mPqP6Dk5onQY8rQ==} - '@grpc/grpc-js@1.12.6': - resolution: {integrity: sha512-JXUj6PI0oqqzTGvKtzOkxtpsyPRNsrmhh41TtIz/zEB6J+AUiZZ0dxWzcMwO9Ns5rmSPuMdghlTbUuqIM48d3Q==} - engines: {node: '>=12.10.0'} + '@internationalized/number@3.6.5': + resolution: {integrity: sha512-6hY4Kl4HPBvtfS62asS/R22JzNNy8vi/Ssev7x6EobfCp+9QIB2hKvI2EtbdJ0VSQacxVNtqhE/NmF/NZ0gm6g==} - '@grpc/proto-loader@0.7.13': - resolution: {integrity: sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==} - engines: {node: '>=6'} - hasBin: true + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} - '@hapi/hoek@9.3.0': - resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - '@hapi/topo@5.1.0': - resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} - '@headlessui/tailwindcss@0.2.2': - resolution: {integrity: sha512-xNe42KjdyA4kfUKLLPGzME9zkH7Q3rOZ5huFihWNWOQFxnItxPB3/67yBI8/qBfY8nwBRx5GHn4VprsoluVMGw==} - engines: {node: '>=10'} - peerDependencies: - tailwindcss: ^3.0 || ^4.0 + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} - '@headlessui/vue@1.7.23': - resolution: {integrity: sha512-JzdCNqurrtuu0YW6QaDtR2PIYCKPUWq28csDyMvN4zmGccmE7lz40Is6hc3LA4HFeCI7sekZ/PQMTNmn9I/4Wg==} - engines: {node: '>=10'} - peerDependencies: - vue: ^3.2.0 + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - '@humanfs/core@0.19.1': - resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} - engines: {node: '>=18.18.0'} + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@humanfs/node@0.16.6': - resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} - engines: {node: '>=18.18.0'} + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - '@humanwhocodes/module-importer@1.0.1': - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} + '@lezer/common@1.5.1': + resolution: {integrity: sha512-6YRVG9vBkaY7p1IVxL4s44n5nUnaNnGM2/AckNgYOnxTG2kWh1vR8BMxPseWPjRNpb5VtXnMpeYAEAADoRV1Iw==} - '@humanwhocodes/retry@0.3.1': - resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} - engines: {node: '>=18.18'} + '@lezer/css@1.3.1': + resolution: {integrity: sha512-PYAKeUVBo3HFThruRyp/iK91SwiZJnzXh8QzkQlwijB5y+N5iB28+iLk78o2zmKqqV0uolNhCwFqB8LA7b0Svg==} - '@humanwhocodes/retry@0.4.2': - resolution: {integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==} - engines: {node: '>=18.18'} + '@lezer/highlight@1.2.3': + resolution: {integrity: sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==} - '@hyperjump/browser@1.2.0': - resolution: {integrity: sha512-xv7u4Ddbhnd9a4yi8V0bNYQrimL0SuBW2T+l4eSEKedxhIBVqxuZ6Vulm6+rPtcvg79LyhWxH4fB/J056qaSMQ==} - engines: {node: '>=18.0.0'} + '@lezer/html@1.3.13': + resolution: {integrity: sha512-oI7n6NJml729m7pjm9lvLvmXbdoMoi2f+1pwSDJkl9d68zGr7a9Btz8NdHTGQZtW2DA25ybeuv/SyDb9D5tseg==} - '@hyperjump/json-pointer@1.1.0': - resolution: {integrity: sha512-tFCKxMKDKK3VEdtUA3EBOS9GmSOS4mbrTjh9v3RnK10BphDMOb6+bxTh++/ae1AyfHyWb6R54O/iaoAtPMZPCg==} + '@lezer/javascript@1.5.4': + resolution: {integrity: sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==} - '@hyperjump/json-schema@1.11.0': - resolution: {integrity: sha512-gX1YNObOybUW6tgJjvb1lomNbI/VnY+EBPokmEGy9Lk8cgi+gE0vXhX1XDgIpUUA4UXfgHEn5I1mga5vHgOttg==} - peerDependencies: - '@hyperjump/browser': ^1.1.0 + '@lezer/json@1.0.3': + resolution: {integrity: sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==} - '@hyperjump/pact@1.3.0': - resolution: {integrity: sha512-/UIKatOtyZ3kN4A7AQmqZKzg/6es9jKyeWbfrenb2rDb3I9W4ZrVZT8q1zDrI/G+849I6Eq0ybzV1mmEC9zoDg==} + '@lezer/lr@1.4.8': + resolution: {integrity: sha512-bPWa0Pgx69ylNlMlPvBPryqeLYQjyJjqPx+Aupm5zydLIF3NE+6MMLT8Yi23Bd9cif9VS00aUebn+6fDIGBcDA==} - '@hyperjump/uri@1.3.1': - resolution: {integrity: sha512-2ecKymxf6prQMgrNpAvlx4RhsuM5+PFT6oh6uUTZdv5qmBv0RZvxv8LJ7oR30ZxGhdPdZAl4We/1NFc0nqHeAw==} + '@lezer/xml@1.0.6': + resolution: {integrity: sha512-CdDwirL0OEaStFue/66ZmFSeppuL6Dwjlk8qk153mSQwiSH/Dlri4GNymrNWnUmPl2Um7QfV1FO9KFUyX3Twww==} - '@internationalized/date@3.7.0': - resolution: {integrity: sha512-VJ5WS3fcVx0bejE/YHfbDKR/yawZgKqn/if+oEeLqNwBtPzVB06olkfcnojTmEMX+gTpH+FlQ69SHNitJ8/erQ==} + '@lezer/yaml@1.0.4': + resolution: {integrity: sha512-2lrrHqxalACEbxIbsjhqGpSW8kWpUKuY6RHgnSAFZa6qK62wvnPxA8hGOwOoDbwHcOFs5M4o27mjGu+P7TvBmw==} - '@internationalized/number@3.6.0': - resolution: {integrity: sha512-PtrRcJVy7nw++wn4W2OuePQQfTqDzfusSuY1QTtui4wa7r+rGVtR75pO8CyKvHvzyQYi3Q1uO5sY0AsB4e65Bw==} + '@marijn/find-cluster-break@1.0.2': + resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==} - '@ioredis/commands@1.2.0': - resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==} + '@napi-rs/wasm-runtime@1.1.1': + resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} - '@isaacs/cliui@8.0.2': - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: '>=12'} + '@netlify/edge-functions@3.0.4': + resolution: {integrity: sha512-3wVqFjBrLxp/8lQ/hm/Z1yLgVnP5WTt3jwlQwm+YN8eHBYAzX0RMRVJkv9c/rQTUTGK92TAIptrwBtK7GRQRSQ==} + engines: {node: '>=18.0.0'} - '@isaacs/fs-minipass@4.0.1': - resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + '@netlify/functions@5.1.3': + resolution: {integrity: sha512-kRvesKsdSbP4XCBHg5WtGGoeoigxuDVpzHM6EI1dVxBiXLRGlazFP12gm/CBJyVhvlXpGHgetamdKCCLvVUB/Q==} engines: {node: '>=18.0.0'} - '@istanbuljs/schema@0.1.3': - resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} - engines: {node: '>=8'} + '@netlify/types@2.4.0': + resolution: {integrity: sha512-FMHxZCa2XWIQgjt1WP1dTZ909XIbD1tWQYfXpIBZMq2H3hzFZV2HIDNWGfoL8INQ/CjGBP6dGbsfC6AbvHmH+Q==} + engines: {node: ^18.14.0 || >=20} - '@jridgewell/gen-mapping@0.3.8': - resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} - engines: {node: '>=6.0.0'} + '@oozcitak/dom@2.0.2': + resolution: {integrity: sha512-GjpKhkSYC3Mj4+lfwEyI1dqnsKTgwGy48ytZEhm4A/xnH/8z9M3ZVXKr/YGQi3uCLs1AEBS+x5T2JPiueEDW8w==} + engines: {node: '>=20.0'} + + '@oozcitak/infra@2.0.2': + resolution: {integrity: sha512-2g+E7hoE2dgCz/APPOEK5s3rMhJvNxSMBrP+U+j1OWsIbtSpWxxlUjq1lU8RIsFJNYv7NMlnVsCuHcUzJW+8vA==} + engines: {node: '>=20.0'} + + '@oozcitak/url@3.0.0': + resolution: {integrity: sha512-ZKfET8Ak1wsLAiLWNfFkZc/BraDccuTJKR6svTYc7sVjbR+Iu0vtXdiDMY4o6jaFl5TW2TlS7jbLl4VovtAJWQ==} + engines: {node: '>=20.0'} + + '@oozcitak/util@10.0.0': + resolution: {integrity: sha512-hAX0pT/73190NLqBPPWSdBVGtbY6VOhWYK3qqHqtXQ1gK7kS2yz4+ivsN07hpJ6I3aeMtKP6J6npsEKOAzuTLA==} + engines: {node: '>=20.0'} + + '@opentelemetry/api@1.9.0': + resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} + engines: {node: '>=8.0.0'} + + '@oxc-project/runtime@0.115.0': + resolution: {integrity: sha512-Rg8Wlt5dCbXhQnsXPrkOjL1DTSvXLgb2R/KYfnf1/K+R0k6UMLEmbQXPM+kwrWqSmWA2t0B1EtHy2/3zikQpvQ==} + engines: {node: ^20.19.0 || >=22.12.0} + + '@oxc-project/types@0.115.0': + resolution: {integrity: sha512-4n91DKnebUS4yjUHl2g3/b2T+IUdCfmoZGhmwsovZCDaJSs+QkVAM+0AqqTxHSsHfeiMuueT75cZaZcT/m0pSw==} + + '@oxfmt/binding-android-arm-eabi@0.40.0': + resolution: {integrity: sha512-S6zd5r1w/HmqR8t0CTnGjFTBLDq2QKORPwriCHxo4xFNuhmOTABGjPaNvCJJVnrKBLsohOeiDX3YqQfJPF+FXw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@oxfmt/binding-android-arm64@0.40.0': + resolution: {integrity: sha512-/mbS9UUP/5Vbl2D6osIdcYiP0oie63LKMoTyGj5hyMCK/SFkl3EhtyRAfdjPvuvHC0SXdW6ePaTKkBSq1SNcIw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@oxfmt/binding-darwin-arm64@0.40.0': + resolution: {integrity: sha512-wRt8fRdfLiEhnRMBonlIbKrJWixoEmn6KCjKE9PElnrSDSXETGZfPb8ee+nQNTobXkCVvVLytp2o0obAsxl78Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@oxfmt/binding-darwin-x64@0.40.0': + resolution: {integrity: sha512-fzowhqbOE/NRy+AE5ob0+Y4X243WbWzDb00W+pKwD7d9tOqsAFbtWUwIyqqCoCLxj791m2xXIEeLH/3uz7zCCg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@oxfmt/binding-freebsd-x64@0.40.0': + resolution: {integrity: sha512-agZ9ITaqdBjcerRRFEHB8s0OyVcQW8F9ZxsszjxzeSthQ4fcN2MuOtQFWec1ed8/lDa50jSLHVE2/xPmTgtCfQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@oxfmt/binding-linux-arm-gnueabihf@0.40.0': + resolution: {integrity: sha512-ZM2oQ47p28TP1DVIp7HL1QoMUgqlBFHey0ksHct7tMXoU5BqjNvPWw7888azzMt25lnyPODVuye1wvNbvVUFOA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxfmt/binding-linux-arm-musleabihf@0.40.0': + resolution: {integrity: sha512-RBFPAxRAIsMisKM47Oe6Lwdv6agZYLz02CUhVCD1sOv5ajAcRMrnwCFBPWwGXpazToW2mjnZxFos8TuFjTU15A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxfmt/binding-linux-arm64-gnu@0.40.0': + resolution: {integrity: sha512-Nb2XbQ+wV3W2jSIihXdPj7k83eOxeSgYP3N/SRXvQ6ZYPIk6Q86qEh5Gl/7OitX3bQoQrESqm1yMLvZV8/J7dA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@oxfmt/binding-linux-arm64-musl@0.40.0': + resolution: {integrity: sha512-tGmWhLD/0YMotCdfezlT6tC/MJG/wKpo4vnQ3Cq+4eBk/BwNv7EmkD0VkD5F/dYkT3b8FNU01X2e8vvJuWoM1w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@oxfmt/binding-linux-ppc64-gnu@0.40.0': + resolution: {integrity: sha512-rVbFyM3e7YhkVnp0IVYjaSHfrBWcTRWb60LEcdNAJcE2mbhTpbqKufx0FrhWfoxOrW/+7UJonAOShoFFLigDqQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@oxfmt/binding-linux-riscv64-gnu@0.40.0': + resolution: {integrity: sha512-3ZqBw14JtWeEoLiioJcXSJz8RQyPE+3jLARnYM1HdPzZG4vk+Ua8CUupt2+d+vSAvMyaQBTN2dZK+kbBS/j5mA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@oxfmt/binding-linux-riscv64-musl@0.40.0': + resolution: {integrity: sha512-JJ4PPSdcbGBjPvb+O7xYm2FmAsKCyuEMYhqatBAHMp/6TA6rVlf9Z/sYPa4/3Bommb+8nndm15SPFRHEPU5qFA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [musl] - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} + '@oxfmt/binding-linux-s390x-gnu@0.40.0': + resolution: {integrity: sha512-Kp0zNJoX9Ik77wUya2tpBY3W9f40VUoMQLWVaob5SgCrblH/t2xr/9B2bWHfs0WCefuGmqXcB+t0Lq77sbBmZw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] - '@jridgewell/set-array@1.2.1': - resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} - engines: {node: '>=6.0.0'} + '@oxfmt/binding-linux-x64-gnu@0.40.0': + resolution: {integrity: sha512-7YTCNzleWTaQTqNGUNQ66qVjpoV6DjbCOea+RnpMBly2bpzrI/uu7Rr+2zcgRfNxyjXaFTVQKaRKjqVdeUfeVA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] - '@jridgewell/source-map@0.3.6': - resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} + '@oxfmt/binding-linux-x64-musl@0.40.0': + resolution: {integrity: sha512-hWnSzJ0oegeOwfOEeejYXfBqmnRGHusgtHfCPzmvJvHTwy1s3Neo59UKc1CmpE3zxvrCzJoVHos0rr97GHMNPw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] - '@jridgewell/sourcemap-codec@1.5.0': - resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + '@oxfmt/binding-openharmony-arm64@0.40.0': + resolution: {integrity: sha512-28sJC1lR4qtBJGzSRRbPnSW3GxU2+4YyQFE6rCmsUYqZ5XYH8jg0/w+CvEzQ8TuAQz5zLkcA25nFQGwoU0PT3Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] - '@jridgewell/trace-mapping@0.3.25': - resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@oxfmt/binding-win32-arm64-msvc@0.40.0': + resolution: {integrity: sha512-cDkRnyT0dqwF5oIX1Cv59HKCeZQFbWWdUpXa3uvnHFT2iwYSSZspkhgjXjU6iDp5pFPaAEAe9FIbMoTgkTmKPg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] - '@jridgewell/trace-mapping@0.3.9': - resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@oxfmt/binding-win32-ia32-msvc@0.40.0': + resolution: {integrity: sha512-7rPemBJjqm5Gkv6ZRCPvK8lE6AqQ/2z31DRdWazyx2ZvaSgL7QGofHXHNouRpPvNsT9yxRNQJgigsWkc+0qg4w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] - '@js-sdsl/ordered-map@4.4.2': - resolution: {integrity: sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==} + '@oxfmt/binding-win32-x64-msvc@0.40.0': + resolution: {integrity: sha512-/Zmj0yTYSvmha6TG1QnoLqVT7ZMRDqXvFXXBQpIjteEwx9qvUYMBH2xbiOFhDeMUJkGwC3D6fdKsFtaqUvkwNA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] - '@lezer/common@1.2.3': - resolution: {integrity: sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==} + '@oxlint/binding-android-arm-eabi@1.55.0': + resolution: {integrity: sha512-NhvgAhncTSOhRahQSCnkK/4YIGPjTmhPurQQ2dwt2IvwCMTvZRW5vF2K10UBOxFve4GZDMw6LtXZdC2qeuYIVQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] - '@lezer/css@1.1.10': - resolution: {integrity: sha512-V5/89eDapjeAkWPBpWEfQjZ1Hag3aYUUJOL8213X0dFRuXJ4BXa5NKl9USzOnaLod4AOpmVCkduir2oKwZYZtg==} + '@oxlint/binding-android-arm64@1.55.0': + resolution: {integrity: sha512-P9iWRh+Ugqhg+D7rkc7boHX8o3H2h7YPcZHQIgvVBgnua5tk4LR2L+IBlreZs58/95cd2x3/004p5VsQM9z4SA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] - '@lezer/highlight@1.2.1': - resolution: {integrity: sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==} + '@oxlint/binding-darwin-arm64@1.55.0': + resolution: {integrity: sha512-esakkJIt7WFAhT30P/Qzn96ehFpzdZ1mNuzpOb8SCW7lI4oB8VsyQnkSHREM671jfpuBb/o2ppzBCx5l0jpgMA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] - '@lezer/html@1.3.10': - resolution: {integrity: sha512-dqpT8nISx/p9Do3AchvYGV3qYc4/rKr3IBZxlHmpIKam56P47RSHkSF5f13Vu9hebS1jM0HmtJIwLbWz1VIY6w==} + '@oxlint/binding-darwin-x64@1.55.0': + resolution: {integrity: sha512-xDMFRCCAEK9fOH6As2z8ELsC+VDGSFRHwIKVSilw+xhgLwTDFu37rtmRbmUlx8rRGS6cWKQPTc47AVxAZEVVPQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] - '@lezer/javascript@1.4.21': - resolution: {integrity: sha512-lL+1fcuxWYPURMM/oFZLEDm0XuLN128QPV+VuGtKpeaOGdcl9F2LYC3nh1S9LkPqx9M0mndZFdXCipNAZpzIkQ==} + '@oxlint/binding-freebsd-x64@1.55.0': + resolution: {integrity: sha512-mYZqnwUD7ALCRxGenyLd1uuG+rHCL+OTT6S8FcAbVm/ZT2AZMGjvibp3F6k1SKOb2aeqFATmwRykrE41Q0GWVw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] - '@lezer/json@1.0.3': - resolution: {integrity: sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==} + '@oxlint/binding-linux-arm-gnueabihf@1.55.0': + resolution: {integrity: sha512-LcX6RYcF9vL9ESGwJW3yyIZ/d/ouzdOKXxCdey1q0XJOW1asrHsIg5MmyKdEBR4plQx+shvYeQne7AzW5f3T1w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] - '@lezer/lr@1.4.2': - resolution: {integrity: sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==} + '@oxlint/binding-linux-arm-musleabihf@1.55.0': + resolution: {integrity: sha512-C+8GS1rPtK+dI7mJFkqoRBkDuqbrNihnyYQsJPS9ez+8zF9JzfvU19lawqt4l/Y23o5uQswE/DORa8aiXUih3w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] - '@lezer/xml@1.0.6': - resolution: {integrity: sha512-CdDwirL0OEaStFue/66ZmFSeppuL6Dwjlk8qk153mSQwiSH/Dlri4GNymrNWnUmPl2Um7QfV1FO9KFUyX3Twww==} + '@oxlint/binding-linux-arm64-gnu@1.55.0': + resolution: {integrity: sha512-ErLE4XbmcCopA4/CIDiH6J1IAaDOMnf/KSx/aFObs4/OjAAM3sFKWGZ57pNOMxhhyBdcmcXwYymph9GwcpcqgQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] - '@lezer/yaml@1.0.3': - resolution: {integrity: sha512-GuBLekbw9jDBDhGur82nuwkxKQ+a3W5H0GfaAthDXcAu+XdpS43VlnxA9E9hllkpSP5ellRDKjLLj7Lu9Wr6xA==} + '@oxlint/binding-linux-arm64-musl@1.55.0': + resolution: {integrity: sha512-/kp65avi6zZfqEng56TTuhiy3P/3pgklKIdf38yvYeJ9/PgEeRA2A2AqKAKbZBNAqUzrzHhz9jF6j/PZvhJzTQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] - '@mapbox/node-pre-gyp@2.0.0': - resolution: {integrity: sha512-llMXd39jtP0HpQLVI37Bf1m2ADlEb35GYSh1SDSLsBhR+5iCxiNGlT31yqbNtVHygHAtMy6dWFERpU2JgufhPg==} - engines: {node: '>=18'} - hasBin: true + '@oxlint/binding-linux-ppc64-gnu@1.55.0': + resolution: {integrity: sha512-A6pTdXwcEEwL/nmz0eUJ6WxmxcoIS+97GbH96gikAyre3s5deC7sts38ZVVowjS2QQFuSWkpA4ZmQC0jZSNvJQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] - '@marijn/find-cluster-break@1.0.2': - resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==} + '@oxlint/binding-linux-riscv64-gnu@1.55.0': + resolution: {integrity: sha512-clj0lnIN+V52G9tdtZl0LbdTSurnZ1NZj92Je5X4lC7gP5jiCSW+Y/oiDiSauBAD4wrHt2S7nN3pA0zfKYK/6Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] - '@netlify/edge-functions@2.11.1': - resolution: {integrity: sha512-pyQOTZ8a+ge5lZlE+H/UAHyuqQqtL5gE0pXrHT9mOykr3YQqnkB2hZMtx12odatZ87gHg4EA+UPyMZUbLfnXvw==} + '@oxlint/binding-linux-riscv64-musl@1.55.0': + resolution: {integrity: sha512-NNu08pllN5x/O94/sgR3DA8lbrGBnTHsINZZR0hcav1sj79ksTiKKm1mRzvZvacwQ0hUnGinFo+JO75ok2PxYg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [musl] - '@netlify/functions@3.0.0': - resolution: {integrity: sha512-XXf9mNw4+fkxUzukDpJtzc32bl1+YlXZwEhc5ZgMcTbJPLpgRLDs5WWSPJ4eY/Mv1ZFvtxmMwmfgoQYVt68Qog==} - engines: {node: '>=18.0.0'} + '@oxlint/binding-linux-s390x-gnu@1.55.0': + resolution: {integrity: sha512-BvfQz3PRlWZRoEZ17dZCqgQsMRdpzGZomJkVATwCIGhHVVeHJMQdmdXPSjcT1DCNUrOjXnVyj1RGDj5+/Je2+Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] - '@netlify/node-cookies@0.1.0': - resolution: {integrity: sha512-OAs1xG+FfLX0LoRASpqzVntVV/RpYkgpI0VrUnw2u0Q1qiZUzcPffxRK8HF3gc4GjuhG5ahOEMJ9bswBiZPq0g==} - engines: {node: ^14.16.0 || >=16.0.0} + '@oxlint/binding-linux-x64-gnu@1.55.0': + resolution: {integrity: sha512-ngSOoFCSBMKVQd24H8zkbcBNc7EHhjnF1sv3mC9NNXQ/4rRjI/4Dj9+9XoDZeFEkF1SX1COSBXF1b2Pr9rqdEw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] - '@netlify/serverless-functions-api@1.30.1': - resolution: {integrity: sha512-JkbaWFeydQdeDHz1mAy4rw+E3bl9YtbCgkntfTxq+IlNX/aIMv2/b1kZnQZcil4/sPoZGL831Dq6E374qRpU1A==} - engines: {node: '>=18.0.0'} + '@oxlint/binding-linux-x64-musl@1.55.0': + resolution: {integrity: sha512-BDpP7W8GlaG7BR6QjGZAleYzxoyKc/D24spZIF2mB3XsfALQJJT/OBmP8YpeTb1rveFSBHzl8T7l0aqwkWNdGA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] - '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} + '@oxlint/binding-openharmony-arm64@1.55.0': + resolution: {integrity: sha512-PS6GFvmde/pc3fCA2Srt51glr8Lcxhpf6WIBFfLphndjRrD34NEcses4TSxQrEcxYo6qVywGfylM0ZhSCF2gGA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] - '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} + '@oxlint/binding-win32-arm64-msvc@1.55.0': + resolution: {integrity: sha512-P6JcLJGs/q1UOvDLzN8otd9JsH4tsuuPDv+p7aHqHM3PrKmYdmUvkNj4K327PTd35AYcznOCN+l4ZOaq76QzSw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] - '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} + '@oxlint/binding-win32-ia32-msvc@1.55.0': + resolution: {integrity: sha512-gzkk4zE2zsE+WmRxFOiAZHpCpUNDFytEakqNXoNHW+PnYEOTPKDdW6nrzgSeTbGKVPXNAKQnRnMgrh7+n3Xueg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] - '@opentelemetry/api@1.9.0': - resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} - engines: {node: '>=8.0.0'} + '@oxlint/binding-win32-x64-msvc@1.55.0': + resolution: {integrity: sha512-ZFALNow2/og75gvYzNP7qe+rREQ5xunktwA+lgykoozHZ6hw9bqg4fn5j2UvG4gIn1FXqrZHkOAXuPf5+GOYTQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] - '@parcel/watcher-android-arm64@2.5.1': - resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} + '@parcel/watcher-android-arm64@2.5.6': + resolution: {integrity: sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [android] - '@parcel/watcher-darwin-arm64@2.5.1': - resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==} + '@parcel/watcher-darwin-arm64@2.5.6': + resolution: {integrity: sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [darwin] - '@parcel/watcher-darwin-x64@2.5.1': - resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==} + '@parcel/watcher-darwin-x64@2.5.6': + resolution: {integrity: sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [darwin] - '@parcel/watcher-freebsd-x64@2.5.1': - resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==} + '@parcel/watcher-freebsd-x64@2.5.6': + resolution: {integrity: sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [freebsd] - '@parcel/watcher-linux-arm-glibc@2.5.1': - resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==} + '@parcel/watcher-linux-arm-glibc@2.5.6': + resolution: {integrity: sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [glibc] - '@parcel/watcher-linux-arm-musl@2.5.1': - resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} + '@parcel/watcher-linux-arm-musl@2.5.6': + resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [musl] - '@parcel/watcher-linux-arm64-glibc@2.5.1': - resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} + '@parcel/watcher-linux-arm64-glibc@2.5.6': + resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] - '@parcel/watcher-linux-arm64-musl@2.5.1': - resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} + '@parcel/watcher-linux-arm64-musl@2.5.6': + resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [musl] - '@parcel/watcher-linux-x64-glibc@2.5.1': - resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} + '@parcel/watcher-linux-x64-glibc@2.5.6': + resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [glibc] - '@parcel/watcher-linux-x64-musl@2.5.1': - resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} + '@parcel/watcher-linux-x64-musl@2.5.6': + resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [musl] - '@parcel/watcher-wasm@2.5.1': - resolution: {integrity: sha512-RJxlQQLkaMMIuWRozy+z2vEqbaQlCuaCgVZIUCzQLYggY22LZbP5Y1+ia+FD724Ids9e+XIyOLXLrLgQSHIthw==} - engines: {node: '>= 10.0.0'} - bundledDependencies: - - napi-wasm - - '@parcel/watcher-win32-arm64@2.5.1': - resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} + '@parcel/watcher-win32-arm64@2.5.6': + resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [win32] - '@parcel/watcher-win32-ia32@2.5.1': - resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==} + '@parcel/watcher-win32-ia32@2.5.6': + resolution: {integrity: sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==} engines: {node: '>= 10.0.0'} cpu: [ia32] os: [win32] - '@parcel/watcher-win32-x64@2.5.1': - resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==} + '@parcel/watcher-win32-x64@2.5.6': + resolution: {integrity: sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [win32] - '@parcel/watcher@2.5.1': - resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} + '@parcel/watcher@2.5.6': + resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==} engines: {node: '>= 10.0.0'} + '@phosphor-icons/core@2.1.1': + resolution: {integrity: sha512-v4ARvrip4qBCImOE5rmPUylOEK4iiED9ZyKjcvzuezqMaiRASCHKcRIuvvxL/twvLpkfnEODCOJp5dM4eZilxQ==} + + '@pinojs/redact@0.4.0': + resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -1309,82 +2096,176 @@ packages: resolution: {integrity: sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==} engines: {node: '>=12.22.0'} - '@pnpm/npm-conf@2.3.1': - resolution: {integrity: sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==} + '@pnpm/npm-conf@3.0.2': + resolution: {integrity: sha512-h104Kh26rR8tm+a3Qkc5S4VLYint3FE48as7+/5oCEcKR2idC/pF1G6AhIXKI+eHPJa/3J9i5z0Al47IeGHPkA==} engines: {node: '>=12'} - '@popperjs/core@2.11.8': - resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} + '@poppinss/colors@4.1.6': + resolution: {integrity: sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==} - '@poppinss/colors@4.1.4': - resolution: {integrity: sha512-FA+nTU8p6OcSH4tLDY5JilGYr1bVWHpNmcLr7xmMEdbWmKHa+3QZ+DqefrXKmdjO/brHTnQZo20lLSjaO7ydog==} - engines: {node: '>=18.16.0'} + '@poppinss/dumper@0.6.5': + resolution: {integrity: sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==} - '@poppinss/dumper@0.6.3': - resolution: {integrity: sha512-iombbn8ckOixMtuV1p3f8jN6vqhXefNjJttoPaJDMeIk/yIGhkkL3OrHkEjE9SRsgoAx1vBUU2GtgggjvA5hCA==} + '@poppinss/dumper@0.7.0': + resolution: {integrity: sha512-0UTYalzk2t6S4rA2uHOz5bSSW2CHdv4vggJI6Alg90yvl0UgXs6XSXpH96OH+bRkX4J/06djv29pqXJ0lq5Kag==} - '@poppinss/exception@1.2.1': - resolution: {integrity: sha512-aQypoot0HPSJa6gDPEPTntc1GT6QINrSbgRlRhadGW2WaYqUK3tK4Bw9SBMZXhmxd3GeAlZjVcODHgiu+THY7A==} - engines: {node: '>=18'} + '@poppinss/exception@1.2.3': + resolution: {integrity: sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==} - '@protobufjs/aspromise@1.1.2': - resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + '@preact/preset-vite@2.10.3': + resolution: {integrity: sha512-1SiS+vFItpkNdBs7q585PSAIln0wBeBdcpJYbzPs1qipsb/FssnkUioNXuRsb8ZnU8YEQHr+3v8+/mzWSnTQmg==} + peerDependencies: + '@babel/core': 7.x + vite: ^8.0.0-beta.18 + + '@prefresh/babel-plugin@0.5.3': + resolution: {integrity: sha512-57LX2SHs4BX2s1IwCjNzTE2OJeEepRCNf1VTEpbNcUyHfMO68eeOWGDIt4ob9aYlW6PEWZ1SuwNikuoIXANDtQ==} + + '@prefresh/core@1.5.9': + resolution: {integrity: sha512-IKBKCPaz34OFVC+adiQ2qaTF5qdztO2/4ZPf4KsRTgjKosWqxVXmEbxCiUydYZRY8GVie+DQlKzQr9gt6HQ+EQ==} + peerDependencies: + preact: ^10.0.0 || ^11.0.0-0 - '@protobufjs/base64@1.1.2': - resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + '@prefresh/utils@1.2.1': + resolution: {integrity: sha512-vq/sIuN5nYfYzvyayXI4C2QkprfNaHUQ9ZX+3xLD8nL3rWyzpxOm1+K7RtMbhd+66QcaISViK7amjnheQ/4WZw==} + + '@prefresh/vite@2.4.12': + resolution: {integrity: sha512-FY1fzXpUjiuosznMV0YM7XAOPZjB5FIdWS0W24+XnlxYkt9hNAwwsiKYn+cuTEoMtD/ZVazS5QVssBr9YhpCQA==} + peerDependencies: + preact: ^10.4.0 || ^11.0.0-0 + vite: ^8.0.0-beta.18 + + '@replit/codemirror-css-color-picker@6.3.0': + resolution: {integrity: sha512-19biDANghUm7Fz7L1SNMIhK48tagaWuCOHj4oPPxc7hxPGkTVY2lU/jVZ8tsbTKQPVG7BO2CBDzs7CBwb20t4A==} + peerDependencies: + '@codemirror/language': ^6.0.0 + '@codemirror/state': ^6.0.0 + '@codemirror/view': ^6.0.0 - '@protobufjs/codegen@2.0.4': - resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} + '@rolldown/binding-android-arm64@1.0.0-rc.9': + resolution: {integrity: sha512-lcJL0bN5hpgJfSIz/8PIf02irmyL43P+j1pTCfbD1DbLkmGRuFIA4DD3B3ZOvGqG0XiVvRznbKtN0COQVaKUTg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] - '@protobufjs/eventemitter@1.1.0': - resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + '@rolldown/binding-darwin-arm64@1.0.0-rc.9': + resolution: {integrity: sha512-J7Zk3kLYFsLtuH6U+F4pS2sYVzac0qkjcO5QxHS7OS7yZu2LRs+IXo+uvJ/mvpyUljDJ3LROZPoQfgBIpCMhdQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] - '@protobufjs/fetch@1.1.0': - resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} + '@rolldown/binding-darwin-x64@1.0.0-rc.9': + resolution: {integrity: sha512-iwtmmghy8nhfRGeNAIltcNXzD0QMNaaA5U/NyZc1Ia4bxrzFByNMDoppoC+hl7cDiUq5/1CnFthpT9n+UtfFyg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] - '@protobufjs/float@1.0.2': - resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + '@rolldown/binding-freebsd-x64@1.0.0-rc.9': + resolution: {integrity: sha512-DLFYI78SCiZr5VvdEplsVC2Vx53lnA4/Ga5C65iyldMVaErr86aiqCoNBLl92PXPfDtUYjUh+xFFor40ueNs4Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] - '@protobufjs/inquire@1.1.0': - resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.9': + resolution: {integrity: sha512-CsjTmTwd0Hri6iTw/DRMK7kOZ7FwAkrO4h8YWKoX/kcj833e4coqo2wzIFywtch/8Eb5enQ/lwLM7w6JX1W5RQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] - '@protobufjs/path@1.1.2': - resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.9': + resolution: {integrity: sha512-2x9O2JbSPxpxMDhP9Z74mahAStibTlrBMW0520+epJH5sac7/LwZW5Bmg/E6CXuEF53JJFW509uP+lSedaUNxg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] - '@protobufjs/pool@1.1.0': - resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.9': + resolution: {integrity: sha512-JA1QRW31ogheAIRhIg9tjMfsYbglXXYGNPLdPEYrwFxdbkQCAzvpSCSHCDWNl4hTtrol8WeboCSEpjdZK8qrCg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] - '@protobufjs/utf8@1.1.0': - resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.9': + resolution: {integrity: sha512-aOKU9dJheda8Kj8Y3w9gnt9QFOO+qKPAl8SWd7JPHP+Cu0EuDAE5wokQubLzIDQWg2myXq2XhTpOVS07qqvT+w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] - '@redocly/ajv@8.11.2': - resolution: {integrity: sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==} + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.9': + resolution: {integrity: sha512-OalO94fqj7IWRn3VdXWty75jC5dk4C197AWEuMhIpvVv2lw9fiPhud0+bW2ctCxb3YoBZor71QHbY+9/WToadA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] - '@redocly/config@0.22.1': - resolution: {integrity: sha512-1CqQfiG456v9ZgYBG9xRQHnpXjt8WoSnDwdkX6gxktuK69v2037hTAR1eh0DGIqpZ1p4k82cGH8yTNwt7/pI9g==} + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.9': + resolution: {integrity: sha512-cVEl1vZtBsBZna3YMjGXNvnYYrOJ7RzuWvZU0ffvJUexWkukMaDuGhUXn0rjnV0ptzGVkvc+vW9Yqy6h8YX4pg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] - '@redocly/openapi-core@1.33.0': - resolution: {integrity: sha512-MUB1jPxYX2NmgiobICcvyrkSbPSaGAb/P/MsxSW+UT9hxpQvDCX81bstGg68BcKIdeFvVRKcoyG4xiTgDOEBfQ==} - engines: {node: '>=18.17.0', npm: '>=9.5.0'} + '@rolldown/binding-linux-x64-musl@1.0.0-rc.9': + resolution: {integrity: sha512-UzYnKCIIc4heAKgI4PZ3dfBGUZefGCJ1TPDuLHoCzgrMYPb5Rv6TLFuYtyM4rWyHM7hymNdsg5ik2C+UD9VDbA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] - '@replit/codemirror-css-color-picker@6.3.0': - resolution: {integrity: sha512-19biDANghUm7Fz7L1SNMIhK48tagaWuCOHj4oPPxc7hxPGkTVY2lU/jVZ8tsbTKQPVG7BO2CBDzs7CBwb20t4A==} - peerDependencies: - '@codemirror/language': ^6.0.0 - '@codemirror/state': ^6.0.0 - '@codemirror/view': ^6.0.0 + '@rolldown/binding-openharmony-arm64@1.0.0-rc.9': + resolution: {integrity: sha512-+6zoiF+RRyf5cdlFQP7nm58mq7+/2PFaY2DNQeD4B87N36JzfF/l9mdBkkmTvSYcYPE8tMh/o3cRlsx1ldLfog==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] - '@rollup/plugin-alias@5.1.1': - resolution: {integrity: sha512-PR9zDb+rOzkRb2VD+EuKB7UC41vU5DIwZ5qqCpk0KJudcWAyi8rvYOhS7+L5aZCspw1stTViLgN5v6FF1p5cgQ==} + '@rolldown/binding-wasm32-wasi@1.0.0-rc.9': + resolution: {integrity: sha512-rgFN6sA/dyebil3YTlL2evvi/M+ivhfnyxec7AccTpRPccno/rPoNlqybEZQBkcbZu8Hy+eqNJCqfBR8P7Pg8g==} engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.9': + resolution: {integrity: sha512-lHVNUG/8nlF1IQk1C0Ci574qKYyty2goMiPlRqkC5R+3LkXDkL5Dhx8ytbxq35m+pkHVIvIxviD+TWLdfeuadA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.9': + resolution: {integrity: sha512-G0oA4+w1iY5AGi5HcDTxWsoxF509hrFIPB2rduV5aDqS9FtDg1CAfa7V34qImbjfhIcA8C+RekocJZA96EarwQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.0-beta.40': + resolution: {integrity: sha512-s3GeJKSQOwBlzdUrj4ISjJj5SfSh+aqn0wjOar4Bx95iV1ETI7F6S/5hLcfAxZ9kXDcyrAkxPlqmd1ZITttf+w==} + + '@rolldown/pluginutils@1.0.0-beta.55': + resolution: {integrity: sha512-vajw/B3qoi7aYnnD4BQ4VoCcXQWnF0roSwE2iynbNxgW4l9mFwtLmLmUhpDdcTBfKyZm1p/T0D13qG94XBLohA==} + + '@rolldown/pluginutils@1.0.0-rc.2': + resolution: {integrity: sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==} + + '@rolldown/pluginutils@1.0.0-rc.3': + resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==} + + '@rolldown/pluginutils@1.0.0-rc.5': + resolution: {integrity: sha512-RxlLX/DPoarZ9PtxVrQgZhPoor987YtKQqCo5zkjX+0S0yLJ7Vv515Wk6+xtTL67VONKJKxETWZwuZjss2idYw==} + + '@rolldown/pluginutils@1.0.0-rc.9': + resolution: {integrity: sha512-w6oiRWgEBl04QkFZgmW+jnU1EC9b57Oihi2ot3HNWIQRqgHp5PnYDia5iZ5FF7rpa4EQdiqMDXjlqKGXBhsoXw==} + + '@rollup/plugin-alias@6.0.0': + resolution: {integrity: sha512-tPCzJOtS7uuVZd+xPhoy5W4vThe6KWXNmsFCNktaAh5RTqcLiSfT4huPQIXkgJ6YCOjJHvecOAzQxLFhPxKr+g==} + engines: {node: '>=20.19.0'} peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + rollup: '>=4.0.0' peerDependenciesMeta: rollup: optional: true - '@rollup/plugin-commonjs@28.0.3': - resolution: {integrity: sha512-pyltgilam1QPdn+Zd9gaCfOLcnjMEJ9gV+bTw6/r73INdvzf1ah9zLIJBm+kW7R6IUFIQ1YO+VqZtYxZNWFPEQ==} + '@rollup/plugin-commonjs@29.0.2': + resolution: {integrity: sha512-S/ggWH1LU7jTyi9DxZOKyxpVd4hF/OZ0JrEbeLjXk/DFXwRny0tjD2c992zOUYQobLrVkRVMDdmHP16HKP7GRg==} engines: {node: '>=16.0.0 || 14 >= 14.17'} peerDependencies: rollup: ^2.68.0||^3.0.0||^4.0.0 @@ -1410,8 +2291,8 @@ packages: rollup: optional: true - '@rollup/plugin-node-resolve@16.0.0': - resolution: {integrity: sha512-0FPvAeVUT/zdWoO0jnb/V5BlBsUSNfkIOtFHzMO4H9MOklrmQFY6FduVHKucNb/aTFxvnGhj4MNj/T1oNdDfNg==} + '@rollup/plugin-node-resolve@16.0.3': + resolution: {integrity: sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^2.78.0||^3.0.0||^4.0.0 @@ -1419,8 +2300,8 @@ packages: rollup: optional: true - '@rollup/plugin-replace@6.0.2': - resolution: {integrity: sha512-7QaYCf8bqF04dOy7w/eHmJeNExxTYwvKAmlSAH/EaWWUzbT0h5sbF6bktFoX/0F/0qwng5/dWFMyf3gzaM8DsQ==} + '@rollup/plugin-replace@6.0.3': + resolution: {integrity: sha512-J4RZarRvQAm5IF0/LwUUg+obsm+xZhYnbMXmXROyoSE1ATJe3oXSb9L5MMppdxP2ylNSjv6zFBwKYjcKMucVfA==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 @@ -1428,17 +2309,12 @@ packages: rollup: optional: true - '@rollup/plugin-terser@0.4.4': - resolution: {integrity: sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true + '@rollup/pluginutils@4.2.1': + resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} + engines: {node: '>= 8.0.0'} - '@rollup/pluginutils@5.1.4': - resolution: {integrity: sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==} + '@rollup/pluginutils@5.3.0': + resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 @@ -1446,240 +2322,575 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.35.0': - resolution: {integrity: sha512-uYQ2WfPaqz5QtVgMxfN6NpLD+no0MYHDBywl7itPYd3K5TjjSghNKmX8ic9S8NU8w81NVhJv/XojcHptRly7qQ==} + '@rollup/rollup-android-arm-eabi@4.59.0': + resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.35.0': - resolution: {integrity: sha512-FtKddj9XZudurLhdJnBl9fl6BwCJ3ky8riCXjEw3/UIbjmIY58ppWwPEvU3fNu+W7FUsAsB1CdH+7EQE6CXAPA==} + '@rollup/rollup-android-arm64@4.59.0': + resolution: {integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.35.0': - resolution: {integrity: sha512-Uk+GjOJR6CY844/q6r5DR/6lkPFOw0hjfOIzVx22THJXMxktXG6CbejseJFznU8vHcEBLpiXKY3/6xc+cBm65Q==} + '@rollup/rollup-darwin-arm64@4.59.0': + resolution: {integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.35.0': - resolution: {integrity: sha512-3IrHjfAS6Vkp+5bISNQnPogRAW5GAV1n+bNCrDwXmfMHbPl5EhTmWtfmwlJxFRUCBZ+tZ/OxDyU08aF6NI/N5Q==} + '@rollup/rollup-darwin-x64@4.59.0': + resolution: {integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.35.0': - resolution: {integrity: sha512-sxjoD/6F9cDLSELuLNnY0fOrM9WA0KrM0vWm57XhrIMf5FGiN8D0l7fn+bpUeBSU7dCgPV2oX4zHAsAXyHFGcQ==} + '@rollup/rollup-freebsd-arm64@4.59.0': + resolution: {integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.35.0': - resolution: {integrity: sha512-2mpHCeRuD1u/2kruUiHSsnjWtHjqVbzhBkNVQ1aVD63CcexKVcQGwJ2g5VphOd84GvxfSvnnlEyBtQCE5hxVVw==} + '@rollup/rollup-freebsd-x64@4.59.0': + resolution: {integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.35.0': - resolution: {integrity: sha512-mrA0v3QMy6ZSvEuLs0dMxcO2LnaCONs1Z73GUDBHWbY8tFFocM6yl7YyMu7rz4zS81NDSqhrUuolyZXGi8TEqg==} + '@rollup/rollup-linux-arm-gnueabihf@4.59.0': + resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==} cpu: [arm] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.35.0': - resolution: {integrity: sha512-DnYhhzcvTAKNexIql8pFajr0PiDGrIsBYPRvCKlA5ixSS3uwo/CWNZxB09jhIapEIg945KOzcYEAGGSmTSpk7A==} + '@rollup/rollup-linux-arm-musleabihf@4.59.0': + resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==} cpu: [arm] os: [linux] + libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.35.0': - resolution: {integrity: sha512-uagpnH2M2g2b5iLsCTZ35CL1FgyuzzJQ8L9VtlJ+FckBXroTwNOaD0z0/UF+k5K3aNQjbm8LIVpxykUOQt1m/A==} + '@rollup/rollup-linux-arm64-gnu@4.59.0': + resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==} cpu: [arm64] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.35.0': - resolution: {integrity: sha512-XQxVOCd6VJeHQA/7YcqyV0/88N6ysSVzRjJ9I9UA/xXpEsjvAgDTgH3wQYz5bmr7SPtVK2TsP2fQ2N9L4ukoUg==} + '@rollup/rollup-linux-arm64-musl@4.59.0': + resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==} cpu: [arm64] os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loong64-gnu@4.59.0': + resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==} + cpu: [loong64] + os: [linux] + libc: [glibc] - '@rollup/rollup-linux-loongarch64-gnu@4.35.0': - resolution: {integrity: sha512-5pMT5PzfgwcXEwOaSrqVsz/LvjDZt+vQ8RT/70yhPU06PTuq8WaHhfT1LW+cdD7mW6i/J5/XIkX/1tCAkh1W6g==} + '@rollup/rollup-linux-loong64-musl@4.59.0': + resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==} cpu: [loong64] os: [linux] + libc: [musl] + + '@rollup/rollup-linux-ppc64-gnu@4.59.0': + resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-ppc64-musl@4.59.0': + resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==} + cpu: [ppc64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-riscv64-gnu@4.59.0': + resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-musl@4.59.0': + resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-s390x-gnu@4.59.0': + resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.59.0': + resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.59.0': + resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-openbsd-x64@4.59.0': + resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.59.0': + resolution: {integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.59.0': + resolution: {integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.59.0': + resolution: {integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.59.0': + resolution: {integrity: sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.59.0': + resolution: {integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==} + cpu: [x64] + os: [win32] + + '@sagold/json-pointer@5.1.2': + resolution: {integrity: sha512-+wAhJZBXa6MNxRScg6tkqEbChEHMgVZAhTHVJ60Y7sbtXtu9XA49KfUkdWlS2x78D6H9nryiKePiYozumauPfA==} + + '@sagold/json-query@6.2.0': + resolution: {integrity: sha512-7bOIdUE6eHeoWtFm8TvHQHfTVSZuCs+3RpOKmZCDBIOrxpvF/rNFTeuvIyjHva/RR0yVS3kQtr+9TW72LQEZjA==} + + '@scalar/agent-chat@0.9.7': + resolution: {integrity: sha512-7zEcejUsDX6h8oqfu9wOLZ5M4QRi6ljftIaF4kQ9mcHO/n8ahCecjcdrCpEhX07HHFZog9WbcTh6lo1lEzFBOA==} + engines: {node: '>=22'} + + '@scalar/analytics-client@1.1.0': + resolution: {integrity: sha512-yJFafZxYv8bAauYPSYxqZZDfGCBSLKEyQfrNm6qPOqz2wSXDIK1N2eVZbjBKE4l3jW0MsejyHvkaEFNuTUFsHQ==} + engines: {node: '>=22'} + + '@scalar/api-client@2.37.0': + resolution: {integrity: sha512-ZNZVV91/DvHPjXUttzQcloq5oCHn8c6DfCENTT7gXiMx3Q2/iNkeUDP/ZfCe97jKsPOOOhqwsLhNTdKh5gRM4w==} + engines: {node: '>=22'} + + '@scalar/api-reference@1.48.7': + resolution: {integrity: sha512-hMjXzMNaQ3Hvmo/4kMtL5TNtm0moR0l5/oyXKNdTt7mafbscrazOePfhFJm2okQ5HnsX+BefRvIjaknOifXvbw==} + engines: {node: '>=22'} + + '@scalar/code-highlight@0.3.0': + resolution: {integrity: sha512-JAOnQ6ckPexNGomA065Gs8xYs01BZO45R+Oc/kgnEr6D02T2+cA7lo9nGr6WXKWniWghSzfngS8h+RjtNfo9aA==} + engines: {node: '>=22'} + + '@scalar/components@0.20.7': + resolution: {integrity: sha512-3wyyMNCxt0BeKYElMlJ9by+HyAwELZmQ4P28sWgVyNDlGkk6Fm5JG2GfGcNwnSQHQe/sBWK75xqU8UxJD4fwJA==} + engines: {node: '>=22'} + + '@scalar/draggable@0.4.0': + resolution: {integrity: sha512-oLCtH8OAPnhGdr6R77s777KUahZFBF/igiF2h1QmCzvYQMIpV/ZNUgA3V3WPBK4kWP8tFWOXB403Lv00ikxRig==} + engines: {node: '>=22'} + + '@scalar/helpers@0.4.1': + resolution: {integrity: sha512-XfyYqSUA597wfzS8lmMY1xvYv4si2WytuoBWj7JDpx3E/lVq7YEsticXF/Q30ttFVRBfgQErg8MQI6b6IkZr2Q==} + engines: {node: '>=22'} + + '@scalar/icons@0.6.0': + resolution: {integrity: sha512-Rl90K0RuzblkY1Ui0nkhB0wBDj70zYe3gkp/Gz4sbbCMobC9yAEpvfNzb+txu7utXb11QalHxSrvvTqkINuQNQ==} + engines: {node: '>=22'} + + '@scalar/import@0.5.2': + resolution: {integrity: sha512-warmmaewTkHNmkEUXctccSXwUhgDHiGH/BtITYmsQ1PDxZGIdppLw1+6OtRlZOayn2mOHwI/wuNtGjYcBh7wsQ==} + engines: {node: '>=22'} + + '@scalar/json-magic@0.12.3': + resolution: {integrity: sha512-SX4LbdCk/0JLP4t4oz1nzqfMzHsG9gY1jSgKB7Q2BsQHJ4V1zapQ+aFrMmbjaCrz8hueGG/3UCtgyWBNuGmT9g==} + engines: {node: '>=22'} + + '@scalar/oas-utils@0.10.6': + resolution: {integrity: sha512-lc1TP98oW61ftVQVD4EyGosXssYq/kldieTLE/4zzHx4vFD27uC/3wCcnffe+5CXE4OQSBMXQUAamRV7ux52jA==} + engines: {node: '>=22'} + + '@scalar/object-utils@1.3.2': + resolution: {integrity: sha512-Pt2pTWJYqpiXBX6UfUlNmJb1kRBYBJSbrufgpH/vBeIaWs2t8juAwl9s8lh9kabXtx4jkpgBlQV3kCyyC8szow==} + engines: {node: '>=22'} + + '@scalar/openapi-parser@0.25.3': + resolution: {integrity: sha512-uiqUxWMYYDrAdwK7qOgbrYW2RsULog1Bv47ehACwCzTJecP1Z/Uez4+UH/Ltqn0hNXPQ56yCzYwaIVcc3td+Jw==} + engines: {node: '>=22'} + + '@scalar/openapi-types@0.6.0': + resolution: {integrity: sha512-OeaCrQmXGqO+ZRGgo/mAA8X1nTsdNWW2BxQjyDWTCSD1Qv5Cm58QvKzINKvJPFWrS0LXebRF6OXN+2H2hu9xpA==} + engines: {node: '>=22'} + + '@scalar/openapi-upgrader@0.2.0': + resolution: {integrity: sha512-T8XKPaYBrxn+8THq8HgXjqpnqp71YZsPCamNYIYJrIM5pXSbBLyLoAh6uie7YfhcNvdQWc/KqahHQebEIcmeqA==} + engines: {node: '>=22'} + + '@scalar/postman-to-openapi@0.5.2': + resolution: {integrity: sha512-bfwT2xuE1ZmyOhBQtt26cWDTyLZXbfZC3TiJAhlrn+wNHeCbTwVoj3BBGVUAAbhsbrm/4OB4ABwEfn/MB2Q2fg==} + engines: {node: '>=22'} + + '@scalar/sidebar@0.8.7': + resolution: {integrity: sha512-21ZWW5ZaMKAqqcfpJSpo8oCOlPhMxdJT4a4uhDaPJRihc+b6ey+ndvjY+NUk6qzm9gkplHnX93P+jeG6nsNKkQ==} + engines: {node: '>=22'} + + '@scalar/snippetz@0.7.4': + resolution: {integrity: sha512-E0krod3+ROfKoKawowT3EfDVWUyZnHmfrKhfM7INm9kVRgxzmXjeM8d5FRNwSa4bVP6F8JycU3sn6QF4HFcA8A==} + engines: {node: '>=22'} + + '@scalar/themes@0.15.0': + resolution: {integrity: sha512-OFGrh0BSqMvZd69b6zBUQGG3Tp1it/+9BKBNWrnF/ftDBr+WfoUBd5qutA6bzpYWGTKe/8m2wUokRKAJT0af3g==} + engines: {node: '>=22'} + + '@scalar/typebox@0.1.3': + resolution: {integrity: sha512-lU055AUccECZMIfGA0z/C1StYmboAYIPJLDFBzOO81yXBi35Pxdq+I4fWX6iUZ8qcoHneiLGk9jAUM1rA93iEg==} + + '@scalar/types@0.7.3': + resolution: {integrity: sha512-9ThydMH28aA5DMm8Q/nTKXKnAKejG7Awlj7IC99oXkq5aOJ60Sn0kS1RWaqQosaWI3ezyPJ7/sUglssAEMA6EA==} + engines: {node: '>=22'} + + '@scalar/use-codemirror@0.14.7': + resolution: {integrity: sha512-dhCHryOnb+7xcbf25OFjIoTvJtOo8gbypPZWjeidKqUHSVsyePBARI0SYUN6A6xal8RDdcWFoUuo4g1doxXb3w==} + engines: {node: '>=22'} + + '@scalar/use-hooks@0.4.0': + resolution: {integrity: sha512-dKdfGssU+qONnHX//vZK1pqUDL5Kx1u4eK7LaZR48R2jC8qLgWNMBJWfCA6gZiiNGe70pqUbvCp9CiDnMTlQwQ==} + engines: {node: '>=22'} + + '@scalar/use-toasts@0.10.0': + resolution: {integrity: sha512-TOgBhomAaikJcTBMPtaOrSgDm4jaOvH2WRqvzRh0lEdMiftqsDP+3Iz7u6oAdQ/TedHgFU6W1COVXS0YFamDkQ==} + engines: {node: '>=22'} + + '@scalar/workspace-store@0.40.0': + resolution: {integrity: sha512-d/icRgkatbhZG2a/uaR0CsHKmOQCiiEJrx7Gf9Cf1u6ydoCzhbzkyZepz6IPNabcNMXrfT45OaJFEMD3PmE2uw==} + engines: {node: '>=22'} + + '@sec-ant/readable-stream@0.4.1': + resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} + + '@shikijs/core@3.23.0': + resolution: {integrity: sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==} + + '@shikijs/engine-javascript@3.23.0': + resolution: {integrity: sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA==} + + '@shikijs/engine-oniguruma@3.23.0': + resolution: {integrity: sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==} + + '@shikijs/langs@3.23.0': + resolution: {integrity: sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==} + + '@shikijs/themes@3.23.0': + resolution: {integrity: sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==} + + '@shikijs/types@3.23.0': + resolution: {integrity: sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==} + + '@shikijs/vscode-textmate@10.0.2': + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + + '@sideway/address@4.1.5': + resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} + + '@sideway/formula@3.0.1': + resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==} + + '@sideway/pinpoint@2.0.0': + resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} + + '@sinclair/typebox@0.34.48': + resolution: {integrity: sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==} + + '@sindresorhus/is@7.2.0': + resolution: {integrity: sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==} + engines: {node: '>=18'} + + '@sindresorhus/merge-streams@4.0.0': + resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} + engines: {node: '>=18'} + + '@speed-highlight/core@1.2.14': + resolution: {integrity: sha512-G4ewlBNhUtlLvrJTb88d2mdy2KRijzs4UhnlrOSRT4bmjh/IqNElZa3zkrZ+TC47TwtlDWzVLFADljF1Ijp5hA==} + + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + + '@swc/helpers@0.5.19': + resolution: {integrity: sha512-QamiFeIK3txNjgUTNppE6MiG3p7TdninpZu0E0PbqVh1a9FNLT2FRhisaa4NcaX52XVhA5l7Pk58Ft7Sqi/2sA==} + + '@tailwindcss/node@4.2.1': + resolution: {integrity: sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==} + + '@tailwindcss/oxide-android-arm64@4.2.1': + resolution: {integrity: sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.2.1': + resolution: {integrity: sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.2.1': + resolution: {integrity: sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.2.1': + resolution: {integrity: sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] - '@rollup/rollup-linux-powerpc64le-gnu@4.35.0': - resolution: {integrity: sha512-c+zkcvbhbXF98f4CtEIP1EBA/lCic5xB0lToneZYvMeKu5Kamq3O8gqrxiYYLzlZH6E3Aq+TSW86E4ay8iD8EA==} - cpu: [ppc64] + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1': + resolution: {integrity: sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==} + engines: {node: '>= 20'} + cpu: [arm] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.35.0': - resolution: {integrity: sha512-s91fuAHdOwH/Tad2tzTtPX7UZyytHIRR6V4+2IGlV0Cej5rkG0R61SX4l4y9sh0JBibMiploZx3oHKPnQBKe4g==} - cpu: [riscv64] + '@tailwindcss/oxide-linux-arm64-gnu@4.2.1': + resolution: {integrity: sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==} + engines: {node: '>= 20'} + cpu: [arm64] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-s390x-gnu@4.35.0': - resolution: {integrity: sha512-hQRkPQPLYJZYGP+Hj4fR9dDBMIM7zrzJDWFEMPdTnTy95Ljnv0/4w/ixFw3pTBMEuuEuoqtBINYND4M7ujcuQw==} - cpu: [s390x] + '@tailwindcss/oxide-linux-arm64-musl@4.2.1': + resolution: {integrity: sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==} + engines: {node: '>= 20'} + cpu: [arm64] os: [linux] + libc: [musl] - '@rollup/rollup-linux-x64-gnu@4.35.0': - resolution: {integrity: sha512-Pim1T8rXOri+0HmV4CdKSGrqcBWX0d1HoPnQ0uw0bdp1aP5SdQVNBy8LjYncvnLgu3fnnCt17xjWGd4cqh8/hA==} + '@tailwindcss/oxide-linux-x64-gnu@4.2.1': + resolution: {integrity: sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==} + engines: {node: '>= 20'} cpu: [x64] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.35.0': - resolution: {integrity: sha512-QysqXzYiDvQWfUiTm8XmJNO2zm9yC9P/2Gkrwg2dH9cxotQzunBHYr6jk4SujCTqnfGxduOmQcI7c2ryuW8XVg==} + '@tailwindcss/oxide-linux-x64-musl@4.2.1': + resolution: {integrity: sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==} + engines: {node: '>= 20'} cpu: [x64] os: [linux] + libc: [musl] - '@rollup/rollup-win32-arm64-msvc@4.35.0': - resolution: {integrity: sha512-OUOlGqPkVJCdJETKOCEf1mw848ZyJ5w50/rZ/3IBQVdLfR5jk/6Sr5m3iO2tdPgwo0x7VcncYuOvMhBWZq8ayg==} + '@tailwindcss/oxide-wasm32-wasi@4.2.1': + resolution: {integrity: sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.2.1': + resolution: {integrity: sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==} + engines: {node: '>= 20'} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.35.0': - resolution: {integrity: sha512-2/lsgejMrtwQe44glq7AFFHLfJBPafpsTa6JvP2NGef/ifOa4KBoglVf7AKN7EV9o32evBPRqfg96fEHzWo5kw==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.35.0': - resolution: {integrity: sha512-PIQeY5XDkrOysbQblSW7v3l1MDZzkTEzAfTPkj5VAu3FW8fS4ynyLg2sINp0fp3SjZ8xkRYpLqoKcYqAkhU1dw==} + '@tailwindcss/oxide-win32-x64-msvc@4.2.1': + resolution: {integrity: sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==} + engines: {node: '>= 20'} cpu: [x64] os: [win32] - '@sagold/json-pointer@5.1.2': - resolution: {integrity: sha512-+wAhJZBXa6MNxRScg6tkqEbChEHMgVZAhTHVJ60Y7sbtXtu9XA49KfUkdWlS2x78D6H9nryiKePiYozumauPfA==} - - '@sagold/json-query@6.2.0': - resolution: {integrity: sha512-7bOIdUE6eHeoWtFm8TvHQHfTVSZuCs+3RpOKmZCDBIOrxpvF/rNFTeuvIyjHva/RR0yVS3kQtr+9TW72LQEZjA==} - - '@scalar/api-client@2.2.59': - resolution: {integrity: sha512-oVn7uE23agRq8oaVqq2YUaM2dmqrVw//jymrBYt94IhfxEu7sYGyI2rb4yqJ95l+0b/W/aFpL24/LOASLZ33VQ==} - engines: {node: '>=18'} + '@tailwindcss/oxide@4.2.1': + resolution: {integrity: sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==} + engines: {node: '>= 20'} - '@scalar/api-reference@1.25.130': - resolution: {integrity: sha512-nAb8ToK/lgFvDhDvC/8cryDtNHoOEzaI4DFNM6CE9er95ty7iYUmDqnji8BQV0yTd5Rs9hp3BcJmHmr6dAx5MQ==} - engines: {node: '>=18'} + '@tailwindcss/vite@4.2.1': + resolution: {integrity: sha512-TBf2sJjYeb28jD2U/OhwdW0bbOsxkWPwQ7SrqGf9sVcoYwZj7rkXljroBO9wKBut9XnmQLXanuDUeqQK0lGg/w==} + peerDependencies: + vite: ^8.0.0-beta.18 - '@scalar/code-highlight@0.0.23': - resolution: {integrity: sha512-hDHoUgjq/8ntXzmD1hbO3nvem1ny+qcWRH7L2nOflwkXhXaDM1aOPNp9zyeCxLoWwC9db4wLFP3QW+eYS0OTiQ==} - engines: {node: '>=18'} + '@tanstack/history@1.161.4': + resolution: {integrity: sha512-Kp/WSt411ZWYvgXy6uiv5RmhHrz9cAml05AQPrtdAp7eUqvIDbMGPnML25OKbzR3RJ1q4wgENxDTvlGPa9+Mww==} + engines: {node: '>=20.19'} - '@scalar/components@0.13.31': - resolution: {integrity: sha512-JseJnIVOuqWKIs56FJ+QbZq5vKseue6WhCM+kFktmBeMRowHqEySxeVgEc7G7cot2+miaokyyviz33wgEvVmuA==} - engines: {node: '>=18'} + '@tanstack/react-router-devtools@1.166.7': + resolution: {integrity: sha512-sAh3gA3wkMvUI6rRLPW4lfP0XxeEA0wrlv4tW1cinb7eoD3avcdKwiE9jhQ3DgFlhVsHa9fa3AKxH46Y/d/e1g==} + engines: {node: '>=20.19'} + peerDependencies: + '@tanstack/react-router': ^1.166.7 + '@tanstack/router-core': ^1.166.7 + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + peerDependenciesMeta: + '@tanstack/router-core': + optional: true - '@scalar/draggable@0.1.11': - resolution: {integrity: sha512-EQW9N1+mDORhsbjdtCI3XDvmUKsuKw1uf6r3kT1Mm2zQKT+rWwA0ChsAkEN6OG62C0YumMuXpH71h1seAWptxw==} - engines: {node: '>=18'} + '@tanstack/react-router@1.167.0': + resolution: {integrity: sha512-U7CamtXjuC8ixg1c32Rj/4A2OFBnjtMLdbgbyOGHrFHE7ULWS/yhnZLVXff0QSyn6qF92Oecek9mDMHCaTnB2Q==} + engines: {node: '>=20.19'} + peerDependencies: + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' - '@scalar/icons@0.1.3': - resolution: {integrity: sha512-Bl46u7WsJ7NYjW1Fva7SMvw9c/92pGBP8B68tvDc+QevQ04DVNxw6+ny1NU/PnLtpuu1rUpPdtSCAkV1OdQGZQ==} - engines: {node: '>=18'} + '@tanstack/react-start-client@1.166.9': + resolution: {integrity: sha512-LCzoN0G8ypNmDmUKKJaPcOL+udOPCROhoCALaibfqPB+OfZqPbsctV2GC5fgv7ZSv7GRAeYE2H7HGr0LdcjiZg==} + engines: {node: '>=22.12.0'} + peerDependencies: + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' - '@scalar/import@0.2.33': - resolution: {integrity: sha512-9XybRaRSCN/jX3VS/Pv/jOXSeyjjWjLfVQKEDZG7wKKAFKTal0e0YFBo4Hd+EUV2MQyP/e5ZoswLaYzFyAkN+Q==} - engines: {node: '>=18'} + '@tanstack/react-start-server@1.166.9': + resolution: {integrity: sha512-3ZEwiLuPJSXQ+RYl+DLDG/si1Ug2EaS0kQ0em1Ll35btKr+sk0M00te3IMVaYudwMJeHqketxrCCZuDE9nHZXg==} + engines: {node: '>=22.12.0'} + peerDependencies: + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' - '@scalar/oas-utils@0.2.113': - resolution: {integrity: sha512-7NRTU5vPhiHpcqy559TXFfnFS2G01XqjQgOwbzicXmH5CD+/nivqo4D3qQhFZLjSuD+P+P/wI/1Rx7rwziAFig==} - engines: {node: '>=18'} + '@tanstack/react-start@1.166.11': + resolution: {integrity: sha512-HSieiNTwJssrq2Wb2BUrAXH+2TLun1VT0cgQ99OwVwxrrGCCQgbyNvS393wSAA2WvsIAEEw143ErwFc13P/zhw==} + engines: {node: '>=22.12.0'} + peerDependencies: + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + vite: ^8.0.0-beta.18 - '@scalar/object-utils@1.1.13': - resolution: {integrity: sha512-311eTykIXgOtjCs4VTELj9UMT97jHTWc5qkGNoIzZ5nxjCcvOVe7kDQobIkE8dGT+ybOgHz5qly02Eu7nVHeZQ==} - engines: {node: '>=18'} + '@tanstack/react-store@0.9.2': + resolution: {integrity: sha512-Vt5usJE5sHG/cMechQfmwvwne6ktGCELe89Lmvoxe3LKRoFrhPa8OCKWs0NliG8HTJElEIj7PLtaBQIcux5pAQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@scalar/openapi-parser@0.10.9': - resolution: {integrity: sha512-wsKZtL4B3Fmbv24B1zzeWdsEr6F60fLmToOFLA1b9QGQ6TAtIvLgKQWQ65eh5Vfx93nQb/iekamfErqHRHtEhA==} - engines: {node: '>=18'} + '@tanstack/router-core@1.167.0': + resolution: {integrity: sha512-pnaaUP+vMQEyL2XjZGe2PXmtzulxvXfGyvEMUs+AEBaNEk77xWA88bl3ujiBRbUxzpK0rxfJf+eSKPdZmBMFdQ==} + engines: {node: '>=20.19'} - '@scalar/openapi-types@0.1.9': - resolution: {integrity: sha512-HQQudOSQBU7ewzfnBW9LhDmBE2XOJgSfwrh5PlUB7zJup/kaRkBGNgV2wMjNz9Af/uztiU/xNrO179FysmUT+g==} - engines: {node: '>=18'} + '@tanstack/router-devtools-core@1.166.7': + resolution: {integrity: sha512-/OGLZlrw5NSNd9/PTL8vPSpmjxIbXNoeJATMHlU3YLCBVBtLx41CHIRc7OLkjyfVFJ4Sq7Pq+2/YH8PChShefg==} + engines: {node: '>=20.19'} + peerDependencies: + '@tanstack/router-core': ^1.166.7 + csstype: ^3.0.10 + peerDependenciesMeta: + csstype: + optional: true - '@scalar/postman-to-openapi@0.1.36': - resolution: {integrity: sha512-xHA7mxlkCMd0JvxkfQy6ux8vr/fv0HWvDyWFhDivUdLIJ3jWaC47vOSaWF17AkUZYf0WLmbVRSk+wXkohr088Q==} - engines: {node: '>=18'} + '@tanstack/router-generator@1.166.8': + resolution: {integrity: sha512-Ijl1AqKaAZAeE0+6boD/RVw/inQgq24AYMcTMhPSLSFdaYp+xR9HS5lhC6qj50rUVLRtWgM1tAbQvsQeyHv2/w==} + engines: {node: '>=20.19'} - '@scalar/snippetz@0.2.16': - resolution: {integrity: sha512-xtIY4kvV619IF2uXg6fDw7emtXwuJeWzLunGAaUTIOwNRw5mGSKqJnLcSnIiSdH54YmN8D2CtdJRo2VxPP9/Wg==} - engines: {node: '>=18'} + '@tanstack/router-plugin@1.166.9': + resolution: {integrity: sha512-vcVjlbFc9Bw5qqRrZlGkM1bFK34t5/YP4qmUJRCTDXa6Xg47b0yWwn39X4uzYe/RgW28XP/0qKJ859EQktUX3Q==} + engines: {node: '>=20.19'} + peerDependencies: + '@rsbuild/core': '>=1.0.2' + '@tanstack/react-router': ^1.167.0 + vite: ^8.0.0-beta.18 + vite-plugin-solid: ^2.11.10 + webpack: '>=5.92.0' + peerDependenciesMeta: + '@rsbuild/core': + optional: true + '@tanstack/react-router': + optional: true + vite: + optional: true + vite-plugin-solid: + optional: true + webpack: + optional: true - '@scalar/themes@0.9.74': - resolution: {integrity: sha512-20ee1pQd5i4f2dhZYShZ0MS08YEV49aQ4T4BeTTyZMvsqjSXhsPBh5kcMuc6xfAk5m0OQfbH1mKfDvpx90phHQ==} - engines: {node: '>=18'} + '@tanstack/router-utils@1.161.4': + resolution: {integrity: sha512-r8TpjyIZoqrXXaf2DDyjd44gjGBoyE+/oEaaH68yLI9ySPO1gUWmQENZ1MZnmBnpUGN24NOZxdjDLc8npK0SAw==} + engines: {node: '>=20.19'} - '@scalar/types@0.0.39': - resolution: {integrity: sha512-oAMBWC5B0I8IViCuaV1ydoUAm7KJSwHZfCuLMea15tSKh0/wj9H1KQvDJF8gE/cUVwjQvj4q94GB22kBT4XGNQ==} - engines: {node: '>=18'} + '@tanstack/start-client-core@1.166.8': + resolution: {integrity: sha512-xaSrDN+J0yiA/yFzv9CQQOMK3iEEnCznQV7nlNr9uQ4HAn1djbKGIWSBPE4qA/77Bfisuon1u4laFLhJkpd0fg==} + engines: {node: '>=22.12.0'} - '@scalar/use-codemirror@0.11.76': - resolution: {integrity: sha512-SYzq2vz/EshJ3bIYD7qKWLSidxX6fRzuDzRwpFbOxArrRDA2nEHNiMbls/loLToXKL7feeUL36UA/UJdwLVEWg==} - engines: {node: '>=18'} + '@tanstack/start-fn-stubs@1.161.4': + resolution: {integrity: sha512-b8s6iSQ+ny0P4lGK0n3DKaL6EI7SECG0/89svDeYieVw2+MaFOJVcQo3rU3BUvmuOcIkgkE5IhdzkmzPXH6yfA==} + engines: {node: '>=22.12.0'} - '@scalar/use-hooks@0.1.28': - resolution: {integrity: sha512-Gq3iYX+O0SHOO8bwxeqJ6DRhpwKiniH5gIM9sX4Fia1yaRvbzOMb6cjK6LdD8yBYLispam9a7k2e/bDglk/Jmw==} - engines: {node: '>=18'} + '@tanstack/start-plugin-core@1.166.11': + resolution: {integrity: sha512-Eb+pfmbEQYt0mKJC+Fnd10aOJK0jeOemesre0DBHagB4nqRhASmwWT7XXEreR2g/6b9fy2HKzWi52/UQD0it9g==} + engines: {node: '>=22.12.0'} + peerDependencies: + vite: ^8.0.0-beta.18 - '@scalar/use-toasts@0.7.9': - resolution: {integrity: sha512-EcUDJY8VozLS9sfoQKvvipStQJ9RuH/nKOzf0BBr+mZDmumi1WFZ1iIJnHVXIN3iSLcSAr5ej6rOqa6jIv4bCQ==} - engines: {node: '>=18'} + '@tanstack/start-server-core@1.166.8': + resolution: {integrity: sha512-mLqPB3SnOcLwCIv4tl/lmtL3E0CLtZyE9Sk4HoZ2JhxZyQ933oRQZeO2kt4z27lyBzddcT6xVayb774sjoEvcQ==} + engines: {node: '>=22.12.0'} - '@scalar/use-tooltip@1.0.6': - resolution: {integrity: sha512-f0gadIaUnILfi9qYAk7g+fNTsvLGXnam8oOUTxovavC1ocYuGTEykdz3g2MTqnAqRS8OkAB64h9mHf0FBfg6mg==} - engines: {node: '>=18'} + '@tanstack/start-storage-context@1.166.8': + resolution: {integrity: sha512-7N5aNVDpsPD8BH3xohA1XMldb2NnQer+qQ3sPv/qt4n8xtKlAAKy3u5Tz1L5ji0JsdLfvLdPdYLqC7egQvSaRQ==} + engines: {node: '>=22.12.0'} - '@sec-ant/readable-stream@0.4.1': - resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} + '@tanstack/store@0.9.2': + resolution: {integrity: sha512-K013lUJEFJK2ofFQ/hZKJUmCnpcV00ebLyOyFOWQvyQHUOZp/iYO84BM6aOGiV81JzwbX0APTVmW8YI7yiG5oA==} - '@sideway/address@4.1.5': - resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} + '@tanstack/virtual-core@3.13.22': + resolution: {integrity: sha512-isuUGKsc5TAPDoHSbWTbl1SCil54zOS2MiWz/9GCWHPUQOvNTQx8qJEWC7UWR0lShhbK0Lmkcf0SZYxvch7G3g==} - '@sideway/formula@3.0.1': - resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==} + '@tanstack/virtual-file-routes@1.161.4': + resolution: {integrity: sha512-42WoRePf8v690qG8yGRe/YOh+oHni9vUaUUfoqlS91U2scd3a5rkLtVsc6b7z60w3RogH0I00vdrC5AaeiZ18w==} + engines: {node: '>=20.19'} - '@sideway/pinpoint@2.0.0': - resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} + '@tanstack/vue-virtual@3.13.22': + resolution: {integrity: sha512-GiUwGKJADlCoTD7PaEfgSTAnQ9JW7KAmV98d5yFQf+vT2bSs52BPC22ZTXnNhe8PViTVqqRERNRKaWlut7tMPQ==} + peerDependencies: + vue: ^2.7.0 || ^3.0.0 - '@sindresorhus/is@7.0.1': - resolution: {integrity: sha512-QWLl2P+rsCJeofkDNIT3WFmb6NrRud1SUYW8dIhXK/46XFV8Q/g7Bsvib0Askb0reRLe+WYPeeE+l5cH7SlkuQ==} + '@tokenizer/inflate@0.4.1': + resolution: {integrity: sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==} engines: {node: '>=18'} - '@sindresorhus/merge-streams@2.3.0': - resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} - engines: {node: '>=18'} + '@tokenizer/token@0.3.0': + resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} - '@sindresorhus/merge-streams@4.0.0': - resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} - engines: {node: '>=18'} + '@toon-format/toon@0.9.0': + resolution: {integrity: sha512-BaMhGh1+/z8ceDrF2xL9Drd42hijbUJlivm/1goPR26RgCYsqlMkHbg48hx9a5UjZC7oZqxWPJ6ju5qvALi6Ag==} - '@speed-highlight/core@1.2.7': - resolution: {integrity: sha512-0dxmVj4gxg3Jg879kvFS/msl4s9F3T9UXC1InxgOf7t5NvcPD97u/WTA5vL/IxWHMn7qSxBozqrnnE2wvl1m8g==} + '@trpc/client@11.12.0': + resolution: {integrity: sha512-zTwFKQdE99pvNm7kXFdHo5xIQpGqpQJHtqVkT9o+i8h/0fbDOUBEEbFVICiMsNA+GiXskoaDRX2l+z6ir+Ug3w==} + peerDependencies: + '@trpc/server': 11.12.0 + typescript: '>=5.7.2' - '@swc/helpers@0.5.15': - resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + '@trpc/server@11.12.0': + resolution: {integrity: sha512-rpZnf5FUjNndE/AjGIy+FvEHR52iBd0u0wySqWCwXj67wraj3qCuBr5Opcf0Te/g67C/YztqceFkLoG0r4mp4Q==} + peerDependencies: + typescript: '>=5.7.2' - '@tanstack/virtual-core@3.13.2': - resolution: {integrity: sha512-Qzz4EgzMbO5gKrmqUondCjiHcuu4B1ftHb0pjCut661lXZdGoHeze9f/M8iwsK1t5LGR6aNuNGU7mxkowaW6RQ==} + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} - '@tanstack/vue-virtual@3.13.2': - resolution: {integrity: sha512-z4swzjdhzCh95n9dw9lTvw+t3iwSkYRlVkYkra3C9mul/m5fTzHR7KmtkwH4qXMTXGJUbngtC/bz2cHQIHkO8g==} - peerDependencies: - vue: ^2.7.0 || ^3.0.0 + '@types/aws-lambda@8.10.161': + resolution: {integrity: sha512-rUYdp+MQwSFocxIOcSsYSF3YYYC/uUpMbCY/mbO21vGqfrEYvNSoPyKYDj6RhXXpPfS0KstW9RwG3qXh9sL7FQ==} - '@tootallnate/once@2.0.0': - resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} - engines: {node: '>= 10'} + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} - '@trysound/sax@0.2.0': - resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} - engines: {node: '>=10.13.0'} + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} - '@types/archiver@6.0.3': - resolution: {integrity: sha512-a6wUll6k3zX6qs5KlxIggs1P1JcYJaTCx2gnlr+f0S1yd2DoaEwoIK10HmBaLnZwWneBz+JBm0dwcZu0zECBcQ==} + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - '@types/aws-lambda@8.10.147': - resolution: {integrity: sha512-nD0Z9fNIZcxYX5Mai2CTmFD7wX7UldCkW2ezCF8D1T5hdiLsnTWDGRpfRYntU6VjTdLQjOvyszru7I1c1oCQew==} + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} - '@types/body-parser@1.19.5': - resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} + '@types/body-parser@1.19.6': + resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} - '@types/caseless@0.12.5': - resolution: {integrity: sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==} + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} '@types/configstore@2.1.1': resolution: {integrity: sha512-YY+hm3afkDHeSM2rsFXxeZtu0garnusBWNG1+7MknmDWQHqcH2w21/xOU9arJUi8ch4qyFklidANLCu3ihhVwQ==} @@ -1687,35 +2898,26 @@ packages: '@types/connect@3.4.38': resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} - '@types/cors@2.8.17': - resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==} - '@types/debug@0.0.30': resolution: {integrity: sha512-orGL5LXERPYsLov6CWs3Fh6203+dXzJkR7OnddIr2514Hsecwc8xRpzCapshBbKFImCsvS/mk6+FWiN5LyZJAQ==} '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} - '@types/estree@1.0.6': - resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} - '@types/etag@1.8.3': - resolution: {integrity: sha512-QYHv9Yeh1ZYSMPQOoxY4XC4F1r+xRUiAriB303F4G6uBsT3KKX60DjiogvVv+2VISVDuJhcIzMdbjT+Bm938QQ==} + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - '@types/express-serve-static-core@4.19.6': - resolution: {integrity: sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==} + '@types/etag@1.8.4': + resolution: {integrity: sha512-f1z/UMth8gQ6636NBqhFmJ3zES7EuDcUnV6K1gl1osHp+85KPKX+VixYWUpqLkw1fftCagyHJjJOZjZkEi2rHw==} - '@types/express-serve-static-core@5.0.6': - resolution: {integrity: sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA==} + '@types/express-serve-static-core@5.1.1': + resolution: {integrity: sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==} - '@types/express@4.17.21': - resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} - - '@types/express@4.17.3': - resolution: {integrity: sha512-I8cGRJj3pyOLs/HndoP+25vOqhqWkAZsWMEmq1qXy/b/M3ppufecUwaK2/TVDVxcV61/iSdhykUjQQ2DLSrTdg==} - - '@types/fs-extra@11.0.4': - resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} + '@types/express@5.0.6': + resolution: {integrity: sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==} '@types/get-port@3.2.0': resolution: {integrity: sha512-TiNg8R1kjDde5Pub9F9vCwZA/BNW9HeXP5b9j7Qucqncy/McfPZ6xze/EyBdXS5FhMIGN6Fx3vg75l5KHy3V1Q==} @@ -1723,41 +2925,30 @@ packages: '@types/glob@5.0.38': resolution: {integrity: sha512-rTtf75rwyP9G2qO5yRpYtdJ6aU1QqEhWbtW55qEgquEDa6bXW0s2TWZfDm02GuppjEozOWG/F2UnPq5hAQb+gw==} + '@types/har-format@1.2.16': + resolution: {integrity: sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A==} + '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} - '@types/http-errors@2.0.4': - resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} - - '@types/http-proxy@1.17.16': - resolution: {integrity: sha512-sdWoUajOB1cd0A8cRRQ1cfyWNbmFKLAqBB89Y8x5iYyG/mkJHc0YUH8pdWBy2omi9qtCpiIgGjuwO0dQST2l5w==} + '@types/http-errors@2.0.5': + resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} - '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/http-proxy@1.17.17': + resolution: {integrity: sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==} - '@types/jsonfile@6.1.4': - resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} + '@types/jsesc@2.5.1': + resolution: {integrity: sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==} - '@types/jsonwebtoken@9.0.9': - resolution: {integrity: sha512-uoe+GxEuHbvy12OUQct2X9JenKM3qAscquYymuQN4fMWG9DBQtykrQEFcAbVACF7qaLw9BePSodUL0kquqBJpQ==} - - '@types/lodash@4.17.16': - resolution: {integrity: sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==} - - '@types/long@4.0.2': - resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==} - - '@types/mdast@3.0.15': - resolution: {integrity: sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==} + '@types/lodash@4.17.24': + resolution: {integrity: sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==} '@types/mdast@4.0.4': resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} - '@types/mime@1.3.5': - resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} - - '@types/minimatch@5.1.2': - resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} + '@types/minimatch@6.0.0': + resolution: {integrity: sha512-zmPitbQ8+6zNutpwgcQuLcsEpn/Cj54Kbn7L5pX0Os5kdWplB7xPgEh/g+SWOB/qmows2gpuCaPyduq8ZZRnxA==} + deprecated: This is a stub types definition. minimatch provides its own type definitions, so you do not need this installed. '@types/mkdirp@0.5.2': resolution: {integrity: sha512-U5icWpv7YnZYGsN4/cmh3WD2onMY0aJIiTE6+51TwJCttdHvtCYmkBNOobHlXwrJRL0nkH9jH4kD+1FAdMN4Tg==} @@ -1765,32 +2956,34 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - '@types/node-fetch@2.6.12': - resolution: {integrity: sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==} + '@types/node-fetch@2.6.13': + resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==} - '@types/node-forge@1.3.11': - resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} + '@types/node-forge@1.3.14': + resolution: {integrity: sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw==} - '@types/node@22.13.10': - resolution: {integrity: sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==} + '@types/node@24.12.0': + resolution: {integrity: sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==} + + '@types/node@25.5.0': + resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==} '@types/node@8.10.66': resolution: {integrity: sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==} - '@types/normalize-package-data@2.4.4': - resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} - - '@types/qs@6.9.18': - resolution: {integrity: sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==} + '@types/qs@6.15.0': + resolution: {integrity: sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow==} '@types/range-parser@1.2.7': resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} - '@types/readdir-glob@1.1.5': - resolution: {integrity: sha512-raiuEPUYqXu+nvtY2Pe8s8FEmZ3x5yAH4VkLdihcPdalvsHltomrRC9BzuStrJ9yk06470hS0Crw0f1pXqD+Hg==} + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + peerDependencies: + '@types/react': ^19.2.0 - '@types/request@2.48.12': - resolution: {integrity: sha512-G3sY+NpsA9jnwm0ixhAFQSJ3Q9JkpLZpJbI3GMv0mIAT0y3mRabYeINzal5WOChIiaTEGQYlHOKgkaM9EisWHw==} + '@types/react@19.2.14': + resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} '@types/resolve@1.20.2': resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} @@ -1798,180 +2991,189 @@ packages: '@types/rimraf@2.0.5': resolution: {integrity: sha512-YyP+VfeaqAyFmXoTh3HChxOQMyjByRMsHU7kc5KOJkSlXudhMhQIALbYV7rHh/l8d2lX3VUQzprrcAgWdRuU8g==} - '@types/semver@7.5.8': - resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} + '@types/semver@7.7.1': + resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==} - '@types/send@0.17.4': - resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} + '@types/send@1.2.1': + resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==} - '@types/serve-static@1.15.7': - resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==} + '@types/serve-static@2.2.0': + resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==} '@types/tmp@0.0.33': resolution: {integrity: sha512-gVC1InwyVrO326wbBZw+AO3u2vRXz/iRWq9jYhpG4W8LXyIgDv3ZmcLQ5Q4Gs+gFMyqx+viFoFT+l3p61QFCmQ==} - '@types/tough-cookie@4.0.5': - resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} - - '@types/unist@2.0.11': - resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} - '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} '@types/web-bluetooth@0.0.20': resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} + '@types/web-bluetooth@0.0.21': + resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} + '@types/xml2js@0.4.14': resolution: {integrity: sha512-4YnrRemBShWRO2QjvUin8ESA41rH+9nQGLUGZV/1IDhi3SL9OhdpNC/MrulTWuptXKwhx/aDxE7toV0f/ypIXQ==} - '@typescript-eslint/eslint-plugin@8.26.0': - resolution: {integrity: sha512-cLr1J6pe56zjKYajK6SSSre6nl1Gj6xDp1TY0trpgPzjVbgDwd09v2Ws37LABxzkicmUjhEeg/fAUjPJJB1v5Q==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260314.1': + resolution: {integrity: sha512-PlDvhms3QsLOkXNnCoQGJXjcZG7G5QMnhpSOmtO5toZ93VhU1qaUdvDlxtbacCYxGXcs6qZiJnGUgcedfqn5cg==} + cpu: [arm64] + os: [darwin] - '@typescript-eslint/parser@8.26.0': - resolution: {integrity: sha512-mNtXP9LTVBy14ZF3o7JG69gRPBK/2QWtQd0j0oH26HcY/foyJJau6pNUez7QrM5UHnSvwlQcJXKsk0I99B9pOA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' + '@typescript/native-preview-darwin-x64@7.0.0-dev.20260314.1': + resolution: {integrity: sha512-EEL6sN1kWor4yPCaowFdPOu/5o0puiudCLWTpDXzkbhFDR0sak/g+2VmtRuNiUi4JOKdJ6bJQKiXFrATAJWDYw==} + cpu: [x64] + os: [darwin] - '@typescript-eslint/scope-manager@8.26.0': - resolution: {integrity: sha512-E0ntLvsfPqnPwng8b8y4OGuzh/iIOm2z8U3S9zic2TeMLW61u5IH2Q1wu0oSTkfrSzwbDJIB/Lm8O3//8BWMPA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript/native-preview-linux-arm64@7.0.0-dev.20260314.1': + resolution: {integrity: sha512-qllNIMVM+kNH/ivL4AMelDs1C8J9NzUFzO6tmJ6hoXD5jUrvc38agcO+DnrXwrxR1Wd7mS7iDujAeSoZkeWWfQ==} + cpu: [arm64] + os: [linux] - '@typescript-eslint/type-utils@8.26.0': - resolution: {integrity: sha512-ruk0RNChLKz3zKGn2LwXuVoeBcUMh+jaqzN461uMMdxy5H9epZqIBtYj7UiPXRuOpaALXGbmRuZQhmwHhaS04Q==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' + '@typescript/native-preview-linux-arm@7.0.0-dev.20260314.1': + resolution: {integrity: sha512-7tahKAxuJvjVmtORpecEtWWJmYVRmYL3t3U+PXaFKwPOBmoa38zWjlmbrBHodTqfO5XSpCp9wUbWC3k83DsCsw==} + cpu: [arm] + os: [linux] - '@typescript-eslint/types@8.26.0': - resolution: {integrity: sha512-89B1eP3tnpr9A8L6PZlSjBvnJhWXtYfZhECqlBl1D9Lme9mHO6iWlsprBtVenQvY1HMhax1mWOjhtL3fh/u+pA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript/native-preview-linux-x64@7.0.0-dev.20260314.1': + resolution: {integrity: sha512-vdqd/swfZTN7EN85QON0e/2fpDbYNP6ZFPjBbZ78BISPy3nsv+DR0t5vAlfRB9wA86zpExfTgVJ4ZUnoUQpTkw==} + cpu: [x64] + os: [linux] - '@typescript-eslint/typescript-estree@8.26.0': - resolution: {integrity: sha512-tiJ1Hvy/V/oMVRTbEOIeemA2XoylimlDQ03CgPPNaHYZbpsc78Hmngnt+WXZfJX1pjQ711V7g0H7cSJThGYfPQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <5.9.0' + '@typescript/native-preview-win32-arm64@7.0.0-dev.20260314.1': + resolution: {integrity: sha512-ukLU9r2/H4oMIw8+JHfmraavREotyt9/5Z2X1F5EksefOvfb0Fpb6j6TWastQFZIFuAlvpr8tXHThq7rZwIdPg==} + cpu: [arm64] + os: [win32] - '@typescript-eslint/utils@8.26.0': - resolution: {integrity: sha512-2L2tU3FVwhvU14LndnQCA2frYC8JnPDVKyQtWFPf8IYFMt/ykEN1bPolNhNbCVgOmdzTlWdusCTKA/9nKrf8Ig==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' + '@typescript/native-preview-win32-x64@7.0.0-dev.20260314.1': + resolution: {integrity: sha512-kkl27prdWvxiRzS8n7/trlVrHTOrrY8AdGZgKnE07C4kUqk/FeIudp5DaOsYeFD9GWO32vUU7KXCfpFqvFrK3A==} + cpu: [x64] + os: [win32] + + '@typescript/native-preview@7.0.0-dev.20260314.1': + resolution: {integrity: sha512-XOVmR59UL6r2dmcdZD6SV4nhX5u4e34onMv7XSz9zKBp9mb8/v8kKPgGy9adp9at24FpAeBYNN5HKIViSeHtpQ==} + hasBin: true - '@typescript-eslint/visitor-keys@8.26.0': - resolution: {integrity: sha512-2z8JQJWAzPdDd51dRQ/oqIJxe99/hoLIqmf8RMCAJQtYDc535W/Jt2+RTP4bP0aKeBG1F65yjIZuczOXCmbWwg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typespec/ts-http-runtime@0.3.4': + resolution: {integrity: sha512-CI0NhTrz4EBaa0U+HaaUZrJhPoso8sG7ZFya8uQoBA57fjzrjRSv87ekCjLZOFExN+gXE/z0xuN2QfH4H2HrLQ==} + engines: {node: '>=20.0.0'} '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} - '@unhead/dom@1.11.20': - resolution: {integrity: sha512-jgfGYdOH+xHJF/j8gudjsYu3oIjFyXhCWcgKaw3vQnT616gSqyqnGQGOItL+BQtQZACKNISwIfx5PuOtztMKLA==} + '@unhead/vue@2.1.12': + resolution: {integrity: sha512-zEWqg0nZM8acpuTZE40wkeUl8AhIe0tU0OkilVi1D4fmVjACrwoh5HP6aNqJ8kUnKsoy6D+R3Vi/O+fmdNGO7g==} + peerDependencies: + vue: '>=3.5.18' - '@unhead/schema@1.11.20': - resolution: {integrity: sha512-0zWykKAaJdm+/Y7yi/Yds20PrUK7XabLe9c3IRcjnwYmSWY6z0Cr19VIs3ozCj8P+GhR+/TI2mwtGlueCEYouA==} + '@vercel/oidc@3.1.0': + resolution: {integrity: sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==} + engines: {node: '>= 20'} - '@unhead/shared@1.11.20': - resolution: {integrity: sha512-1MOrBkGgkUXS+sOKz/DBh4U20DNoITlJwpmvSInxEUNhghSNb56S0RnaHRq0iHkhrO/cDgz2zvfdlRpoPLGI3w==} + '@vitejs/plugin-react@5.2.0': + resolution: {integrity: sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^8.0.0-beta.18 - '@unhead/vue@1.11.20': - resolution: {integrity: sha512-sqQaLbwqY9TvLEGeq8Fd7+F2TIuV3nZ5ihVISHjWpAM3y7DwNWRU7NmT9+yYT+2/jw1Vjwdkv5/HvDnvCLrgmg==} + '@vitejs/plugin-rsc@0.5.21': + resolution: {integrity: sha512-uNayLT8IKvWoznvQyfwKuGiEFV28o7lxUDnw/Av36VCuGpDFZnMmvVCwR37gTvnSmnpul9V0tdJqY3tBKEaDqw==} peerDependencies: - vue: '>=2.7 || >=3' + react: '*' + react-dom: '*' + react-server-dom-webpack: '*' + vite: ^8.0.0-beta.18 + peerDependenciesMeta: + react-server-dom-webpack: + optional: true - '@vercel/nft@0.29.2': - resolution: {integrity: sha512-A/Si4mrTkQqJ6EXJKv5EYCDQ3NL6nJXxG8VGXePsaiQigsomHYQC9xSpX8qGk7AEZk4b1ssbYIqJ0ISQQ7bfcA==} - engines: {node: '>=18'} - hasBin: true + '@vitejs/plugin-vue@6.0.5': + resolution: {integrity: sha512-bL3AxKuQySfk1iGcBsQnoRVexTPJq0Z/ixFVM8OhVJAP6ZXXXLtM7NFKWhLl30Kg7uTBqIaPXbh+nuQCuBDedg==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^8.0.0-beta.18 + vue: ^3.2.25 - '@vitest/coverage-v8@3.0.8': - resolution: {integrity: sha512-y7SAKsQirsEJ2F8bulBck4DoluhI2EEgTimHd6EEUgJBGKy9tC25cpywh1MH4FvDGoG2Unt7+asVd1kj4qOSAw==} + '@vitest/coverage-v8@4.1.0': + resolution: {integrity: sha512-nDWulKeik2bL2Va/Wl4x7DLuTKAXa906iRFooIRPR+huHkcvp9QDkPQ2RJdmjOFrqOqvNfoSQLF68deE3xC3CQ==} peerDependencies: - '@vitest/browser': 3.0.8 - vitest: 3.0.8 + '@vitest/browser': 4.1.0 + vitest: 4.1.0 peerDependenciesMeta: '@vitest/browser': optional: true - '@vitest/expect@3.0.8': - resolution: {integrity: sha512-Xu6TTIavTvSSS6LZaA3EebWFr6tsoXPetOWNMOlc7LO88QVVBwq2oQWBoDiLCN6YTvNYsGSjqOO8CAdjom5DCQ==} + '@vitest/expect@4.1.0': + resolution: {integrity: sha512-EIxG7k4wlWweuCLG9Y5InKFwpMEOyrMb6ZJ1ihYu02LVj/bzUwn2VMU+13PinsjRW75XnITeFrQBMH5+dLvCDA==} - '@vitest/mocker@3.0.8': - resolution: {integrity: sha512-n3LjS7fcW1BCoF+zWZxG7/5XvuYH+lsFg+BDwwAz0arIwHQJFUEsKBQ0BLU49fCxuM/2HSeBPHQD8WjgrxMfow==} + '@vitest/mocker@4.1.0': + resolution: {integrity: sha512-evxREh+Hork43+Y4IOhTo+h5lGmVRyjqI739Rz4RlUPqwrkFFDF6EMvOOYjTx4E8Tl6gyCLRL8Mu7Ry12a13Tw==} peerDependencies: msw: ^2.4.9 - vite: ^5.0.0 || ^6.0.0 + vite: ^8.0.0-beta.18 peerDependenciesMeta: msw: optional: true vite: optional: true - '@vitest/pretty-format@3.0.8': - resolution: {integrity: sha512-BNqwbEyitFhzYMYHUVbIvepOyeQOSFA/NeJMIP9enMntkkxLgOcgABH6fjyXG85ipTgvero6noreavGIqfJcIg==} + '@vitest/pretty-format@4.1.0': + resolution: {integrity: sha512-3RZLZlh88Ib0J7NQTRATfc/3ZPOnSUn2uDBUoGNn5T36+bALixmzphN26OUD3LRXWkJu4H0s5vvUeqBiw+kS0A==} - '@vitest/runner@3.0.8': - resolution: {integrity: sha512-c7UUw6gEcOzI8fih+uaAXS5DwjlBaCJUo7KJ4VvJcjL95+DSR1kova2hFuRt3w41KZEFcOEiq098KkyrjXeM5w==} + '@vitest/runner@4.1.0': + resolution: {integrity: sha512-Duvx2OzQ7d6OjchL+trw+aSrb9idh7pnNfxrklo14p3zmNL4qPCDeIJAK+eBKYjkIwG96Bc6vYuxhqDXQOWpoQ==} - '@vitest/snapshot@3.0.8': - resolution: {integrity: sha512-x8IlMGSEMugakInj44nUrLSILh/zy1f2/BgH0UeHpNyOocG18M9CWVIFBaXPt8TrqVZWmcPjwfG/ht5tnpba8A==} + '@vitest/snapshot@4.1.0': + resolution: {integrity: sha512-0Vy9euT1kgsnj1CHttwi9i9o+4rRLEaPRSOJ5gyv579GJkNpgJK+B4HSv/rAWixx2wdAFci1X4CEPjiu2bXIMg==} - '@vitest/spy@3.0.8': - resolution: {integrity: sha512-MR+PzJa+22vFKYb934CejhR4BeRpMSoxkvNoDit68GQxRLSf11aT6CTj3XaqUU9rxgWJFnqicN/wxw6yBRkI1Q==} + '@vitest/spy@4.1.0': + resolution: {integrity: sha512-pz77k+PgNpyMDv2FV6qmk5ZVau6c3R8HC8v342T2xlFxQKTrSeYw9waIJG8KgV9fFwAtTu4ceRzMivPTH6wSxw==} - '@vitest/utils@3.0.8': - resolution: {integrity: sha512-nkBC3aEhfX2PdtQI/QwAWp8qZWwzASsU4Npbcd5RdMPBSSLCpkZp52P3xku3s3uA0HIEhGvEcF8rNkBsz9dQ4Q==} + '@vitest/utils@4.1.0': + resolution: {integrity: sha512-XfPXT6a8TZY3dcGY8EdwsBulFCIw+BeeX0RZn2x/BtiY/75YGh8FeWGG8QISN/WhaqSrE2OrlDgtF8q5uhOTmw==} - '@vue/compiler-core@3.5.13': - resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==} + '@vue/compiler-core@3.5.30': + resolution: {integrity: sha512-s3DfdZkcu/qExZ+td75015ljzHc6vE+30cFMGRPROYjqkroYI5NV2X1yAMX9UeyBNWB9MxCfPcsjpLS11nzkkw==} - '@vue/compiler-dom@3.5.13': - resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==} + '@vue/compiler-dom@3.5.30': + resolution: {integrity: sha512-eCFYESUEVYHhiMuK4SQTldO3RYxyMR/UQL4KdGD1Yrkfdx4m/HYuZ9jSfPdA+nWJY34VWndiYdW/wZXyiPEB9g==} - '@vue/compiler-sfc@3.5.13': - resolution: {integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==} + '@vue/compiler-sfc@3.5.30': + resolution: {integrity: sha512-LqmFPDn89dtU9vI3wHJnwaV6GfTRD87AjWpTWpyrdVOObVtjIuSeZr181z5C4PmVx/V3j2p+0f7edFKGRMpQ5A==} - '@vue/compiler-ssr@3.5.13': - resolution: {integrity: sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==} + '@vue/compiler-ssr@3.5.30': + resolution: {integrity: sha512-NsYK6OMTnx109PSL2IAyf62JP6EUdk4Dmj6AkWcJGBvN0dQoMYtVekAmdqgTtWQgEJo+Okstbf/1p7qZr5H+bA==} '@vue/devtools-api@6.6.4': resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} - '@vue/reactivity@3.5.13': - resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==} + '@vue/reactivity@3.5.30': + resolution: {integrity: sha512-179YNgKATuwj9gB+66snskRDOitDiuOZqkYia7mHKJaidOMo/WJxHKF8DuGc4V4XbYTJANlfEKb0yxTQotnx4Q==} - '@vue/runtime-core@3.5.13': - resolution: {integrity: sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==} + '@vue/runtime-core@3.5.30': + resolution: {integrity: sha512-e0Z+8PQsUTdwV8TtEsLzUM7SzC7lQwYKePydb7K2ZnmS6jjND+WJXkmmfh/swYzRyfP1EY3fpdesyYoymCzYfg==} - '@vue/runtime-dom@3.5.13': - resolution: {integrity: sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==} + '@vue/runtime-dom@3.5.30': + resolution: {integrity: sha512-2UIGakjU4WSQ0T4iwDEW0W7vQj6n7AFn7taqZ9Cvm0Q/RA2FFOziLESrDL4GmtI1wV3jXg5nMoJSYO66egDUBw==} - '@vue/server-renderer@3.5.13': - resolution: {integrity: sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==} + '@vue/server-renderer@3.5.30': + resolution: {integrity: sha512-v+R34icapydRwbZRD0sXwtHqrQJv38JuMB4JxbOxd8NEpGLny7cncMp53W9UH/zo4j8eDHjQ1dEJXwzFQknjtQ==} peerDependencies: - vue: 3.5.13 + vue: 3.5.30 - '@vue/shared@3.5.13': - resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==} + '@vue/shared@3.5.30': + resolution: {integrity: sha512-YXgQ7JjaO18NeK2K9VTbDHaFy62WrObMa6XERNfNOkAhD1F1oDSf3ZJ7K6GqabZ0BvSDHajp8qfS5Sa2I9n8uQ==} '@vueuse/core@10.11.1': resolution: {integrity: sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==} - '@vueuse/core@11.3.0': - resolution: {integrity: sha512-7OC4Rl1f9G8IT6rUfi9JrKiXy4bfmHhZ5x2Ceojy0jnd3mHNEvV4JaRygH362ror6/NZ+Nl+n13LPzGiPN8cKA==} + '@vueuse/core@13.9.0': + resolution: {integrity: sha512-ts3regBQyURfCE2BcytLqzm8+MmLlo5Ln/KLoxDVcsZ2gzIwVNnQpQOL/UKV8alUqjSZOlpFZcRNsLRqj+OzyA==} + peerDependencies: + vue: ^3.5.0 - '@vueuse/integrations@11.3.0': - resolution: {integrity: sha512-5fzRl0apQWrDezmobchoiGTkGw238VWESxZHazfhP3RM7pDSiyXy18QbfYkILoYNTd23HPAfQTJpkUc5QbkwTw==} + '@vueuse/integrations@13.9.0': + resolution: {integrity: sha512-SDobKBbPIOe0cVL7QxMzGkuUGHvWTdihi9zOrrWaWUgFKe15cwEcwfWmgrcNzjT6kHnNmWuTajPHoIzUjYNYYQ==} peerDependencies: async-validator: ^4 axios: ^1 @@ -1984,7 +3186,8 @@ packages: nprogress: ^0.2 qrcode: ^1.5 sortablejs: ^1 - universal-cookie: ^7 + universal-cookie: ^7 || ^8 + vue: ^3.5.0 peerDependenciesMeta: async-validator: optional: true @@ -2014,48 +3217,26 @@ packages: '@vueuse/metadata@10.11.1': resolution: {integrity: sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==} - '@vueuse/metadata@11.3.0': - resolution: {integrity: sha512-pwDnDspTqtTo2HwfLw4Rp6yywuuBdYnPYDq+mO38ZYKGebCUQC/nVj/PXSiK9HX5otxLz8Fn7ECPbjiRz2CC3g==} + '@vueuse/metadata@13.9.0': + resolution: {integrity: sha512-1AFRvuiGphfF7yWixZa0KwjYH8ulyjDCC0aFgrGRz8+P4kvDFSdXLVfTk5xAN9wEuD1J6z4/myMoYbnHoX07zg==} '@vueuse/shared@10.11.1': resolution: {integrity: sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==} - '@vueuse/shared@11.3.0': - resolution: {integrity: sha512-P8gSSWQeucH5821ek2mn/ciCk+MS/zoRKqdQIM3bHq6p7GXDAJLmnRRKmF5F65sAVJIfzQlwR3aDzwCn10s8hA==} - - abbrev@3.0.0: - resolution: {integrity: sha512-+/kfrslGQ7TNV2ecmQwMJj/B65g5KVq1/L3SGVZ3tCYGqlzFuFCGBZJtMP99wH3NpEUyAjn0zPdPUg0D+DwrOA==} - engines: {node: ^18.17.0 || >=20.5.0} - - abort-controller@3.0.0: - resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} - engines: {node: '>=6.5'} - - accepts@1.3.8: - resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} - engines: {node: '>= 0.6'} - - acorn-import-attributes@1.9.5: - resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} + '@vueuse/shared@13.9.0': + resolution: {integrity: sha512-e89uuTLMh0U5cZ9iDpEI2senqPGfbPRTHM/0AaQkcxnpqjkZqDYP8rpfm7edOz8s+pOCOROEy1PIveSW8+fL5g==} peerDependencies: - acorn: ^8 + vue: ^3.5.0 - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - - acorn-walk@8.3.2: - resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} - engines: {node: '>=0.4.0'} + abstract-logging@2.0.1: + resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} - acorn@8.14.0: - resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} - engines: {node: '>=0.4.0'} - hasBin: true + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} - acorn@8.14.1: - resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==} + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} engines: {node: '>=0.4.0'} hasBin: true @@ -2063,14 +3244,16 @@ packages: resolution: {integrity: sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==} engines: {node: '>=12.0'} - agent-base@6.0.2: - resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} - engines: {node: '>= 6.0.0'} - - agent-base@7.1.3: - resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} + ai@6.0.33: + resolution: {integrity: sha512-bVokbmy2E2QF6Efl+5hOJx5MRWoacZ/CZY/y1E+VcewknvGlgaiCzMu8Xgddz6ArFJjiMFNUPHKxAhIePE4rmg==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + ajv-draft-04@1.0.0: resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} peerDependencies: @@ -2087,19 +3270,12 @@ packages: ajv: optional: true - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - - ajv@8.17.1: - resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + ajv@8.18.0: + resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} ansi-align@3.0.1: resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} - ansi-colors@4.1.3: - resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} - engines: {node: '>=6'} - ansi-escapes@4.3.2: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} @@ -2108,18 +3284,22 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - ansi-regex@6.1.0: - resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} engines: {node: '>=12'} ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} - ansi-styles@6.2.1: - resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} + ansis@4.2.0: + resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} + engines: {node: '>=14'} + anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} @@ -2127,70 +3307,82 @@ packages: application-config-path@0.1.1: resolution: {integrity: sha512-zy9cHePtMP0YhwG+CfHm0bgwdnga2X3gZexpdCwEj//dpb+TKajtiC8REEUJUSq6Ab4f9cgNy2l8ObXzCXFkEw==} - archiver-utils@5.0.2: - resolution: {integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==} - engines: {node: '>= 14'} - - archiver@7.0.1: - resolution: {integrity: sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==} - engines: {node: '>= 14'} - argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - aria-hidden@1.2.4: - resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==} + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} engines: {node: '>=10'} - array-flatten@1.1.1: - resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} - - arrify@2.0.1: - resolution: {integrity: sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==} - engines: {node: '>=8'} - - as-table@1.0.55: - resolution: {integrity: sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==} + array-find-index@1.0.2: + resolution: {integrity: sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==} + engines: {node: '>=0.10.0'} assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} - async-listen@3.0.1: - resolution: {integrity: sha512-cWMaNwUJnf37C/S5TfCkk/15MwbPRwVYALA2jtjkbHjCmAPiDXyNJy2q3p1KAZzDLHAWyarUWSujUoHR4pEgrA==} - engines: {node: '>= 14'} + ast-kit@3.0.0-beta.1: + resolution: {integrity: sha512-trmleAnZ2PxN/loHWVhhx1qeOHSRXq4TDsBBxq3GqeJitfk3+jTQ+v/C1km/KYq9M7wKqCewMh+/NAvVH7m+bw==} + engines: {node: '>=20.19.0'} - async-retry@1.3.3: - resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==} + ast-types@0.16.1: + resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} + engines: {node: '>=4'} - async-sema@3.1.1: - resolution: {integrity: sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==} + ast-v8-to-istanbul@1.0.0: + resolution: {integrity: sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==} - async@3.2.6: - resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + async-listen@3.0.1: + resolution: {integrity: sha512-cWMaNwUJnf37C/S5TfCkk/15MwbPRwVYALA2jtjkbHjCmAPiDXyNJy2q3p1KAZzDLHAWyarUWSujUoHR4pEgrA==} + engines: {node: '>= 14'} asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - atomically@2.0.3: - resolution: {integrity: sha512-kU6FmrwZ3Lx7/7y3hPS5QnbJfaohcIul5fGqf7ok+4KklIEk9tJ0C2IQPdacSbVUWv6zVHXEBWoWd6NrVMT7Cw==} + atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} - automd@0.4.0: - resolution: {integrity: sha512-zU63NNzqdaUoFMUgw6srqFem4p+FiKV+wsavIsaT8NDyJK9H7SsElWv/+3kiCvJp71Ukjau9Roz0kF1hCy0cYA==} - hasBin: true + atomically@2.1.1: + resolution: {integrity: sha512-P4w9o2dqARji6P7MHprklbfiArZAWvo07yW7qs3pdljb3BWr12FIB7W+p0zJiuiVsUpRO0iZn1kFFcpPegg0tQ==} - autoprefixer@10.4.20: - resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==} - engines: {node: ^10 || ^12 || >=14} + automd@0.4.3: + resolution: {integrity: sha512-5WJNEiaNpFm8h0OmQzhnESthadUQhJwQfka/TmmJpMudZ8qU9MZao9p0G1g7WYA9pVTz6FMMOSvxnfQ9g8q9vQ==} hasBin: true + + avvio@9.2.0: + resolution: {integrity: sha512-2t/sy01ArdHHE0vRH5Hsay+RtCZt3dLPji7W7/MMOCEgze5b7SNDC4j5H6FnVgPkI1MTNFGzHdHrVXDDl7QSSQ==} + + axios-retry@4.5.0: + resolution: {integrity: sha512-aR99oXhpEDGo0UuAlYcn2iGRds30k366Zfa05XWScR9QaQD4JYiP3/1Qt1u7YlefUOK+cn0CcwoL1oefavQUlQ==} + peerDependencies: + axios: 0.x || 1.x + + axios@1.13.6: + resolution: {integrity: sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==} + + babel-dead-code-elimination@1.0.12: + resolution: {integrity: sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==} + + babel-plugin-jsx-dom-expressions@0.40.5: + resolution: {integrity: sha512-8TFKemVLDYezqqv4mWz+PhRrkryTzivTGu0twyLrOkVZ0P63COx2Y04eVsUjFlwSOXui1z3P3Pn209dokWnirg==} peerDependencies: - postcss: ^8.1.0 + '@babel/core': ^7.20.12 - axios@1.8.2: - resolution: {integrity: sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg==} + babel-plugin-transform-hook-names@1.0.2: + resolution: {integrity: sha512-5gafyjyyBTTdX/tQQ0hRgu4AhNHG/hqWi0ZZmg2xvs2FgRkJXzDNKBZCyoYqgFkovfDrgM8OoKg8karoUvWeCw==} + peerDependencies: + '@babel/core': ^7.12.10 - b4a@1.6.7: - resolution: {integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==} + babel-preset-solid@1.9.10: + resolution: {integrity: sha512-HCelrgua/Y+kqO8RyL04JBWS/cVdrtUv/h45GntgQY+cJl4eBcKkCDV3TdMjtKx1nXwRaR9QXslM/Npm1dxdZQ==} + peerDependencies: + '@babel/core': ^7.0.0 + solid-js: ^1.9.10 + peerDependenciesMeta: + solid-js: + optional: true bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} @@ -2198,24 +3390,34 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - bare-events@2.5.4: - resolution: {integrity: sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - bignumber.js@9.1.2: - resolution: {integrity: sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==} + baseline-browser-mapping@2.10.8: + resolution: {integrity: sha512-PCLz/LXGBsNTErbtB6i5u4eLpHeMfi93aUv5duMmj6caNu6IphS4q6UevDnL36sZQv9lrP11dbPKGMaXPwMKfQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} - bindings@1.5.0: - resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + birpc@4.0.0: + resolution: {integrity: sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==} bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - body-parser@1.20.3: - resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + blake3-wasm@2.1.5: + resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} + + body-parser@2.2.2: + resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} + engines: {node: '>=18'} boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} @@ -2224,41 +3426,31 @@ packages: resolution: {integrity: sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==} engines: {node: '>=18'} - brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} - brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + brace-expansion@5.0.4: + resolution: {integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==} + engines: {node: 18 || 20 || >=22} braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - browserslist@4.24.4: - resolution: {integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==} + browserslist@4.28.1: + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true - buffer-crc32@1.0.0: - resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} - engines: {node: '>=8.0.0'} - buffer-equal-constant-time@1.0.1: resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} - buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - buffer@6.0.3: - resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - - builtin-modules@3.3.0: - resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} - engines: {node: '>=6'} - bundle-name@4.1.0: resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} engines: {node: '>=18'} @@ -2267,17 +3459,37 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} - c12@3.0.2: - resolution: {integrity: sha512-6Tzk1/TNeI3WBPpK0j/Ss4+gPj3PUJYbWl/MWDJBThFvwNGNkXtd7Cz8BJtD4aRwoGHtzQD0SnxamgUiBH0/Nw==} + c12@3.3.3: + resolution: {integrity: sha512-750hTRvgBy5kcMNPdh95Qo+XUBeGo8C7nsKSmedDmaQI+E0r82DwHeM6vBewDe4rGFbnxoa4V9pw+sPh5+Iz8Q==} peerDependencies: - magicast: ^0.3.5 + magicast: '*' peerDependenciesMeta: magicast: optional: true - cac@6.7.14: - resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} - engines: {node: '>=8'} + c12@4.0.0-beta.3: + resolution: {integrity: sha512-15pHxeM4kKKnF1zPgvXq/ETPhf9DRLGg0Id3GAyQhQqYxt8WkUCbo0NipHjQUUNC5VPP8TQA32pGPDUZmAi/3g==} + peerDependencies: + chokidar: ^5 + dotenv: '*' + giget: '*' + jiti: '*' + magicast: '*' + peerDependenciesMeta: + chokidar: + optional: true + dotenv: + optional: true + giget: + optional: true + jiti: + optional: true + magicast: + optional: true + + cac@7.0.0: + resolution: {integrity: sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==} + engines: {node: '>=20.19.0'} call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} @@ -2287,88 +3499,71 @@ packages: resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} engines: {node: '>= 0.4'} - callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - camelcase@8.0.0: resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==} engines: {node: '>=16'} - caniuse-api@3.0.0: - resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} - - caniuse-lite@1.0.30001702: - resolution: {integrity: sha512-LoPe/D7zioC0REI5W73PeR1e1MLCipRGq/VkovJnd6Df+QVqT+vT33OXCp8QUd7kA7RZrHWxb1B36OQKI/0gOA==} + caniuse-lite@1.0.30001778: + resolution: {integrity: sha512-PN7uxFL+ExFJO61aVmP1aIEG4i9whQd4eoSCebav62UwDyp5OHh06zN4jqKSMePVgxHifCw1QJxdRkA1Pisekg==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} - chai@5.2.0: - resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==} - engines: {node: '>=12'} + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} - chalk@5.4.1: - resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - change-case@5.4.4: - resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} - - changelogen@0.6.1: - resolution: {integrity: sha512-rTw2bZgiEHMgyYzWFMH+qTMFOSpCf4qwmd8LyxLDUKCtL4T/7O7978tPPtKYpjiFbPoHG64y4ugdF0Mt/l+lQg==} + changelogen@0.6.2: + resolution: {integrity: sha512-QtC7+r9BxoUm+XDAwhLbz3CgU134J1ytfE3iCpLpA4KFzX2P1e6s21RrWDwUBzfx66b1Rv+6lOA2nS2btprd+A==} hasBin: true character-entities-html4@2.1.0: resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} - character-entities-legacy@1.1.4: - resolution: {integrity: sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==} - character-entities-legacy@3.0.0: resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} - character-entities@1.2.4: - resolution: {integrity: sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==} - character-entities@2.0.2: resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} - character-reference-invalid@1.1.4: - resolution: {integrity: sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==} - charenc@0.0.2: resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} - check-error@2.1.1: - resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} - engines: {node: '>= 16'} + cheerio-select@2.1.0: + resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} + + cheerio@1.2.0: + resolution: {integrity: sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==} + engines: {node: '>=20.18.1'} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} - chokidar@4.0.3: - resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} - engines: {node: '>= 14.16.0'} + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} - chownr@3.0.0: - resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} - engines: {node: '>=18'} - - ci-info@4.1.0: - resolution: {integrity: sha512-HutrvTNsF48wnxkzERIXOe5/mlcfFcbfCmwcg6CJnizbSue78AbDt+1cgl26zwn61WFxhcPykPfZrbqjGmBb4A==} + ci-info@4.4.0: + resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} engines: {node: '>=8'} citty@0.1.6: resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} - clean-regexp@1.0.0: - resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} - engines: {node: '>=4'} + citty@0.2.1: + resolution: {integrity: sha512-kEV95lFBhQgtogAPlQfJJ0WGVSokvLr/UEoFPiKKOXF7pl98HfUVUD0ejsuTCld/9xH9vogSywZ5KqHzXrZpqg==} cli-boxes@3.0.0: resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} @@ -2386,10 +3581,6 @@ packages: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} - clipboardy@4.0.0: - resolution: {integrity: sha512-5mOlNS0mhX0707P2I0aZ2V/cmHUEO/fL7VFLqszkhUsxt7RwnmrInf/eEQKlf5GzvYeHIjT+Ov1HRfNmymlG0w==} - engines: {node: '>=18'} - cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -2402,13 +3593,6 @@ packages: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} - cluster-key-slot@1.1.2: - resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} - engines: {node: '>=0.10.0'} - - codemirror@6.0.1: - resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==} - color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -2416,12 +3600,6 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - colord@2.9.3: - resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} - - colorette@1.4.0: - resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} - combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -2435,23 +3613,18 @@ packages: commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - commander@7.2.0: - resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} - engines: {node: '>= 10'} - commander@9.5.0: resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} engines: {node: ^12.20.0 || >=14} + commenting@1.1.0: + resolution: {integrity: sha512-YeNK4tavZwtH7jEgK1ZINXzLKm6DZdEMfsaaieOsCAN0S8vsY7UeuO3Q7d/M018EFgE+IeUAuBOKkFccBZsUZA==} + commondir@1.0.1: resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} - compatx@0.1.8: - resolution: {integrity: sha512-jcbsEAR81Bt5s1qOFymBufmCbXCXbk0Ql+K5ouj6gCyx2yHlu6AgmGIi9HxfKixpUDO5bCFJUHQ5uM6ecbTebw==} - - compress-commons@6.0.2: - resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==} - engines: {node: '>= 14'} + compatx@0.2.0: + resolution: {integrity: sha512-6gLRNt4ygsi5NyMVhceOCFv14CIdDFN7fQjX1U4+47qVE/+kjPoXMK65KWK+dWxmFzMTuKazoQ9sch6pM0p5oA==} concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -2464,23 +3637,23 @@ packages: confbox@0.1.8: resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} - confbox@0.2.1: - resolution: {integrity: sha512-hkT3yDPFbs95mNCy1+7qNKC6Pro+/ibzYxtM2iqEigpf0sVw+bg4Zh9/snjsBcf990vfIsg5+1U7VyiyBb3etg==} + confbox@0.2.4: + resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} config-chain@1.1.13: resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} - configstore@7.0.0: - resolution: {integrity: sha512-yk7/5PN5im4qwz0WFZW3PXnzHgPu9mX29Y8uZ3aefe2lBPC1FYttWZRcaW9fKkT0pBCJyuQ2HfbmPVaODi9jcQ==} + configstore@7.1.0: + resolution: {integrity: sha512-N4oog6YJWbR9kGyXvS7jEykLDXIE2C0ILYqNBZBp9iwiJpoCBWYsuAdW6PPFn6w06jjnC+3JstVvWHO4cZqvRg==} engines: {node: '>=18'} - consola@3.4.0: - resolution: {integrity: sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==} + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} - content-disposition@0.5.4: - resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} - engines: {node: '>= 0.6'} + content-disposition@1.0.1: + resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} + engines: {node: '>=18'} content-type@1.0.5: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} @@ -2493,113 +3666,63 @@ packages: resolution: {integrity: sha512-7V+KqSvMiHp8yWDuwfww06XleMWVVB9b9tURBx+G7UTADuo5hYPuowKloz4OzOqbPezxgo+fdQ1522WzPG4OeA==} engines: {node: '>=8'} - cookie-es@1.2.2: - resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==} + convert-hrtime@5.0.0: + resolution: {integrity: sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==} + engines: {node: '>=12'} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} cookie-es@2.0.0: resolution: {integrity: sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==} - cookie-signature@1.0.6: - resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} cookie@0.5.0: resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} engines: {node: '>= 0.6'} - cookie@0.7.1: - resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} - cookie@1.0.2: - resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} engines: {node: '>=18'} - core-js-compat@3.41.0: - resolution: {integrity: sha512-RFsU9LySVue9RTwdDVX/T0e2Y6jRYWXERKElIjpuEOEnxaXffI0X7RUwVzfYLfzuLXSNJDYoRYUAmRUcyln20A==} - - core-util-is@1.0.3: - resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - - cors@2.8.5: - resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} - engines: {node: '>= 0.10'} - - crc-32@1.2.2: - resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} - engines: {node: '>=0.8'} - hasBin: true - - crc32-stream@6.0.0: - resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==} - engines: {node: '>= 14'} - crelt@1.0.6: resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} - croner@9.0.0: - resolution: {integrity: sha512-onMB0OkDjkXunhdW9htFjEhqrD54+M94i6ackoUkjHKbRnXdyEyKRelp4nJ1kAz32+s27jP1FsebpJCVl0BsvA==} + croner@10.0.1: + resolution: {integrity: sha512-ixNtAJndqh173VQ4KodSdJEI6nuioBWI0V1ITNKhZZsO0pEMoDxz539T4FTTbSZ/xIOSuDnzxLVRqBVSvPNE2g==} engines: {node: '>=18.0'} cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - crossws@0.3.4: - resolution: {integrity: sha512-uj0O1ETYX1Bh6uSgktfPvwDiPYGQ3aI4qVsaC/LWpkIzGj1nUYm5FK3K+t11oOlpN01lGbprFCH4wBlKdJjVgw==} + crossws@0.4.4: + resolution: {integrity: sha512-w6c4OdpRNnudVmcgr7brb/+/HmYjMQvYToO/oTrprTwxRUiom3LYWU1PMWuD006okbUWpII1Ea9/+kwpUfmyRg==} + peerDependencies: + srvx: '>=0.7.1' + peerDependenciesMeta: + srvx: + optional: true crypt@0.0.2: resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} - css-declaration-sorter@7.2.0: - resolution: {integrity: sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==} - engines: {node: ^14 || ^16 || >=18} - peerDependencies: - postcss: ^8.0.9 - - css-select@5.1.0: - resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} - - css-tree@2.2.1: - resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} - engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} - - css-tree@2.3.1: - resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} - engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} - - css-what@6.1.0: - resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} - engines: {node: '>= 6'} - - cssesc@3.0.0: - resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} - engines: {node: '>=4'} - hasBin: true - - cssnano-preset-default@7.0.6: - resolution: {integrity: sha512-ZzrgYupYxEvdGGuqL+JKOY70s7+saoNlHSCK/OGn1vB2pQK8KSET8jvenzItcY+kA7NoWvfbb/YhlzuzNKjOhQ==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - cssnano-utils@5.0.0: - resolution: {integrity: sha512-Uij0Xdxc24L6SirFr25MlwC2rCFX6scyUmuKpzI+JQ7cyqDEwD42fJ0xfB3yLfOnRDU5LKGgjQ9FA6LYh76GWQ==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - cssnano@7.0.6: - resolution: {integrity: sha512-54woqx8SCbp8HwvNZYn68ZFAepuouZW4lTwiMVnBErM3VkO7/Sd4oTOt3Zz3bPx3kxQ36aISppyXj2Md4lg8bw==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 + css-select@5.2.2: + resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} - csso@5.0.5: - resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} - engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + css-what@6.2.2: + resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} + engines: {node: '>= 6'} - csstype@3.1.3: - resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} cva@1.0.0-beta.2: resolution: {integrity: sha512-dqcOFe247I5pKxfuzqfq3seLL5iMYsTgo40Uw7+pKZAntPgFtR7Tmy59P5IVIq/XgB0NQWoIvYDt9TwHkuK8Cg==} @@ -2609,15 +3732,20 @@ packages: typescript: optional: true - data-uri-to-buffer@2.0.2: - resolution: {integrity: sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==} + cva@1.0.0-beta.4: + resolution: {integrity: sha512-F/JS9hScapq4DBVQXcK85l9U91M6ePeXoBMSp7vypzShoefUBxjQTo3g3935PUHgQd+IW77DjbPRIxugy4/GCQ==} + peerDependencies: + typescript: '>= 4.5.5' + peerDependenciesMeta: + typescript: + optional: true date-fns@2.30.0: resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} engines: {node: '>=0.11'} - db0@0.3.1: - resolution: {integrity: sha512-3RogPLE2LLq6t4YiFCREyl572aBjkfMvfwPyN51df00TbPbryL3XqBYuJ/j6mgPssPK8AKfYdLxizaO5UG10sA==} + db0@0.3.4: + resolution: {integrity: sha512-RiXXi4WaNzPTHEOu8UPQKMooIbqOEyqA1t7Z6MsdxSCeb8iUC9ko3LcmsLmeUt2SM5bctfArZKkRQggKZz7JNw==} peerDependencies: '@electric-sql/pglite': '*' '@libsql/client': '*' @@ -2655,8 +3783,8 @@ packages: supports-color: optional: true - debug@4.4.0: - resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -2664,34 +3792,27 @@ packages: supports-color: optional: true - decode-named-character-reference@1.1.0: - resolution: {integrity: sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w==} + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} decompress-response@6.0.0: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} engines: {node: '>=10'} - deep-eql@5.0.2: - resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} - engines: {node: '>=6'} - deep-extend@0.6.0: resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} engines: {node: '>=4.0.0'} - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} - default-browser-id@5.0.0: - resolution: {integrity: sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==} + default-browser-id@5.0.1: + resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} engines: {node: '>=18'} - default-browser@5.2.1: - resolution: {integrity: sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==} + default-browser@5.5.0: + resolution: {integrity: sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==} engines: {node: '>=18'} default-gateway@6.0.3: @@ -2716,10 +3837,6 @@ packages: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} - denque@2.1.0: - resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} - engines: {node: '>=0.10'} - depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -2728,24 +3845,19 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} - destr@2.0.3: - resolution: {integrity: sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ==} + destr@2.0.5: + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} destroy@1.2.0: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - detect-libc@1.0.3: - resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} - engines: {node: '>=0.10'} - hasBin: true - - detect-libc@2.0.3: - resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} - devcert@1.2.2: - resolution: {integrity: sha512-UsLqvtJGPiGwsIZnJINUnFYaWgK7CroreGRndWHZkRD58tPFr3pVbbSyHR8lbh41+azR4jKvuNZ+eCoBZGA5kA==} + devcert@1.2.3: + resolution: {integrity: sha512-vmLo0hDNHmZ47HED1ZiouJ7cAcamL8HY7qa9YdmCBkXxHEVtdDgT9pN/Xy3ZkcF3pFjF0sqq8WMV93HF2nmHHw==} devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} @@ -2754,6 +3866,10 @@ packages: resolution: {integrity: sha512-+yW4SNY7W2DOWe2Jx5H4c2qMTFbLGM6wIyoDPkAPy66X+sD1KfYjBPAIWPVsYqMxelflaMQCloZDudELIPhLqA==} engines: {node: ^18.12.0 || >=20.9.0} + diff@8.0.3: + resolution: {integrity: sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==} + engines: {node: '>=0.3.1'} + discontinuous-range@1.0.0: resolution: {integrity: sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==} @@ -2767,17 +3883,37 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} + dompurify@3.1.7: + resolution: {integrity: sha512-VaTstWtsneJY8xzy7DekmYWEOZcmzIe3Qb3zPd4STve1OBTa+e+WmS1ITQec1fZYXI3HCsOZZiSMpG6oxoWMWQ==} + domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + dot-prop@10.1.0: + resolution: {integrity: sha512-MVUtAugQMOff5RnBy2d9N31iG0lNwg1qAoAOn7pOK5wf94WIaE3My2p3uwTQuvS2AcqchkcR3bHByjaM0mmi7Q==} + engines: {node: '>=20'} + dot-prop@9.0.0: resolution: {integrity: sha512-1gxPBJpI/pcjQhKgIU91II6Wkay+dLcN3M6rf2uwP8hRur3HtQXjVrdAK3sjC0piaEuxzMwjXChcETiJl47lAQ==} engines: {node: '>=18'} - dotenv@16.4.7: - resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} + dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} engines: {node: '>=12'} + dotenv@17.3.1: + resolution: {integrity: sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==} + engines: {node: '>=12'} + + dts-resolver@2.1.3: + resolution: {integrity: sha512-bihc7jPC90VrosXNzK0LTE2cuLP6jr0Ro8jk+kMugHReJVLIpHz/xadeq3MhuwyO4TD4OA3L1Q8pBBFRc08Tsw==} + engines: {node: '>=20.19.0'} + peerDependencies: + oxc-resolver: '>=11.0.0' + peerDependenciesMeta: + oxc-resolver: + optional: true + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -2785,9 +3921,6 @@ packages: duplexer@0.1.2: resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} - duplexify@4.1.3: - resolution: {integrity: sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==} - eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} @@ -2806,11 +3939,26 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.113: - resolution: {integrity: sha512-wjT2O4hX+wdWPJ76gWSkMhcHAV2PTMX+QetUCPYEdCIe+cxmgzzSSiGRCKW8nuh4mwKZlpv0xvoW7OF2X+wmHg==} + electron-to-chromium@1.5.313: + resolution: {integrity: sha512-QBMrTWEf00GXZmJyx2lbYD45jpI3TUFnNIzJ5BBc8piGUDwMPa1GV6HJWTZVvY/eiN3fSopl7NRbgGp9sZ9LTA==} + + elysia@1.4.27: + resolution: {integrity: sha512-2UlmNEjPJVA/WZVPYKy+KdsrfFwwNlqSBW1lHz6i2AHc75k7gV4Rhm01kFeotH7PDiHIX2G8X3KnRPc33SGVIg==} + peerDependencies: + '@sinclair/typebox': '>= 0.34.0 < 1' + '@types/bun': '>= 1.2.0' + exact-mirror: '>= 0.0.9' + file-type: '>= 20.0.0' + openapi-types: '>= 12.0.0' + typescript: '>= 5.0.0' + peerDependenciesMeta: + '@types/bun': + optional: true + typescript: + optional: true - emoji-regex@10.4.0: - resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} + emoji-regex@10.6.0: + resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -2818,27 +3966,44 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - encodeurl@1.0.2: - resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} - engines: {node: '>= 0.8'} - encodeurl@2.0.0: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} - end-of-stream@1.4.4: - resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + encoding-sniffer@0.2.1: + resolution: {integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==} + + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + + enhanced-resolve@5.20.0: + resolution: {integrity: sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==} + engines: {node: '>=10.13.0'} entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} + engines: {node: '>=0.12'} + + env-runner@0.1.6: + resolution: {integrity: sha512-fSb7X1zdda8k6611a6/SdSQpDe7a/bqMz2UWdbHjk9YWzpUR4/fn9YtE/hqgGQ2nhvVN0zUtcL1SRMKwIsDbAA==} + hasBin: true + peerDependencies: + miniflare: ^4.0.0 + peerDependenciesMeta: + miniflare: + optional: true + eol@0.9.1: resolution: {integrity: sha512-Ds/TEoZjwggRoz/Q2O7SE3i4Jm66mqTDfmdHdq/7DKVk3bro9Q8h6WdXKdPqFLMoqxrDK5SVRzHVPOS6uuGtrg==} - error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} - error-stack-parser-es@1.0.5: resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} @@ -2850,8 +4015,8 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-module-lexer@1.6.0: - resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==} + es-module-lexer@2.0.0: + resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} @@ -2865,13 +4030,13 @@ packages: resolution: {integrity: sha512-ginqzK3J90Rd4/Yz7qRrqUeIpe3TwSXTPPZtPne7tGBPeAaQiU8qt4fpKApnxHcq1AwtUdHVg5P77x/yrggG8Q==} engines: {node: '>=6'} - esbuild@0.24.2: - resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==} + esbuild@0.27.3: + resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} engines: {node: '>=18'} hasBin: true - esbuild@0.25.0: - resolution: {integrity: sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==} + esbuild@0.27.4: + resolution: {integrity: sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==} engines: {node: '>=18'} hasBin: true @@ -2886,73 +4051,14 @@ packages: escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} - - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - escape-string-regexp@5.0.0: resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} engines: {node: '>=12'} - eslint-config-unjs@0.4.2: - resolution: {integrity: sha512-i9//hTramdqBZw/xwkk3Teako/eUZOw1QUaALr2euMt/K44DoCJj2aY3ppiHG7XE5HiYNkUYNaRAHjb9QhM3tQ==} - peerDependencies: - eslint: '*' - typescript: '*' - - eslint-plugin-markdown@5.1.0: - resolution: {integrity: sha512-SJeyKko1K6GwI0AN6xeCDToXDkfKZfXcexA6B+O2Wr2btUS9GrC+YgwSyVli5DJnctUHjFXcQ2cqTaAmVoLi2A==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: '>=8' - - eslint-plugin-unicorn@56.0.1: - resolution: {integrity: sha512-FwVV0Uwf8XPfVnKSGpMg7NtlZh0G0gBarCaFcMUOoqPxXryxdYxTRRv4kH6B9TFCVIrjRXG+emcxIk2ayZilog==} - engines: {node: '>=18.18'} - peerDependencies: - eslint: '>=8.56.0' - - eslint-scope@8.3.0: - resolution: {integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-visitor-keys@4.2.0: - resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - eslint@9.22.0: - resolution: {integrity: sha512-9V/QURhsRN40xuHXWjV64yvrzMjcz7ZyNoF2jJFmy9j/SLk0u1OLSZgXi28MrXjymnjEGSR80WCdab3RGMDveQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} hasBin: true - peerDependencies: - jiti: '*' - peerDependenciesMeta: - jiti: - optional: true - - espree@10.3.0: - resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} - engines: {node: '>=0.10'} - - esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - - estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} @@ -2960,102 +4066,86 @@ packages: estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - etag@1.8.1: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} - event-target-shim@5.0.1: - resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} - engines: {node: '>=6'} - eventemitter3@4.0.7: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} - events@3.3.0: - resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} - engines: {node: '>=0.8.x'} + eventsource-parser@3.0.6: + resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} + engines: {node: '>=18.0.0'} + + eventsource@4.1.0: + resolution: {integrity: sha512-2GuF51iuHX6A9xdTccMTsNb7VO0lHZihApxhvQzJB5A03DvHDd2FQepodbMaztPBmBcE/ox7o2gqaxGhYB9LhQ==} + engines: {node: '>=20.0.0'} + + exact-mirror@0.2.7: + resolution: {integrity: sha512-+MeEmDcLA4o/vjK2zujgk+1VTxPR4hdp23qLqkWfStbECtAq9gmsvQa3LW6z/0GXZyHJobrCnmy1cdeE7BjsYg==} + peerDependencies: + '@sinclair/typebox': ^0.34.15 + peerDependenciesMeta: + '@sinclair/typebox': + optional: true execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} - execa@8.0.1: - resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} - engines: {node: '>=16.17'} - - execa@9.5.2: - resolution: {integrity: sha512-EHlpxMCpHWSAh1dgS6bVeoLAXGnJNdR93aabr4QCGbzOM73o5XmRfM/e5FUqsw3aagP8S8XEWUWFAxnRBnAF0Q==} + execa@9.6.1: + resolution: {integrity: sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==} engines: {node: ^18.19.0 || >=20.5.0} - exit-hook@2.2.1: - resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==} - engines: {node: '>=6'} - expand-template@2.0.3: resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} engines: {node: '>=6'} - expect-type@1.2.0: - resolution: {integrity: sha512-80F22aiJ3GLyVnS/B3HzgR6RelZVumzj9jkL0Rhz4h0xYbNW9PjlQz5h3J/SShErbXBc295vseR4/MIbVmUbeA==} + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} - express@4.21.2: - resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} - engines: {node: '>= 0.10.0'} + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} - exsolve@1.0.4: - resolution: {integrity: sha512-xsZH6PXaER4XoV+NiT7JHp1bJodJVT+cxeSH1G0f0tlT0lJqYuHUP3bUx2HtfTDvOagMINYp8rsqusxud3RXhw==} + exsolve@1.0.8: + resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - farmhash-modern@1.1.0: - resolution: {integrity: sha512-6ypT4XfgqJk/F3Yuv4SX26I3doUjt0GTG4a+JgWxXQpxXzTBq8fPUeGHfcYMMDPHJHm3yPOSjaeBwBGAHWXCdA==} - engines: {node: '>=18.0.0'} - fast-copy@3.0.2: resolution: {integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==} + fast-decode-uri-component@1.0.1: + resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - fast-fifo@1.3.2: - resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} - - fast-glob@3.3.3: - resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} - engines: {node: '>=8.6.0'} - - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + fast-json-stringify@6.3.0: + resolution: {integrity: sha512-oRCntNDY/329HJPlmdNLIdogNtt6Vyjb1WuT01Soss3slIdyUp8kAcDU3saQTOquEK8KFVfwIIF7FebxUAu+yA==} - fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-querystring@1.1.2: + resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==} - fast-uri@3.0.6: - resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} - - fast-xml-parser@4.5.3: - resolution: {integrity: sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==} - hasBin: true + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} fastest-levenshtein@1.0.16: resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} engines: {node: '>= 4.9.1'} - fastq@1.19.1: - resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + fastify@5.8.2: + resolution: {integrity: sha512-lZmt3navvZG915IE+f7/TIVamxIwmBd+OMB+O9WBzcpIwOo6F0LTh0sluoMFk5VkrKTvvrwIaoJPkir4Z+jtAg==} - faye-websocket@0.11.4: - resolution: {integrity: sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==} - engines: {node: '>=0.8.0'} + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} - fdir@6.4.3: - resolution: {integrity: sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==} + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} peerDependencies: picomatch: ^3 || ^4 peerDependenciesMeta: @@ -3066,55 +4156,34 @@ packages: resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} engines: {node: '>=18'} - file-entry-cache@8.0.0: - resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} - engines: {node: '>=16.0.0'} - - file-uri-to-path@1.0.0: - resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + file-type@21.3.2: + resolution: {integrity: sha512-DLkUvGwep3poOV2wpzbHCOnSKGk1LzyXTv+aHFgN2VFl96wnp8YA9YjO2qPzg5PuL8q/SW9Pdi6WTkYOIh995w==} + engines: {node: '>=20'} fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - finalhandler@1.3.1: - resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} + finalhandler@1.3.2: + resolution: {integrity: sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==} engines: {node: '>= 0.8'} - find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} - - find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - - firebase-admin@12.7.0: - resolution: {integrity: sha512-raFIrOyTqREbyXsNkSHyciQLfv8AUZazehPaQS1lZBSCDYW74FYXU0nQZa3qHI4K+hawohlDbywZ4+qce9YNxA==} - engines: {node: '>=14'} - - firebase-functions@4.9.0: - resolution: {integrity: sha512-IqxOEsVAWGcRv9KRGzWQR5mOFuNsil3vsfkRPPiaV1U/ATC27/jbahh4z8I4rW8Xqa6cQE5xqnw0ueyMH7i7Ag==} - engines: {node: '>=14.10.0'} - hasBin: true - peerDependencies: - firebase-admin: ^10.0.0 || ^11.0.0 || ^12.0.0 - - fix-dts-default-cjs-exports@1.0.0: - resolution: {integrity: sha512-i9Vd++WOWo6JilNgZvNvmy1T0r+/j7vikghQSEhKIuDwz4GjUrYj+Z18zlL7MleYNxE+xE6t3aG7LiAwA1P+dg==} + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} - flat-cache@4.0.1: - resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} - engines: {node: '>=16'} + find-my-way@9.5.0: + resolution: {integrity: sha512-VW2RfnmscZO5KgBY5XVyKREMW5nMZcxDy+buTOsL+zIPnBlbKm+00sgzoQzq1EVh4aALZLfKdwv6atBGcjvjrQ==} + engines: {node: '>=20'} - flatted@3.3.3: - resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + flatted@3.4.1: + resolution: {integrity: sha512-IxfVbRFVlV8V/yRaGzk0UVIcsKKHMSfYw66T/u4nTwlWteQePsxe//LjudR1AMX4tZW3WFCh3Zqa/sjlqpbURQ==} - focus-trap@7.6.4: - resolution: {integrity: sha512-xx560wGBk7seZ6y933idtjJQc1l+ck+pI3sKvhKozdBV1dRZoKhkW5xoCaFv9tQiX5RH1xfSxjuNu6g+lmN/gw==} + focus-trap@7.8.0: + resolution: {integrity: sha512-/yNdlIkpWbM0ptxno3ONTuf+2g318kh2ez3KSeZN5dZ8YC6AAmgeWz+GasYYiBJPFaYcSAPeu4GfhUaChzIJXA==} - follow-redirects@1.15.9: - resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} + follow-redirects@1.15.11: + resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} engines: {node: '>=4.0'} peerDependencies: debug: '*' @@ -3126,32 +4195,25 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} - form-data@2.5.3: - resolution: {integrity: sha512-XHIrMD0NpDrNM/Ckf7XJiBbLl57KEhT3+i3yY+eWm+cqYZJQTZrKo8Y8AWKnuV5GT4scfuUGt9LzNoIx3dU1nQ==} - engines: {node: '>= 0.12'} - - form-data@4.0.2: - resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==} + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} engines: {node: '>= 6'} forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} - fraction.js@4.3.7: - resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} - fresh@0.5.2: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} - fs-extra@11.3.0: - resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==} - engines: {node: '>=14.14'} - fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -3163,27 +4225,24 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - functional-red-black-tree@1.0.1: - resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} + function-timeout@1.0.2: + resolution: {integrity: sha512-939eZS4gJ3htTHAldmyyuzlrD58P03fHG49v2JfFXbV6OhvZKRC9j2yAtdHw/zrp2zXHuv05zMIy40F0ge7spA==} + engines: {node: '>=18'} fuse.js@7.1.0: resolution: {integrity: sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==} engines: {node: '>=10'} - gaxios@6.7.1: - resolution: {integrity: sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==} - engines: {node: '>=14'} - - gcp-metadata@6.1.1: - resolution: {integrity: sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==} - engines: {node: '>=14'} + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - get-east-asian-width@1.3.0: - resolution: {integrity: sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==} + get-east-asian-width@1.5.0: + resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==} engines: {node: '>=18'} get-intrinsic@1.3.0: @@ -3194,8 +4253,8 @@ packages: resolution: {integrity: sha512-PKsK2FSrQCyxcGHsGrLDcK0lx+0Ke+6e8KFFozA9/fIQLhQzPaRvJFdcz7+Axg3jUH/Mq+NI4xa5u/UT2tQskA==} engines: {node: '>=14.16'} - get-port-please@3.1.2: - resolution: {integrity: sha512-Gxc29eLs1fbn6LQ4jSU4vXjlwyZhF5HsGuMAa7gqBP4Rw4yxxltyDUuF5MBclFzDTXO+ACchGQoeela4DSfzdQ==} + get-port-please@3.2.0: + resolution: {integrity: sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==} get-port@3.2.0: resolution: {integrity: sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==} @@ -3209,25 +4268,31 @@ packages: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} - get-source@2.0.12: - resolution: {integrity: sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==} - get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} - get-stream@8.0.1: - resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} - engines: {node: '>=16'} - get-stream@9.0.1: resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} engines: {node: '>=18'} + get-tsconfig@4.13.6: + resolution: {integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==} + giget@2.0.0: resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} hasBin: true + giget@3.1.2: + resolution: {integrity: sha512-T2qUpKBHeUTwHcIhydgnJzhL0Hj785ms+JkxaaWQH9SDM/llXeewnOkfJcFShAHjWI+26hOChwUfCoupaXLm8g==} + hasBin: true + + git-up@7.0.0: + resolution: {integrity: sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ==} + + git-url-parse@15.0.0: + resolution: {integrity: sha512-5reeBufLi+i4QD3ZFftcJs9jC26aULFLBU23FeKM/b1rI0K6ofIeAblmDVO7Ht22zTDE9+CkJ3ZVb0CgJmz3UQ==} + github-from-package@0.0.0: resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} @@ -3238,51 +4303,26 @@ packages: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} - glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - - glob-to-regexp@0.4.1: - resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - - glob@10.4.5: - resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + glob@10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me global-directory@4.0.1: resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==} engines: {node: '>=18'} - globals@14.0.0: - resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} - engines: {node: '>=18'} - - globals@15.15.0: - resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} - engines: {node: '>=18'} - - globby@14.1.0: - resolution: {integrity: sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==} - engines: {node: '>=18'} - globrex@0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} - google-auth-library@9.15.1: - resolution: {integrity: sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==} - engines: {node: '>=14'} - - google-gax@4.4.1: - resolution: {integrity: sha512-Phyp9fMfA00J3sZbJxbbB4jC55b7DBjE3F6poyL3wKMEBVKA79q6BGuHcTiM28yOzVql0NDbRL8MLLh8Iwk9Dg==} - engines: {node: '>=14'} - - google-logging-utils@0.0.2: - resolution: {integrity: sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==} - engines: {node: '>=14'} + goober@2.1.18: + resolution: {integrity: sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw==} + peerDependencies: + csstype: ^3.0.10 gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} @@ -3294,19 +4334,23 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - - gtoken@7.1.0: - resolution: {integrity: sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==} - engines: {node: '>=14.0.0'} + guess-json-indent@3.0.1: + resolution: {integrity: sha512-LWZ3Vr8BG7DHE3TzPYFqkhjNRw4vYgFSsv2nfMuHklAlOfiy54/EwiDQuQfFVLxENCVv20wpbjfTayooQHrEhQ==} + engines: {node: '>=18.18.0'} gzip-size@7.0.0: resolution: {integrity: sha512-O1Ld7Dr+nqPnmGpdhzLmMTQ4vAsD+rHwMm1NLUmoUFFymBOMKxCCrtDxqdBRYXdeEPEi3SyoR4TizJLQrnKBNA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - h3@1.15.1: - resolution: {integrity: sha512-+ORaOBttdUm1E2Uu/obAyCguiI7MbBvsLTndc3gyK3zU+SYLoZXlyCP9Xgy0gikkGufFLTZXCXD6+4BsufnmHA==} + h3@2.0.1-rc.16: + resolution: {integrity: sha512-h+pjvyujdo9way8qj6FUbhaQcHlR8FEq65EhTX9ViT5pK8aLj68uFl4hBkF+hsTJAH+H1END2Yv6hTIsabGfag==} + engines: {node: '>=20.11.1'} + hasBin: true + peerDependencies: + crossws: ^0.4.1 + peerDependenciesMeta: + crossws: + optional: true has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} @@ -3363,8 +4407,8 @@ packages: hast-util-to-html@9.0.5: resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} - hast-util-to-parse5@8.0.0: - resolution: {integrity: sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==} + hast-util-to-parse5@8.0.1: + resolution: {integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==} hast-util-to-text@4.0.2: resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==} @@ -3375,6 +4419,10 @@ packages: hastscript@9.0.1: resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} + he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + highlight.js@11.11.1: resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==} engines: {node: '>=12.0.0'} @@ -3382,17 +4430,15 @@ packages: highlightjs-curl@1.3.0: resolution: {integrity: sha512-50UEfZq1KR0Lfk2Tr6xb/MUIZH3h10oNC0OTy9g7WELcs5Fgy/mKN1vEhuKTkKbdo8vr5F9GXstu2eLhApfQ3A==} - highlightjs-vue@1.0.0: - resolution: {integrity: sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA==} + hono@4.12.8: + resolution: {integrity: sha512-VJCEvtrezO1IAR+kqEYnxUOoStaQPGrCmX3j4wDTNOcD1uRPFpGlwQUIW8niPuvHXaTUxeOUl5MMDGrl+tmO9A==} + engines: {node: '>=16.9.0'} - hookable@5.5.3: - resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + hookable@6.0.1: + resolution: {integrity: sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw==} - hosted-git-info@2.8.9: - resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} - - html-entities@2.5.2: - resolution: {integrity: sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==} + html-entities@2.3.3: + resolution: {integrity: sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==} html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} @@ -3403,16 +4449,12 @@ packages: html-whitespace-sensitive-tag-names@3.0.1: resolution: {integrity: sha512-q+310vW8zmymYHALr1da4HyXUQ0zgiIwIicEfotYPWGN0OJVEN/58IJ3A4GBYcEq3LGAZqKb+ugvP0GNB9CEAA==} - http-errors@2.0.0: - resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} - engines: {node: '>= 0.8'} - - http-parser-js@0.5.9: - resolution: {integrity: sha512-n1XsPy3rXVxlqxVioEWdC+0+M+SQw0DpJynwtOPo1X+ZlvdzTLtDBIJJlDQTnwZIFJrZSzSGmIOUdP8tu+SgLw==} + htmlparser2@10.1.0: + resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} - http-proxy-agent@5.0.0: - resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} - engines: {node: '>= 6'} + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} http-proxy-agent@7.0.2: resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} @@ -3422,68 +4464,36 @@ packages: resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==} engines: {node: '>=8.0.0'} - http-shutdown@1.2.2: - resolution: {integrity: sha512-S9wWkJ/VSY9/k4qcjG318bqJNruzE4HySUhFYknwmu6LBP97KLLfwNf+n4V1BHurvFNkSKLFnK/RsuUnRTf9Vw==} - engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} - - https-proxy-agent@5.0.1: - resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} - engines: {node: '>= 6'} - https-proxy-agent@7.0.6: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} - httpxy@0.1.7: - resolution: {integrity: sha512-pXNx8gnANKAndgga5ahefxc++tJvNL87CXoRwxn1cJE2ZkWEojF3tNfQIEhZX/vfpt+wzeAzpUI4qkediX1MLQ==} + httpxy@0.3.1: + resolution: {integrity: sha512-XjG/CEoofEisMrnFr0D6U6xOZ4mRfnwcYQ9qvvnT4lvnX8BoeA3x3WofB75D+vZwpaobFVkBIHrZzoK40w8XSw==} human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} - human-signals@5.0.0: - resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} - engines: {node: '>=16.17.0'} - - human-signals@8.0.0: - resolution: {integrity: sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA==} + human-signals@8.0.1: + resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==} engines: {node: '>=18.18.0'} - iconv-lite@0.4.24: - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} - engines: {node: '>=0.10.0'} - iconv-lite@0.6.3: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} - ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - - ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} - - ignore@7.0.3: - resolution: {integrity: sha512-bAH5jbK/F3T3Jls4I0SO1hmPR0dKU0a7+SY6n1yzRtG54FLO8d6w/nxLFX2Nb7dBu6cCWXPaAME6cYqFUMmuCA==} - engines: {node: '>= 4'} - - import-fresh@3.3.1: - resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} - engines: {node: '>=6'} - - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - - indent-string@4.0.0: - resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} - engines: {node: '>=8'} + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + engines: {node: '>=0.10.0'} - index-to-position@0.1.2: - resolution: {integrity: sha512-MWDKS3AS1bGCHLBA2VLImJz42f7bJh8wQsTGCzI3j519/CASStoDONUBVz2I/VID0MpiX3SGSnbOD2xUalbE5g==} + identifier-regex@1.0.1: + resolution: {integrity: sha512-ZrYyM0sozNPZlvBvE7Oq9Bn44n0qKGrYu5sQ0JzMUnjIhpgWYE2JB6aBoFwEYdPjqj7jPyxXTMJiHDOxDfd8yw==} engines: {node: '>=18'} + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. @@ -3502,10 +4512,6 @@ packages: resolution: {integrity: sha512-D8WGsR6yDt8uq7vDMu7mjcR+yRMm3dW8yufyChmszWRjcSHuxLBkR3GdS2HZAjodsaGuCvXeEJpueisXJULghg==} engines: {node: '>=10'} - ioredis@5.6.0: - resolution: {integrity: sha512-tBZlIIWbndeWBWCXWZiqtOF/yxf6yZX3tAlTJ7nfo5jhd6dctNxF7QnYlZLZ1a0o0pDoen7CgZqO+zjNaFbJAg==} - engines: {node: '>=12.22.0'} - ip-regex@4.3.0: resolution: {integrity: sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==} engines: {node: '>=8'} @@ -3514,36 +4520,29 @@ packages: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} - iron-webcrypto@1.2.1: - resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} + ipaddr.js@2.3.0: + resolution: {integrity: sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==} + engines: {node: '>= 10'} is-absolute-url@4.0.1: resolution: {integrity: sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - is-alphabetical@1.0.4: - resolution: {integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==} - - is-alphanumerical@1.0.4: - resolution: {integrity: sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==} - - is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} is-buffer@1.1.6: resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} - is-builtin-module@3.2.1: - resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==} - engines: {node: '>=6'} + is-ci@4.1.0: + resolution: {integrity: sha512-Ab9bQDQ11lWootZUI5qxgN2ZXwxNI5hTwnsvOc1wyxQ7zQ8OkEDw79mI0+9jI3x432NfwbVRru+3noJfXF6lSQ==} + hasBin: true is-core-module@2.16.1: resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} - is-decimal@1.0.4: - resolution: {integrity: sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==} - is-docker@2.2.1: resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} engines: {node: '>=8'} @@ -3566,8 +4565,9 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} - is-hexadecimal@1.0.4: - resolution: {integrity: sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==} + is-identifier@1.0.1: + resolution: {integrity: sha512-HQ5v4rEJ7REUV54bCd2l5FaD299SGDEn2UPoVXaTHAyGviLq2menVUD2udi3trQ32uvB6LdAh/0ck2EuizrtpA==} + engines: {node: '>=18'} is-in-ci@1.0.0: resolution: {integrity: sha512-eUuAjybVTHMYWm/U+vBO1sY/JOCgoPCXRxzdju0K+K0BiGW0SChEL1MLC0PoCIR1OlPo5YAp8HuQoUlsWEICwg==} @@ -3594,8 +4594,8 @@ packages: is-module@1.0.0: resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} - is-npm@6.0.0: - resolution: {integrity: sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==} + is-npm@6.1.0: + resolution: {integrity: sha512-O2z4/kNgyjhQwVR1Wpkbfc19JIhggF97NZNCpWTnjH7kVcZMUrnut9XSN7txI7VdyIYk5ZatOq3zvSuWpU8hoA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} is-number@7.0.0: @@ -3614,21 +4614,30 @@ packages: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-reference@1.2.1: resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} + is-reference@3.0.3: + resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} + is-regexp@3.1.0: resolution: {integrity: sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA==} engines: {node: '>=12'} + is-retry-allowed@2.2.0: + resolution: {integrity: sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==} + engines: {node: '>=10'} + + is-ssh@1.4.1: + resolution: {integrity: sha512-JNeu1wQsHjyHgn9NcWTaXq6zWSR6hqE0++zhfZlkFBbScNkyvxCdeV8sRkSBaeLKxmbpR21brail63ACNxJ0Tg==} + is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} - is-stream@3.0.0: - resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - is-stream@4.0.1: resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==} engines: {node: '>=18'} @@ -3644,21 +4653,22 @@ packages: is-valid-domain@0.1.6: resolution: {integrity: sha512-ZKtq737eFkZr71At8NxOFcP9O1K89gW3DkdrGMpp1upr/ueWjj+Weh4l9AI4rN0Gt8W2M1w7jrG2b/Yv83Ljpg==} + is-what@4.1.16: + resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} + engines: {node: '>=12.13'} + is-wsl@2.2.0: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} - is-wsl@3.1.0: - resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} + is-wsl@3.1.1: + resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} engines: {node: '>=16'} - is64bit@2.0.0: - resolution: {integrity: sha512-jv+8jaWCl0g2lSBkNSVXdzfBA0npK1HGC2KtWM9FumFRoGS94g3NbCCLVnCYHLjp4GrW2KZeeSTMo5ddtznmGw==} + isbot@5.1.36: + resolution: {integrity: sha512-C/ZtXyJqDPZ7G7JPr06ApWyYoHjYexQbS6hPYD4WYCzpv2Qes6Z+CCEfTX4Owzf+1EJ933PoI2p+B9v7wpGZBQ==} engines: {node: '>=18'} - isarray@1.0.0: - resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -3670,34 +4680,31 @@ packages: resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} engines: {node: '>=10'} - istanbul-lib-source-maps@5.0.6: - resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} - engines: {node: '>=10'} - - istanbul-reports@3.1.7: - resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} + istanbul-reports@3.2.0: + resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} engines: {node: '>=8'} jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - jiti@1.21.7: - resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} - hasBin: true - - jiti@2.4.2: - resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true joi@17.13.3: resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==} - jose@4.15.9: - resolution: {integrity: sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==} + jose@5.10.0: + resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==} - js-levenshtein@1.1.6: - resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==} - engines: {node: '>=0.10.0'} + jose@6.2.1: + resolution: {integrity: sha512-jUaKr1yrbfaImV7R2TN/b3IcZzsw38/chqMpo2XJ7i2F8AfM/lA4G1goC3JVEwg0H7UldTmSt3P68nt31W7/mw==} + + js-base64@3.7.8: + resolution: {integrity: sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==} + + js-tokens@10.0.0: + resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -3705,12 +4712,8 @@ packages: js-tokens@9.0.1: resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} - js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true - - jsesc@0.5.0: - resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true jsesc@3.1.0: @@ -3718,66 +4721,45 @@ packages: engines: {node: '>=6'} hasBin: true - json-bigint@1.0.0: - resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} - - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - - json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - json-schema-library@9.3.5: resolution: {integrity: sha512-5eBDx7cbfs+RjylsVO+N36b0GOPtv78rfqgf2uON+uaHUIC62h63Y8pkV2ovKbaL4ZpQcHp21968x5nx/dFwqQ==} - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + json-schema-ref-resolver@3.0.0: + resolution: {integrity: sha512-hOrZIVL5jyYFjzk7+y7n5JDzGlU8rfWDuYyHwGa2WA8/pcmMHezp2xsVwxrebD/Q9t8Nc5DboieySDpCp4WG4A==} json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json-schema@0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + json-source-map@0.6.1: resolution: {integrity: sha512-1QoztHPsMQqhDq0hlXY5ZqcEdUzxQEIxgFkKl4WUp2pgShObl+9ovi4kRh2TfvAfxAoHOJ9vIMEqk3k4iex7tg==} - json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - - json-stringify-deterministic@1.0.12: - resolution: {integrity: sha512-q3PN0lbUdv0pmurkBNdJH3pfFvOTL/Zp0lquqpvcjfKzt6Y0j49EPHAmVHCAS4Ceq/Y+PejWTzyiVpoY71+D6g==} - engines: {node: '>= 4'} + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true - jsonfile@6.1.0: - resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} jsonpointer@5.0.1: resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==} engines: {node: '>=0.10.0'} - jsonwebtoken@9.0.2: - resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} + jsonwebtoken@9.0.3: + resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==} engines: {node: '>=12', npm: '>=6'} just-clone@6.2.0: resolution: {integrity: sha512-1IynUYEc/HAwxhi3WDpIpxJbZpMCvvrrmZVqvj9EhpvbH8lls7HhdhiByjL7DkAaWlLIzpC0Xc/VPvy/UxLNjA==} - just-curry-it@5.3.0: - resolution: {integrity: sha512-silMIRiFjUWlfaDhkgSzpuAyQ6EX/o09Eu8ZBfmFwQMbax7+LQzeIU2CBrICT6Ne4l86ITCGvUCBpCubWYy0Yw==} - - jwa@1.4.1: - resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==} - - jwa@2.0.0: - resolution: {integrity: sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==} - - jwks-rsa@3.1.0: - resolution: {integrity: sha512-v7nqlfezb9YfHHzYII3ef2a2j1XnGeSE/bK3WfumaYCqONAIstJbrEGapz4kadScZzEt7zYCN7bucj8C0Mv/Rg==} - engines: {node: '>=14'} - - jws@3.2.2: - resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} + jwa@2.0.1: + resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} - jws@4.0.0: - resolution: {integrity: sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==} + jws@4.0.1: + resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} jwt-decode@4.0.0: resolution: {integrity: sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==} @@ -3786,9 +4768,6 @@ packages: keytar@7.9.0: resolution: {integrity: sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==} - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} @@ -3801,73 +4780,185 @@ packages: resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} engines: {node: '>= 8'} - knitwork@1.2.0: - resolution: {integrity: sha512-xYSH7AvuQ6nXkq42x0v5S8/Iry+cfulBz/DJQzhIyESdLD7425jXsPy4vn5cCXU+HhRN2kVw51Vd1K6/By4BQg==} + knitwork@1.3.0: + resolution: {integrity: sha512-4LqMNoONzR43B1W0ek0fhXMsDNW/zxa1NdFAVMY+k28pgZLovR4G3PB5MrpTxCy1QaZCqNoiaKPr5w5qZHfSNw==} + + kolorist@1.8.0: + resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} + + ky@1.14.3: + resolution: {integrity: sha512-9zy9lkjac+TR1c2tG+mkNSVlyOpInnWdSMiue4F+kq8TwJSgv6o8jhLRg8Ho6SnZ9wOYUq/yozts9qQCfk7bIw==} + engines: {node: '>=18'} + + latest-version@9.0.0: + resolution: {integrity: sha512-7W0vV3rqv5tokqkBAFV1LbR7HPOWzXQDpDgEuib/aJ1jsZZx6x3c2mBI+TJhJzOhkGeaLbCKEHXEXLfirtG2JA==} + engines: {node: '>=18'} + + leven@4.1.0: + resolution: {integrity: sha512-KZ9W9nWDT7rF7Dazg8xyLHGLrmpgq2nVNFUckhqdW3szVP6YhCpp/RAnpmVExA9JvrMynjwSLVrEj3AepHR6ew==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + light-my-request@6.6.0: + resolution: {integrity: sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A==} + + lightningcss-android-arm64@1.31.1: + resolution: {integrity: sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.31.1: + resolution: {integrity: sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.31.1: + resolution: {integrity: sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.31.1: + resolution: {integrity: sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.31.1: + resolution: {integrity: sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] - ky@1.7.5: - resolution: {integrity: sha512-HzhziW6sc5m0pwi5M196+7cEBtbt0lCYi67wNsiwMUmz833wloE0gbzJPWKs1gliFKQb34huItDQX97LyOdPdA==} - engines: {node: '>=18'} + lightningcss-linux-arm64-gnu@1.31.1: + resolution: {integrity: sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] - latest-version@9.0.0: - resolution: {integrity: sha512-7W0vV3rqv5tokqkBAFV1LbR7HPOWzXQDpDgEuib/aJ1jsZZx6x3c2mBI+TJhJzOhkGeaLbCKEHXEXLfirtG2JA==} - engines: {node: '>=18'} + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] - lazystream@1.0.1: - resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} - engines: {node: '>= 0.6.3'} + lightningcss-linux-arm64-musl@1.31.1: + resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] - leven@4.0.0: - resolution: {integrity: sha512-puehA3YKku3osqPlNuzGDUHq8WpwXupUg1V6NXdV38G+gr+gkBwFC8g1b/+YcIvp8gnqVIus+eJCH/eGsRmJNw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] - levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} + lightningcss-linux-x64-gnu@1.31.1: + resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] - lilconfig@3.1.3: - resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} - engines: {node: '>=14'} + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] - limiter@1.1.5: - resolution: {integrity: sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==} + lightningcss-linux-x64-musl@1.31.1: + resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] - lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] - listhen@1.9.0: - resolution: {integrity: sha512-I8oW2+QL5KJo8zXNWX046M134WchxsXC7SawLPvRQpogCbkyQIaFxPE89A2HiwR7vAK2Dm2ERBAmyjTYGYEpBg==} - hasBin: true + lightningcss-win32-arm64-msvc@1.31.1: + resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] - local-pkg@1.1.1: - resolution: {integrity: sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==} - engines: {node: '>=14'} + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] - locate-path@5.0.0: - resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} - engines: {node: '>=8'} + lightningcss-win32-x64-msvc@1.31.1: + resolution: {integrity: sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] - locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.31.1: + resolution: {integrity: sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==} + engines: {node: '>= 12.0.0'} - lodash.camelcase@4.3.0: - resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} - lodash.clonedeep@4.5.0: - resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==} + local-pkg@1.1.2: + resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==} + engines: {node: '>=14'} lodash.deburr@4.1.0: resolution: {integrity: sha512-m/M1U1f3ddMCs6Hq2tAsYThTBDaAKFDX3dwDo97GEYzamXi9SqUpjWi/Rrj/gf3X2n8ktwgZrlP1z6E3v/IExQ==} - lodash.defaults@4.2.0: - resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} - lodash.includes@4.3.0: resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} - lodash.isarguments@3.1.0: - resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==} - lodash.isboolean@3.0.3: resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} @@ -3883,20 +4974,11 @@ packages: lodash.isstring@4.0.1: resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} - lodash.memoize@4.1.2: - resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} - - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - lodash.once@4.1.1: resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} - lodash.uniq@4.5.0: - resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} - - lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + lodash@4.17.23: + resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==} log-symbols@4.1.0: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} @@ -3905,33 +4987,27 @@ packages: long@4.0.0: resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} - long@5.3.1: - resolution: {integrity: sha512-ka87Jz3gcx/I7Hal94xaN2tZEOPoUOEVftkQqZx2EeQRN7LGdfLlI3FvZ+7WDplm+vK2Urx9ULrvSowtdCieng==} - longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} - loupe@3.1.3: - resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==} - lowlight@3.3.0: resolution: {integrity: sha512-0JNhgFoPvP6U6lE/UdVsSq99tn6DhjjpAj5MxG49ewd2mOBVtwWYIT8ClyABhq198aXXODMU6Ox8DrGy/CpTZQ==} lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - lru-memoizer@2.3.0: - resolution: {integrity: sha512-GXn7gyHAMhO13WSKrIiNfztwxodVsP8IoZ3XfrJV4yH2x0/OeTO/FIaAHTY5YekdGgW94njfuKmyyt1E0mR6Ug==} + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - magic-string@0.30.17: - resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + magicast@0.5.2: + resolution: {integrity: sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==} - magicast@0.3.5: - resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} + make-asynchronous@1.1.0: + resolution: {integrity: sha512-ayF7iT+44LXdxJLTrTd3TLQpFDDvPCBxXxbv+pMUSuHA5Q8zyAfwkRP6aHHwNVFBUFWtxAHqwNJxF8vMZLAbVg==} + engines: {node: '>=18'} make-dir@4.0.0: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} @@ -3940,12 +5016,21 @@ packages: markdown-table@3.0.4: resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + marked@14.0.0: + resolution: {integrity: sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==} + engines: {node: '>= 18'} + hasBin: true + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} - md4w@0.2.6: - resolution: {integrity: sha512-CBLQ2PxVe9WA+/nndZCx/Y+1C3DtmtSeubmXTPhMIgsXtq9gVGleikREko5FYnV6Dz4cHDWm0Ea+YMLpIjP4Kw==} + md4w@0.2.7: + resolution: {integrity: sha512-lFM7vwk3d4MzkV2mija7aPkK6OjKXZDQsH2beX+e2cvccBoqc6RraheMtAO0Wcr/gjj5L+WS5zhb+06AmuGZrg==} + + md4x@0.0.25: + resolution: {integrity: sha512-GrexawUhrKcwl7o2hkgs7Ut0PqI/meOCevmaRB1ueKo2y1Fh2nIl8e6KKawYGm9eXJP3u6BzVs4rzZOc2+w3hA==} + hasBin: true md5@2.3.0: resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==} @@ -3953,11 +5038,8 @@ packages: mdast-util-find-and-replace@3.0.2: resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} - mdast-util-from-markdown@0.8.5: - resolution: {integrity: sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==} - - mdast-util-from-markdown@2.0.2: - resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} + mdast-util-from-markdown@2.0.3: + resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} mdast-util-gfm-autolink-literal@2.0.1: resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} @@ -3980,44 +5062,43 @@ packages: mdast-util-phrasing@4.1.0: resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} - mdast-util-to-hast@13.2.0: - resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==} + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} mdast-util-to-markdown@2.1.2: resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} - mdast-util-to-string@2.0.0: - resolution: {integrity: sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==} - mdast-util-to-string@4.0.0: resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} mdbox@0.1.1: resolution: {integrity: sha512-jvLISenzbLRPWWamTG3THlhTcMbKWzJQNyTi61AVXhCBOC+gsldNTUfUNH8d3Vay83zGehFw3wZpF3xChzkTIQ==} - mdn-data@2.0.28: - resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} + mdream@0.17.0: + resolution: {integrity: sha512-DVaUCgKJZx7Wp6DNZMBhkMWf40nEtANLa8+ZwhqFJE276YiKUqpupG+eCIxKIcLtUP4aKpKp6EssNjCx49qtSg==} + hasBin: true - mdn-data@2.0.30: - resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} + mdzilla@0.0.6: + resolution: {integrity: sha512-mZIILIQVzQIoQ2LTHRY11iR2WczshOObi8svaVGl+IAwzibKZJ2Dk5XLdrKQCfW/8SpN/Gg2Pa62WVw/kH/IaQ==} + hasBin: true - media-typer@0.3.0: - resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} - engines: {node: '>= 0.6'} + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} - merge-descriptors@1.0.3: - resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + memoirist@0.4.0: + resolution: {integrity: sha512-zxTgA0mSYELa66DimuNQDvyLq36AwDlTuVRbnQtB+VuTcKWm5Qc4z3WkSpgsFWHNhexqkIooqpv4hdcqrX5Nmg==} - merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + merge-anything@5.1.7: + resolution: {integrity: sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ==} + engines: {node: '>=12.13'} - merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} - methods@1.1.2: - resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} - engines: {node: '>= 0.6'} + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} microdiff@1.5.0: resolution: {integrity: sha512-Drq+/THMvDdzRYrK0oxJmOKiC24ayUV8ahrt8l3oRK51PWt6gdtrIGrlIH3pT/lFh1z93FbAcidtsHcWbnRz8Q==} @@ -4103,36 +5184,32 @@ packages: micromark-util-types@2.0.2: resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} - micromark@2.11.4: - resolution: {integrity: sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==} - micromark@4.0.2: resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} - mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + mime@1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} engines: {node: '>=4'} hasBin: true - mime@3.0.0: - resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} - engines: {node: '>=10.0.0'} - hasBin: true - - mime@4.0.6: - resolution: {integrity: sha512-4rGt7rvQHBbaSOF9POGkk1ocRP16Md1x36Xma8sz8h8/vfCUI2OtEIeCqe4Ofes853x4xDoPiFLIT47J5fI/7A==} + mime@4.1.0: + resolution: {integrity: sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==} engines: {node: '>=16'} hasBin: true @@ -4140,45 +5217,33 @@ packages: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} - mimic-fn@4.0.0: - resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} - engines: {node: '>=12'} - mimic-response@3.1.0: resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} engines: {node: '>=10'} - min-indent@1.0.1: - resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} - engines: {node: '>=4'} - - miniflare@3.20250224.0: - resolution: {integrity: sha512-DyLxzhHCQ9UWDceqEsT7tmw8ZTSAhb1yKUqUi5VDmSxsIocKi4y5kvMijw9ELK8+tq/CiCp/RQxwRNZRJD8Xbg==} - engines: {node: '>=16.13'} + miniflare@4.20260312.0: + resolution: {integrity: sha512-pieP2rfXynPT6VRINYaiHe/tfMJ4c5OIhqRlIdLF6iZ9g5xgpEmvimvIgMpgAdDJuFlrLcwDUi8MfAo2R6dt/w==} + engines: {node: '>=18.0.0'} hasBin: true - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@10.2.4: + resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} + engines: {node: 18 || 20 || >=22} - minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} - engines: {node: '>=10'} + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} - minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} engines: {node: '>=16 || 14 >=14.17'} minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - minipass@7.1.2: - resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} - minizlib@3.0.1: - resolution: {integrity: sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==} - engines: {node: '>= 18'} - mkdirp-classic@0.5.3: resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} @@ -4186,34 +5251,44 @@ packages: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true - mkdirp@3.0.1: - resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} - engines: {node: '>=10'} - hasBin: true + mlly@1.8.1: + resolution: {integrity: sha512-SnL6sNutTwRWWR/vcmCYHSADjiEesp5TGQQ0pXyLhW5IoeibRlF/CbSLailbB3CNqJUk9cVJ9dUDnbD7GrcHBQ==} - mkdist@2.2.0: - resolution: {integrity: sha512-GfKwu4A2grXfhj2TZm4ydfzP515NaALqKaPq4WqaZ6NhEnD47BiIQPySoCTTvVqHxYcuqVkNdCXjYf9Bz1Y04Q==} - hasBin: true + moment@2.30.1: + resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} + + monaco-editor@0.54.0: + resolution: {integrity: sha512-hx45SEUoLatgWxHKCmlLJH81xBo0uXP4sRkESUpmDQevfi+e7K1VuiSprK6UpQ8u4zOcKNiH0pMvHvlMWA/4cw==} + + monaco-languageserver-types@0.4.0: + resolution: {integrity: sha512-QQ3BZiU5LYkJElGncSNb5AKoJ/LCs6YBMCJMAz9EA7v+JaOdn3kx2cXpPTcZfKA5AEsR0vc97sAw+5mdNhVBmw==} + + monaco-marker-data-provider@1.2.5: + resolution: {integrity: sha512-5ZdcYukhPwgYMCvlZ9H5uWs5jc23BQ8fFF5AhSIdrz5mvYLsqGZ58ZLxTv8rCX6+AxdJ8+vxg1HVSk+F2bLosg==} + + monaco-types@0.1.2: + resolution: {integrity: sha512-8LwfrlWXsedHwAL41xhXyqzPibS8IqPuIXr9NdORhonS495c2/wky+sI1PRLvMCuiI0nqC2NH1six9hdiRY4Xg==} + + monaco-worker-manager@2.0.1: + resolution: {integrity: sha512-kdPL0yvg5qjhKPNVjJoym331PY/5JC11aPJXtCZNwWRvBr6jhkIamvYAyiY5P1AWFmNOy0aRDRoMdZfa71h8kg==} peerDependencies: - sass: ^1.83.0 - typescript: '>=5.7.2' - vue: ^3.5.13 - vue-tsc: ^1.8.27 || ^2.0.21 - peerDependenciesMeta: - sass: - optional: true - typescript: - optional: true - vue: - optional: true - vue-tsc: - optional: true + monaco-editor: '>=0.30.0' + + monaco-yaml@5.2.3: + resolution: {integrity: sha512-GEplKC+YYmS0TOlJdv0FzbqkDN/IG2FSwEw+95myECVxTlhty2amwERYjzvorvJXmIagP1grd3Lleq7aQEJpPg==} + peerDependencies: + monaco-editor: '>=0.36' - mlly@1.7.4: - resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} + mono-jsx@0.8.2: + resolution: {integrity: sha512-MxDtxbsdIIn4aZ4Ml6D13jyovuIoLIRWhf+ObcMwXYe+F6SUR1UJHKdzL53EsY9UNyRN9dBdSuNx0GhKGkA/vw==} + hasBin: true + + mono-jsx@0.9.10: + resolution: {integrity: sha512-gDgJQuNzDiyLYkKLHBzleUBxVMwK+4nA0htHS8A2MmzADbbctS7enRzk1aRQf97j321aPOC5knQs8cJJg6qjoA==} + hasBin: true - moo@0.5.2: - resolution: {integrity: sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==} + moo@0.5.3: + resolution: {integrity: sha512-m2fmM2dDm7GZQsY7KK2cme8agi+AAljILjQnof7p1ZMDe6dQ4bdnSMx0cPppudoeNv5hEFQirN6u+O4fDE0IWA==} mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} @@ -4225,40 +5300,41 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - mustache@4.2.0: - resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} - hasBin: true - - nano-jsx@0.0.37: - resolution: {integrity: sha512-0gVuDCLqKR3t0C4m2vvx8EW5MLxlAB9XAyLfJRhXIX9QfAMBFUn/wwEYT8+t6XgL5cMiuG+a8eZAXA/+wB026w==} - engines: {node: '>=12'} + nano-jsx@0.2.1: + resolution: {integrity: sha512-0zTNveaQn6aUCk01bLmywK1209zaxg+1gCTqm33VH05kWxmkng9GAdmzDky2Oy6wZ4GstaEa7PqH8Ll2Ygfbkw==} + engines: {node: '>=18'} - nanoid@3.3.9: - resolution: {integrity: sha512-SppoicMGpZvbF1l3z4x7No3OlIjP7QJvC9XR7AhZr1kL133KHnKPztkKDc+Ir4aJ/1VhTySrtKhrsycmrMQfvg==} + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - nanoid@5.1.3: - resolution: {integrity: sha512-zAbEOEr7u2CbxwoMRlz/pNSpRP0FdAU4pRaYunCdEezWohXFs+a0Xw7RfkKaezMsmSM1vttcLthJtwRnVtOfHQ==} + nanoid@5.1.6: + resolution: {integrity: sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==} engines: {node: ^18 || >=20} hasBin: true napi-build-utils@2.0.0: resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} - natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - nearley@2.20.1: resolution: {integrity: sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==} hasBin: true - negotiator@0.6.3: - resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} - node-abi@3.74.0: - resolution: {integrity: sha512-c5XK0MjkGBrQPGYG24GBADZud0NCbznxNx0ZkS+ebUTrmV1qTDxPxSL8zEAPURXSbLRWVexxmP4986BziahL5w==} + neverpanic@0.0.5: + resolution: {integrity: sha512-daO+ijOQG8g2BXaAwpETa0GUvlIAfqC+1/CUdLp2Ga8qwDaUyHIieX/SM0yZoPBf7k92deq4DO7tZOWWeL063Q==} + peerDependencies: + typescript: '5' + + nf3@0.3.11: + resolution: {integrity: sha512-ObKp/SA3f1g1f/OMeDlRWaZmqGgk7A0NnDIbeO7c/MV4r/quMlpP/BsqMGuTi3lUlXbC1On8YH7ICM2u2bIAOw==} + + node-abi@3.88.0: + resolution: {integrity: sha512-At6b4UqIEVudaqPsXjmUO1r/N5BUr4yhDGs5PkBE8/oG5+TfLPhFechiskFsnT6Ql0VfUXbalUUCbfXxtj7K+w==} engines: {node: '>=10'} node-addon-api@4.3.0: @@ -4267,8 +5343,8 @@ packages: node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} - node-fetch-native@1.6.6: - resolution: {integrity: sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==} + node-fetch-native@1.6.7: + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} @@ -4279,44 +5355,28 @@ packages: encoding: optional: true - node-forge@1.3.1: - resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} + node-forge@1.3.3: + resolution: {integrity: sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==} engines: {node: '>= 6.13.0'} - node-gyp-build@4.8.4: - resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} - hasBin: true - - node-mock-http@1.0.0: - resolution: {integrity: sha512-0uGYQ1WQL1M5kKvGRXWQ3uZCHtLTO8hln3oBjIusM75WoesZ909uQJs/Hb946i2SS+Gsrhkaa6iAO17jRIv6DQ==} - - node-releases@2.0.19: - resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + node-html-parser@6.1.13: + resolution: {integrity: sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==} - nopt@8.1.0: - resolution: {integrity: sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==} - engines: {node: ^18.17.0 || >=20.5.0} - hasBin: true + node-persist@4.0.4: + resolution: {integrity: sha512-8sPAz/7tw1mCCc8xBG4f0wi+flHkSSgQeX998iQ75Pu27evA6UUWCjSE7xnrYTg2q33oU5leJ061EKPDv6BocQ==} + engines: {node: '>=10.12.0'} - normalize-package-data@2.5.0: - resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} + node-releases@2.0.36: + resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - normalize-range@0.1.2: - resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} - engines: {node: '>=0.10.0'} - npm-run-path@4.0.1: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} - npm-run-path@5.3.0: - resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - npm-run-path@6.0.0: resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} engines: {node: '>=18'} @@ -4324,32 +5384,41 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - nypm@0.6.0: - resolution: {integrity: sha512-mn8wBFV9G9+UFHIrq+pZ2r2zL4aPau/by3kJb3cM7+5tQHMt6HGQB8FDIeKFYp8o0D2pnH6nVsO88N4AmUxIWg==} - engines: {node: ^14.16.0 || >=16.10.0} + nypm@0.6.5: + resolution: {integrity: sha512-K6AJy1GMVyfyMXRVB88700BJqNUkByijGJM8kEHpLdcAt+vSQAVfkWWHYzuRXHSY6xA2sNc5RjTj0p9rE2izVQ==} + engines: {node: '>=18'} hasBin: true - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - - object-hash@3.0.0: - resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} - engines: {node: '>= 6'} + oauth4webapi@3.8.5: + resolution: {integrity: sha512-A8jmyUckVhRJj5lspguklcl90Ydqk61H3dcU0oLhH3Yv13KpAliKTt5hknpGGPZSSfOwGyraNEFmofDYH+1kSg==} object-inspect@1.13.4: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} - ofetch@1.4.1: - resolution: {integrity: sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==} + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + + obuild@0.4.32: + resolution: {integrity: sha512-U6NNt0ZL6lCE6B6aU+qcBwbFU4g2DwrO/68aKhyXNUXgq0jf+fyHg9s9+ETZOLmlfJvQwub5mHF3aohGgWGYKQ==} + hasBin: true + + ocache@0.1.2: + resolution: {integrity: sha512-lI34wjM7cahEdrq2I5obbF7MEdE97vULf6vNj6ZCzwEadzyXO1w7QOl2qzzG4IL8cyO7wDtXPj9CqW/aG3mn7g==} - ohash@1.1.6: - resolution: {integrity: sha512-TBu7PtV8YkAZn0tSxobKY2n2aAQva936lhRrj6957aDaCf9IEtqsKbgMzXE/F/sjqYOwmrukeORHNLe5glk7Cg==} + ofetch@1.5.1: + resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} + + ofetch@2.0.0-alpha.3: + resolution: {integrity: sha512-zpYTCs2byOuft65vI3z43Dd6iSdFbOZZLb9/d21aCpx2rGastVU9dOCv0lu4ykc1Ur1anAYjDi3SUvR0vq50JA==} ohash@2.0.11: resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + on-exit-leak-free@2.1.2: + resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} + engines: {node: '>=14.0.0'} + on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} @@ -4361,27 +5430,25 @@ packages: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} - onetime@6.0.0: - resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} - engines: {node: '>=12'} + oniguruma-parser@0.12.1: + resolution: {integrity: sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==} - open@10.1.0: - resolution: {integrity: sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==} + oniguruma-to-es@4.3.4: + resolution: {integrity: sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==} + + open@10.2.0: + resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} engines: {node: '>=18'} open@8.4.2: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} - openapi-typescript@7.6.1: - resolution: {integrity: sha512-F7RXEeo/heF3O9lOXo2bNjCOtfp7u+D6W3a3VNEH2xE6v+fxLtn5nq0uvUcA1F5aT+CMhNeC5Uqtg5tlXFX/ag==} - hasBin: true - peerDependencies: - typescript: ^5.x + openapi-types@12.1.3: + resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==} - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} + openid-client@6.8.2: + resolution: {integrity: sha512-uOvTCndr4udZsKihJ68H9bUICrriHdUVJ6Az+4Ns6cW55rwM5h0bjVIzDz2SxgOI84LKjFyjOFvERLzdTUROGA==} ora@5.4.1: resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} @@ -4391,37 +5458,44 @@ packages: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} + oxfmt@0.40.0: + resolution: {integrity: sha512-g0C3I7xUj4b4DcagevM9kgH6+pUHytikxUcn3/VUkvzTNaaXBeyZqb7IBsHwojeXm4mTBEC/aBjBTMVUkZwWUQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + oxlint@1.55.0: + resolution: {integrity: sha512-T+FjepiyWpaZMhekqRpH8Z3I4vNM610p6w+Vjfqgj5TZUxHXl7N8N5IPvmOU8U4XdTRxqtNNTh9Y4hLtr7yvFg==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + oxlint-tsgolint: '>=0.15.0' + peerDependenciesMeta: + oxlint-tsgolint: + optional: true + p-event@4.2.0: resolution: {integrity: sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==} engines: {node: '>=8'} + p-event@6.0.1: + resolution: {integrity: sha512-Q6Bekk5wpzW5qIyUP4gdMEujObYstZl6DMMOSenwBvV0BlE5LkDwkjs5yHbZmdCEq2o4RJx4tE1vwxFVf2FG1w==} + engines: {node: '>=16.17'} + p-finally@1.0.0: resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} engines: {node: '>=4'} - p-limit@2.3.0: - resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} - engines: {node: '>=6'} - p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} - p-locate@4.1.0: - resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} - engines: {node: '>=8'} - - p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - p-timeout@3.2.0: resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==} engines: {node: '>=8'} - p-try@2.2.0: - resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} - engines: {node: '>=6'} + p-timeout@6.1.4: + resolution: {integrity: sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==} + engines: {node: '>=14.16'} package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} @@ -4430,38 +5504,32 @@ packages: resolution: {integrity: sha512-ua1L4OgXSBdsu1FPb7F3tYH0F48a6kxvod4pLUlGY9COeJAJQNX/sNH2IiEmsxw7lqYiAwrdHMjz1FctOsyDQg==} engines: {node: '>=18'} - packrup@0.1.2: - resolution: {integrity: sha512-ZcKU7zrr5GlonoS9cxxrb5HVswGnyj6jQvwFBa6p5VFw7G71VAHcUKL5wyZSU/ECtPM/9gacWxy2KFQKt1gMNA==} - - parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - - parse-entities@2.0.0: - resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==} - - parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} - - parse-json@8.1.0: - resolution: {integrity: sha512-rum1bPifK5SSar35Z6EKZuYPJx85pkNaFrxBK3mwdfSJ1/WKbYrjoW/zTPSjRRamfmVX1ACBIdFAO0VRErW/EA==} - engines: {node: '>=18'} + package-name-regex@2.0.6: + resolution: {integrity: sha512-gFL35q7kbE/zBaPA3UKhp2vSzcPYx2ecbYuwv1ucE9Il6IIgBDweBlH8D68UFGZic2MkllKa2KHCfC1IQBQUYA==} + engines: {node: '>=12'} parse-ms@2.1.0: resolution: {integrity: sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==} engines: {node: '>=6'} - parse-ms@3.0.0: - resolution: {integrity: sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==} - engines: {node: '>=12'} - parse-ms@4.0.0: resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} engines: {node: '>=18'} - parse5@7.2.1: - resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==} + parse-path@7.1.0: + resolution: {integrity: sha512-EuCycjZtfPcjWk7KTksnJ5xPMvWGA/6i4zrLYhRG0hGvC3GPU/jGUj3Cy+ZR0v30duV3e23R95T1lE2+lsndSw==} + + parse-url@8.1.0: + resolution: {integrity: sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w==} + + parse5-htmlparser2-tree-adapter@7.1.0: + resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} + + parse5-parser-stream@7.1.2: + resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==} + + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} @@ -4470,9 +5538,8 @@ packages: password-prompt@1.1.3: resolution: {integrity: sha512-HkrjG2aJlvF0t2BMH0e2LB/EHf3Lcq3fNMzy4GYHcQblAvOl+QQji1Lx7WRBMqpVK8p+KR7bCg7oqAMXtdgqyw==} - path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} @@ -4493,29 +5560,24 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} - path-to-regexp@0.1.12: - resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} - - path-type@6.0.0: - resolution: {integrity: sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==} - engines: {node: '>=18'} + path-to-regexp@6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} - pathe@1.1.2: - resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + path-to-regexp@8.3.0: + resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - pathval@2.0.0: - resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} - engines: {node: '>= 14.16'} - pem@1.14.8: resolution: {integrity: sha512-ZpbOf4dj9/fQg5tQzTqv4jSKJQsK7tPl0pm4/pvPcZVjZcJg7TMfr3PBk6gJH97lnpJDu4e4v8UUqEz5daipCg==} engines: {node: '>=14.0.0'} - perfect-debounce@1.0.0: - resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + perfect-debounce@2.1.0: + resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==} + + periscopic@4.0.2: + resolution: {integrity: sha512-sqpQDUy8vgB7ycLkendSKS6HnVz1Rneoc3Rc+ZBUCe2pbqlVuCC5vF52l0NJ1aiMg/r1qfYF9/myz8CZeI2rjA==} picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -4524,263 +5586,87 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - picomatch@4.0.2: - resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} - pkg-types@1.3.1: - resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} - - pkg-types@2.1.0: - resolution: {integrity: sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==} - - pluralize@8.0.0: - resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} - engines: {node: '>=4'} - - postcss-calc@10.1.1: - resolution: {integrity: sha512-NYEsLHh8DgG/PRH2+G9BTuUdtf9ViS+vdoQ0YA5OQdGsfN4ztiwtDWNtBl9EKeqNMFnIu8IKZ0cLxEQ5r5KVMw==} - engines: {node: ^18.12 || ^20.9 || >=22.0} - peerDependencies: - postcss: ^8.4.38 - - postcss-colormin@7.0.2: - resolution: {integrity: sha512-YntRXNngcvEvDbEjTdRWGU606eZvB5prmHG4BF0yLmVpamXbpsRJzevyy6MZVyuecgzI2AWAlvFi8DAeCqwpvA==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-convert-values@7.0.4: - resolution: {integrity: sha512-e2LSXPqEHVW6aoGbjV9RsSSNDO3A0rZLCBxN24zvxF25WknMPpX8Dm9UxxThyEbaytzggRuZxaGXqaOhxQ514Q==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-discard-comments@7.0.3: - resolution: {integrity: sha512-q6fjd4WU4afNhWOA2WltHgCbkRhZPgQe7cXF74fuVB/ge4QbM9HEaOIzGSiMvM+g/cOsNAUGdf2JDzqA2F8iLA==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-discard-duplicates@7.0.1: - resolution: {integrity: sha512-oZA+v8Jkpu1ct/xbbrntHRsfLGuzoP+cpt0nJe5ED2FQF8n8bJtn7Bo28jSmBYwqgqnqkuSXJfSUEE7if4nClQ==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-discard-empty@7.0.0: - resolution: {integrity: sha512-e+QzoReTZ8IAwhnSdp/++7gBZ/F+nBq9y6PomfwORfP7q9nBpK5AMP64kOt0bA+lShBFbBDcgpJ3X4etHg4lzA==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-discard-overridden@7.0.0: - resolution: {integrity: sha512-GmNAzx88u3k2+sBTZrJSDauR0ccpE24omTQCVmaTTZFz1du6AasspjaUPMJ2ud4RslZpoFKyf+6MSPETLojc6w==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-merge-longhand@7.0.4: - resolution: {integrity: sha512-zer1KoZA54Q8RVHKOY5vMke0cCdNxMP3KBfDerjH/BYHh4nCIh+1Yy0t1pAEQF18ac/4z3OFclO+ZVH8azjR4A==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-merge-rules@7.0.4: - resolution: {integrity: sha512-ZsaamiMVu7uBYsIdGtKJ64PkcQt6Pcpep/uO90EpLS3dxJi6OXamIobTYcImyXGoW0Wpugh7DSD3XzxZS9JCPg==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-minify-font-values@7.0.0: - resolution: {integrity: sha512-2ckkZtgT0zG8SMc5aoNwtm5234eUx1GGFJKf2b1bSp8UflqaeFzR50lid4PfqVI9NtGqJ2J4Y7fwvnP/u1cQog==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-minify-gradients@7.0.0: - resolution: {integrity: sha512-pdUIIdj/C93ryCHew0UgBnL2DtUS3hfFa5XtERrs4x+hmpMYGhbzo6l/Ir5de41O0GaKVpK1ZbDNXSY6GkXvtg==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-minify-params@7.0.2: - resolution: {integrity: sha512-nyqVLu4MFl9df32zTsdcLqCFfE/z2+f8GE1KHPxWOAmegSo6lpV2GNy5XQvrzwbLmiU7d+fYay4cwto1oNdAaQ==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-minify-selectors@7.0.4: - resolution: {integrity: sha512-JG55VADcNb4xFCf75hXkzc1rNeURhlo7ugf6JjiiKRfMsKlDzN9CXHZDyiG6x/zGchpjQS+UAgb1d4nqXqOpmA==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-nested@7.0.2: - resolution: {integrity: sha512-5osppouFc0VR9/VYzYxO03VaDa3e8F23Kfd6/9qcZTUI8P58GIYlArOET2Wq0ywSl2o2PjELhYOFI4W7l5QHKw==} - engines: {node: '>=18.0'} - peerDependencies: - postcss: ^8.2.14 - - postcss-normalize-charset@7.0.0: - resolution: {integrity: sha512-ABisNUXMeZeDNzCQxPxBCkXexvBrUHV+p7/BXOY+ulxkcjUZO0cp8ekGBwvIh2LbCwnWbyMPNJVtBSdyhM2zYQ==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-normalize-display-values@7.0.0: - resolution: {integrity: sha512-lnFZzNPeDf5uGMPYgGOw7v0BfB45+irSRz9gHQStdkkhiM0gTfvWkWB5BMxpn0OqgOQuZG/mRlZyJxp0EImr2Q==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-normalize-positions@7.0.0: - resolution: {integrity: sha512-I0yt8wX529UKIGs2y/9Ybs2CelSvItfmvg/DBIjTnoUSrPxSV7Z0yZ8ShSVtKNaV/wAY+m7bgtyVQLhB00A1NQ==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-normalize-repeat-style@7.0.0: - resolution: {integrity: sha512-o3uSGYH+2q30ieM3ppu9GTjSXIzOrRdCUn8UOMGNw7Af61bmurHTWI87hRybrP6xDHvOe5WlAj3XzN6vEO8jLw==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-normalize-string@7.0.0: - resolution: {integrity: sha512-w/qzL212DFVOpMy3UGyxrND+Kb0fvCiBBujiaONIihq7VvtC7bswjWgKQU/w4VcRyDD8gpfqUiBQ4DUOwEJ6Qg==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-normalize-timing-functions@7.0.0: - resolution: {integrity: sha512-tNgw3YV0LYoRwg43N3lTe3AEWZ66W7Dh7lVEpJbHoKOuHc1sLrzMLMFjP8SNULHaykzsonUEDbKedv8C+7ej6g==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-normalize-unicode@7.0.2: - resolution: {integrity: sha512-ztisabK5C/+ZWBdYC+Y9JCkp3M9qBv/XFvDtSw0d/XwfT3UaKeW/YTm/MD/QrPNxuecia46vkfEhewjwcYFjkg==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-normalize-url@7.0.0: - resolution: {integrity: sha512-+d7+PpE+jyPX1hDQZYG+NaFD+Nd2ris6r8fPTBAjE8z/U41n/bib3vze8x7rKs5H1uEw5ppe9IojewouHk0klQ==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 + pino-abstract-transport@3.0.0: + resolution: {integrity: sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==} - postcss-normalize-whitespace@7.0.0: - resolution: {integrity: sha512-37/toN4wwZErqohedXYqWgvcHUGlT8O/m2jVkAfAe9Bd4MzRqlBmXrJRePH0e9Wgnz2X7KymTgTOaaFizQe3AQ==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-ordered-values@7.0.1: - resolution: {integrity: sha512-irWScWRL6nRzYmBOXReIKch75RRhNS86UPUAxXdmW/l0FcAsg0lvAXQCby/1lymxn/o0gVa6Rv/0f03eJOwHxw==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 - - postcss-reduce-initial@7.0.2: - resolution: {integrity: sha512-pOnu9zqQww7dEKf62Nuju6JgsW2V0KRNBHxeKohU+JkHd/GAH5uvoObqFLqkeB2n20mr6yrlWDvo5UBU5GnkfA==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 + pino-std-serializers@7.1.0: + resolution: {integrity: sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==} - postcss-reduce-transforms@7.0.0: - resolution: {integrity: sha512-pnt1HKKZ07/idH8cpATX/ujMbtOGhUfE+m8gbqwJE05aTaNw8gbo34a2e3if0xc0dlu75sUOiqvwCGY3fzOHew==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 + pino@10.3.1: + resolution: {integrity: sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==} + hasBin: true - postcss-selector-parser@6.1.2: - resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} - engines: {node: '>=4'} + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} - postcss-selector-parser@7.1.0: - resolution: {integrity: sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==} - engines: {node: '>=4'} + pkg-types@2.3.0: + resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} - postcss-svgo@7.0.1: - resolution: {integrity: sha512-0WBUlSL4lhD9rA5k1e5D8EN5wCEyZD6HJk0jIvRxl+FDVOMlJ7DePHYWGGVc5QRqrJ3/06FTXM0bxjmJpmTPSA==} - engines: {node: ^18.12.0 || ^20.9.0 || >= 18} - peerDependencies: - postcss: ^8.4.31 + postcss@8.5.8: + resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} + engines: {node: ^10 || ^12 || >=14} - postcss-unique-selectors@7.0.3: - resolution: {integrity: sha512-J+58u5Ic5T1QjP/LDV9g3Cx4CNOgB5vz+kM6+OxHHhFACdcDeKhBXjQmB7fnIZM12YSTvsL0Opwco83DmacW2g==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + preact-render-to-string@6.6.6: + resolution: {integrity: sha512-EfqZJytnjJldV+YaaqhthU2oXsEf5e+6rDv957p+zxAvNfFLQOPfvBOTncscQ+akzu6Wrl7s3Pa0LjUQmWJsGQ==} peerDependencies: - postcss: ^8.4.31 - - postcss-value-parser@4.2.0: - resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + preact: '>=10 || >= 11.0.0-0' - postcss@8.5.3: - resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} - engines: {node: ^10 || ^12 || >=14} + preact@10.29.0: + resolution: {integrity: sha512-wSAGyk2bYR1c7t3SZ3jHcM6xy0lcBcDel6lODcs9ME6Th++Dx2KU+6D3HD8wMMKGA8Wpw7OMd3/4RGzYRpzwRg==} prebuild-install@7.1.3: resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} engines: {node: '>=10'} + deprecated: No longer maintained. Please contact the author of the relevant native addon; alternatives are available. hasBin: true - prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} + prettier@2.8.8: + resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} + engines: {node: '>=10.13.0'} + hasBin: true - prettier@3.5.3: - resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==} + prettier@3.8.1: + resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} engines: {node: '>=14'} hasBin: true - pretty-bytes@6.1.1: - resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==} - engines: {node: ^14.13.1 || >=16.0.0} + pretty-bytes@7.1.0: + resolution: {integrity: sha512-nODzvTiYVRGRqAOvE84Vk5JDPyyxsVk0/fbA/bq7RqlnhksGpset09XTxbpvLTIjoaF7K8Z8DG8yHtKGTPSYRw==} + engines: {node: '>=20'} pretty-ms@7.0.1: resolution: {integrity: sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==} engines: {node: '>=10'} - pretty-ms@8.0.0: - resolution: {integrity: sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q==} - engines: {node: '>=14.16'} - - pretty-ms@9.2.0: - resolution: {integrity: sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg==} + pretty-ms@9.3.0: + resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==} engines: {node: '>=18'} - printable-characters@1.0.42: - resolution: {integrity: sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==} + process-warning@4.0.1: + resolution: {integrity: sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==} - process-nextick-args@2.0.1: - resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - - process@0.11.10: - resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} - engines: {node: '>= 0.6.0'} + process-warning@5.0.0: + resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} - property-information@6.5.0: - resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==} + proper-lockfile@4.1.2: + resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} - property-information@7.0.0: - resolution: {integrity: sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg==} + property-information@7.1.0: + resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} - proto3-json-serializer@2.0.2: - resolution: {integrity: sha512-SAzp/O4Yh02jGdRc+uIrGoe87dkN/XtwxfZ4ZyafJHymd79ozp5VG5nyZ7ygqPM5+cpLDjjGnYFUkngonyDPOQ==} - engines: {node: '>=14.0.0'} - - protobufjs@7.4.0: - resolution: {integrity: sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==} - engines: {node: '>=12.0.0'} + protocols@2.0.2: + resolution: {integrity: sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==} proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} @@ -4789,35 +5675,32 @@ packages: proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - pump@3.0.2: - resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - pupa@3.1.0: - resolution: {integrity: sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==} + pupa@3.3.0: + resolution: {integrity: sha512-LjgDO2zPtoXP2wJpDjZrGdojii1uqO0cnwKoIoUzkfS98HDmbeiGmYiXo3lXeFlq2xvne1QFQhwYXSUCLKtEuA==} engines: {node: '>=12.20'} - qs@6.13.0: - resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} + qs@6.15.0: + resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} engines: {node: '>=0.6'} - quansync@0.2.8: - resolution: {integrity: sha512-4+saucphJMazjt7iOM27mbFCk+D9dd/zmgMDCzRZ8MEoBfYp7lAvoN38et/phRQF6wOPMy/OROBGgoWeSKyluA==} + quansync@0.2.11: + resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} - queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} radix-vue@1.9.17: resolution: {integrity: sha512-mVCu7I2vXt1L2IUYHTt0sZMz7s1K2ZtqKeTIxG3yC5mMFfLBG4FtE1FDeRMpDd+Hhg/ybi9+iXmAP1ISREndoQ==} peerDependencies: vue: '>= 3.2.0' - radix3@1.1.2: - resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} - railroad-diagrams@1.0.0: resolution: {integrity: sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==} @@ -4825,77 +5708,74 @@ packages: resolution: {integrity: sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==} engines: {node: '>=0.12'} - randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - range-parser@1.2.1: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} - raw-body@2.5.2: - resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} - engines: {node: '>= 0.8'} + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} rc9@2.1.2: resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} + rc9@3.0.0: + resolution: {integrity: sha512-MGOue0VqscKWQ104udASX/3GYDcKyPI4j4F8gu/jHHzglpmy9a/anZK3PNe8ug6aZFl+9GxLtdhe3kVZuMaQbA==} + rc@1.2.8: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true - read-pkg-up@7.0.1: - resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} - engines: {node: '>=8'} + react-dom@19.2.4: + resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} + peerDependencies: + react: ^19.2.4 - read-pkg@5.2.0: - resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} - engines: {node: '>=8'} + react-refresh@0.18.0: + resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} + engines: {node: '>=0.10.0'} - readable-stream@2.3.8: - resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + react@19.2.4: + resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} + engines: {node: '>=0.10.0'} readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} - readable-stream@4.7.0: - resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} - readdir-glob@1.1.3: - resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} + readdirp@5.0.0: + resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} + engines: {node: '>= 20.19.0'} - readdirp@4.1.2: - resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} - engines: {node: '>= 14.18.0'} + real-require@0.2.0: + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} + engines: {node: '>= 12.13.0'} - redis-errors@1.2.0: - resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} - engines: {node: '>=4'} + recast@0.23.11: + resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==} + engines: {node: '>= 4'} - redis-parser@3.0.0: - resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==} - engines: {node: '>=4'} + regex-recursion@6.0.2: + resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} - regenerator-runtime@0.14.1: - resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + regex-utilities@2.3.0: + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} - regexp-tree@0.1.27: - resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} - hasBin: true + regex@6.1.0: + resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==} - registry-auth-token@5.1.0: - resolution: {integrity: sha512-GdekYuwLXLxMuFTwAPg5UKGLW/UXzQrZvH/Zj791BQif5T05T0RsaLfHc9q3ZOKi7n+BoprPD9mJ0O0k4xzUlw==} + registry-auth-token@5.1.1: + resolution: {integrity: sha512-P7B4+jq8DeD2nMsAcdfaqHbssgHtZ7Z5+++a5ask90fvmJ8p5je4mOa+wzu+DB4vQ5tdJV/xywY+UnVFeQLV5Q==} engines: {node: '>=14'} registry-url@6.0.1: resolution: {integrity: sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==} engines: {node: '>=12'} - regjsparser@0.10.0: - resolution: {integrity: sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==} - hasBin: true - rehype-external-links@3.0.0: resolution: {integrity: sha512-yp+e5N9V3C6bwBeAC4n796kc86M4gJCdlVhiMTxIrJG5UHDMh+PJANf9heqORJbt1nrCbDwIlAZKjANIaVBbvw==} @@ -4920,12 +5800,16 @@ packages: remark-parse@11.0.0: resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} - remark-rehype@11.1.1: - resolution: {integrity: sha512-g/osARvjkBXb6Wo0XvAeXQohVta8i84ACbenPpoSsxTOQH/Ae0/RGP4WZgnMH5pMLpsj4FG7OHmcIcXxpza8eQ==} + remark-rehype@11.1.2: + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} remark-stringify@11.0.0: resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + rendu@0.0.7: + resolution: {integrity: sha512-zR9sesmefLrWv41owJ3GP3vSRCDhMNDkiKQ7U5pZtTLr2eUkXbcXAi0VxAj2eGnJjv2fbJp6W2YOE5nV/R3mNw==} + hasBin: true + require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -4937,16 +5821,15 @@ packages: requires-port@1.0.0: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} - resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} + reserved-identifiers@1.2.0: + resolution: {integrity: sha512-yE7KUfFvaBFzGPs5H3Ops1RevfUEsDc5Iz65rOwWg4lE8HJSYtle77uul3+573457oHvBKuHYDl/xqUkKpEEdw==} + engines: {node: '>=18'} - resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - resolve@1.22.10: - resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} engines: {node: '>= 0.4'} hasBin: true @@ -4958,18 +5841,21 @@ packages: resolution: {integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==} engines: {node: '>=0.12'} - retry-request@7.0.2: - resolution: {integrity: sha512-dUOvLMJ0/JJYEn8NrpOaGNE7X3vpI5XlZS/u0ANjqtcZVKnIxP7IgCFwrKTxENw29emmwug53awKtaMm4i9g5w==} - engines: {node: '>=14'} + ret@0.5.0: + resolution: {integrity: sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==} + engines: {node: '>=10'} - retry@0.13.1: - resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} + retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} engines: {node: '>= 4'} reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + rimraf@2.7.1: resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} deprecated: Rimraf versions prior to v4 are no longer supported @@ -4979,86 +5865,137 @@ packages: resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==} hasBin: true - rollup-plugin-dts@6.1.1: - resolution: {integrity: sha512-aSHRcJ6KG2IHIioYlvAOcEq6U99sVtqDDKVhnwt70rW6tsz3tv5OSjEiWcgzfsHdLyGXZ/3b/7b/+Za3Y6r1XA==} - engines: {node: '>=16'} - peerDependencies: - rollup: ^3.29.4 || ^4 - typescript: ^4.5 || ^5.0 - - rollup-plugin-visualizer@5.14.0: - resolution: {integrity: sha512-VlDXneTDaKsHIw8yzJAFWtrzguoJ/LnQ+lMpoVfYJ3jJF4Ihe5oYLAqLklIK/35lgUY+1yEzCkHyZ1j4A5w5fA==} - engines: {node: '>=18'} - hasBin: true + rolldown-plugin-dts@0.22.5: + resolution: {integrity: sha512-M/HXfM4cboo+jONx9Z0X+CUf3B5tCi7ni+kR5fUW50Fp9AlZk0oVLesibGWgCXDKFp5lpgQ9yhKoImUFjl3VZw==} + engines: {node: '>=20.19.0'} peerDependencies: - rolldown: 1.x - rollup: 2.x || 3.x || 4.x + '@ts-macro/tsc': ^0.3.6 + '@typescript/native-preview': '>=7.0.0-dev.20250601.1' + rolldown: ^1.0.0-rc.8 + typescript: ^5.0.0 || ^6.0.0-beta + vue-tsc: ~3.2.0 peerDependenciesMeta: - rolldown: + '@ts-macro/tsc': optional: true - rollup: + '@typescript/native-preview': + optional: true + typescript: + optional: true + vue-tsc: optional: true - rollup@4.35.0: - resolution: {integrity: sha512-kg6oI4g+vc41vePJyO6dHt/yl0Rz3Thv0kJeVQ3D1kS3E5XSuKbPc29G4IpT/Kv1KQwgHVcN+HtyS+HYLNSvQg==} + rolldown@1.0.0-rc.9: + resolution: {integrity: sha512-9EbgWge7ZH+yqb4d2EnELAntgPTWbfL8ajiTW+SyhJEC4qhBbkCKbqFV4Ge4zmu5ziQuVbWxb/XwLZ+RIO7E8Q==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + rollup-plugin-license@3.7.0: + resolution: {integrity: sha512-RvvOIF+GH3fBR3wffgc/vmjQn6qOn72WjppWVDp/v+CLpT0BbcRBdSkPeeIOL6U5XccdYgSIMjUyXgxlKEEFcw==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0 + + rollup@4.59.0: + resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true - run-applescript@7.0.0: - resolution: {integrity: sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==} - engines: {node: '>=18'} + rou3@0.8.1: + resolution: {integrity: sha512-ePa+XGk00/3HuCqrEnK3LxJW7I0SdNg6EFzKUJG73hMAdDcOUC/i/aSz7LSDwLrGr33kal/rqOGydzwl6U7zBA==} + + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + + rsc-html-stream@0.0.7: + resolution: {integrity: sha512-v9+fuY7usTgvXdNl8JmfXCvSsQbq2YMd60kOeeMIqCJFZ69fViuIxztHei7v5mlMMa2h3SqS+v44Gu9i9xANZA==} - run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + run-applescript@7.1.0: + resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} + engines: {node: '>=18'} rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} - safe-buffer@5.1.2: - resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safe-regex2@5.1.0: + resolution: {integrity: sha512-pNHAuBW7TrcleFHsxBr5QMi/Iyp0ENjUKz7GCcX1UO7cMh+NmVK6HxQckNL1tJp1XAJVjG6B8OKIPqodqj9rtw==} + hasBin: true + + safe-stable-stringify@2.5.0: + resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} + engines: {node: '>=10'} + safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sax@1.4.1: - resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} + sax@1.5.0: + resolution: {integrity: sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==} + engines: {node: '>=11.0.0'} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} scule@1.3.0: resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==} + secure-json-parse@4.1.0: + resolution: {integrity: sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==} + selfsigned@2.4.1: resolution: {integrity: sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==} engines: {node: '>=10'} - semver@5.7.2: - resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.7.1: - resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} engines: {node: '>=10'} hasBin: true - send@0.19.0: - resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} + send@0.19.2: + resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==} engines: {node: '>= 0.8.0'} - serialize-javascript@6.0.2: - resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + + seroval-plugins@1.5.1: + resolution: {integrity: sha512-4FbuZ/TMl02sqv0RTFexu0SP6V+ywaIe5bAWCCEik0fk17BhALgwvUDVF7e3Uvf9pxmwCEJsRPmlkUE6HdzLAw==} + engines: {node: '>=10'} + peerDependencies: + seroval: ^1.0 + + seroval@1.5.1: + resolution: {integrity: sha512-OwrZRZAfhHww0WEnKHDY8OM0U/Qs8OTfIDWhUD4BLpNJUfXK4cGmjiagGze086m+mhI+V2nD0gfbHEnJjb9STA==} + engines: {node: '>=10'} serve-placeholder@2.0.2: resolution: {integrity: sha512-/TMG8SboeiQbZJWRlfTCqMs2DD3SZgWp0kDQePz9yUuCnDfDh/92gf7/PxGhzXTKBIPASIHxFcZndoNbp6QOLQ==} - serve-static@1.16.2: - resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} + serve-static@1.16.3: + resolution: {integrity: sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==} engines: {node: '>= 0.8.0'} + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + + set-cookie-parser@2.7.2: + resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -5067,10 +6004,13 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - shell-quote@1.8.2: - resolution: {integrity: sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==} + shell-quote@1.8.3: + resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} engines: {node: '>= 0.4'} + shiki@3.23.0: + resolution: {integrity: sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA==} + side-channel-list@1.0.0: resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} engines: {node: '>= 0.4'} @@ -5101,6 +6041,9 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + simple-code-frame@1.3.0: + resolution: {integrity: sha512-MB4pQmETUBlNs62BBeRjIFGeuy/x6gGKh7+eRUemn1rCFhqo7K+4slPqsyizCbcbYLnaYqaoZ2FWsZ/jN06D8w==} + simple-concat@1.0.1: resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} @@ -5110,31 +6053,32 @@ packages: sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - slash@5.1.0: - resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} - engines: {node: '>=14.16'} - - smob@1.5.0: - resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==} - smtp-address-parser@1.0.10: resolution: {integrity: sha512-Osg9LmvGeAG/hyao4mldbflLOkkr3a+h4m1lwKCK5U8M6ZAr7tdXEz/+/vr752TSGE4MNUlUl9cIK2cB8cgzXg==} engines: {node: '>=0.10'} + solid-js@1.9.11: + resolution: {integrity: sha512-WEJtcc5mkh/BnHA6Yrg4whlF8g6QwpmXXRg4P2ztPmcKeHHlH4+djYecBLhSpecZY2RRECXYUwIc/C2r3yzQ4Q==} + + solid-refresh@0.6.3: + resolution: {integrity: sha512-F3aPsX6hVw9ttm5LYlth8Q15x6MlI/J3Dn+o3EQyRTtTxidepSTwAYdozt01/YA+7ObcciagGEyXIopGZzQtbA==} + peerDependencies: + solid-js: ^1.3 + + sonic-boom@4.2.1: + resolution: {integrity: sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} - source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} - source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} - source-map@0.7.4: - resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} - engines: {node: '>= 8'} + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} @@ -5142,8 +6086,8 @@ packages: spawn-command@0.0.2: resolution: {integrity: sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==} - spdx-correct@3.2.0: - resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + spdx-compare@1.0.0: + resolution: {integrity: sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A==} spdx-exceptions@2.5.0: resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} @@ -5151,37 +6095,56 @@ packages: spdx-expression-parse@3.0.1: resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} - spdx-license-ids@3.0.21: - resolution: {integrity: sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==} + spdx-expression-validate@2.0.0: + resolution: {integrity: sha512-b3wydZLM+Tc6CFvaRDBOF9d76oGIHNCLYFeHbftFXUWjnfZWganmDmvtM5sm1cRwJc/VDBMLyGGrsLFd1vOxbg==} - stackback@0.0.2: - resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + spdx-license-ids@3.0.23: + resolution: {integrity: sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==} - stacktracey@2.1.8: - resolution: {integrity: sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==} + spdx-ranges@2.1.1: + resolution: {integrity: sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA==} - standard-as-callback@2.1.0: - resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} + spdx-satisfies@5.0.1: + resolution: {integrity: sha512-Nwor6W6gzFp8XX4neaKQ7ChV4wmpSh2sSDemMFSzHxpTw460jxFYeOn+jq4ybnSSw/5sc3pjka9MQPouksQNpw==} - statuses@2.0.1: - resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} - engines: {node: '>= 0.8'} + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + srvx@0.11.9: + resolution: {integrity: sha512-97wWJS6F0KTKAhDlHVmBzMvlBOp5FiNp3XrLoodIgYJpXxgG5tE9rX4Pg7s46n2shI4wtEsMATTS1+rI3/ubzA==} + engines: {node: '>=20.16.0'} + hasBin: true + + srvx@0.9.8: + resolution: {integrity: sha512-RZaxTKJEE/14HYn8COLuUOJAt0U55N9l1Xf6jj+T0GoA01EUH1Xz5JtSUOI+EHn+AEgPCVn7gk6jHJffrr06fQ==} + engines: {node: '>=20.16.0'} + hasBin: true - std-env@3.8.1: - resolution: {integrity: sha512-vj5lIj3Mwf9D79hBkltk5qmkFI+biIKWS2IBxEyEU3AX1tUf7AoL8nSazCOiiqQsGKIq01SClsKEzweu34uwvA==} + stack-trace@1.0.0-pre2: + resolution: {integrity: sha512-2ztBJRek8IVofG9DBJqdy2N5kulaacX30Nz7xmkYF6ale9WBVmIy6mFBchvGX7Vx/MyjBhx+Rcxqrj+dbOnQ6A==} + engines: {node: '>=16'} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - stoppable@1.1.0: - resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==} - engines: {node: '>=4', npm: '>=6'} + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} - stream-events@1.0.5: - resolution: {integrity: sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==} + std-env@4.0.0: + resolution: {integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==} - stream-shift@1.0.3: - resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} + string-byte-length@3.0.1: + resolution: {integrity: sha512-yJ8vP0HMwZ54CcA8S8mKoXbkezpZHANFtmafFo8lGxZThCQcAwRHjdFabuSLgOzxj9OFJcmssmiAvmcOK4O2Hw==} + engines: {node: '>=18.18.0'} - streamx@2.22.0: - resolution: {integrity: sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==} + string-byte-slice@3.0.1: + resolution: {integrity: sha512-GWv2K4lYyd2+AhmKH3BV+OVx62xDX+99rSLfKpaqFiQU7uOMaUY1tDjdrRD4gsrCr9lTyjMgjna7tZcCOw+Smg==} + engines: {node: '>=18.18.0'} string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} @@ -5195,78 +6158,62 @@ packages: resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} - string_decoder@1.1.1: - resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} - string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} stringify-entities@4.0.4: resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} - stringify-object@5.0.0: - resolution: {integrity: sha512-zaJYxz2FtcMb4f+g60KsRNFOpVMUyuJgA51Zi5Z1DOTC3S59+OQiVOzE9GZt0x72uBGWKsQIuBKeF9iusmKFsg==} - engines: {node: '>=14.16'} + stringify-object@6.0.0: + resolution: {integrity: sha512-6f94vIED6vmJJfh3lyVsVWxCYSfI5uM+16ntED/Ql37XIyV6kj0mRAAiTeMMc/QLYIaizC3bUprQ8pQnDDrKfA==} + engines: {node: '>=20'} strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} - strip-ansi@7.1.0: - resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} engines: {node: '>=12'} strip-final-newline@2.0.0: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} - strip-final-newline@3.0.0: - resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} - engines: {node: '>=12'} - strip-final-newline@4.0.0: resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==} engines: {node: '>=18'} - strip-indent@3.0.0: - resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} - engines: {node: '>=8'} - strip-json-comments@2.0.1: resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} engines: {node: '>=0.10.0'} - strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - - strip-literal@3.0.0: - resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==} + strip-literal@3.1.0: + resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} - strnum@1.1.2: - resolution: {integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==} - - stubborn-fs@1.2.5: - resolution: {integrity: sha512-H2N9c26eXjzL/S/K+i/RHHcFanE74dptvvjM8iwzwbVcWY/zjBbgRqF3K0DY4+OD+uTTASTBvDoxPDaPN02D7g==} + strtok3@10.3.4: + resolution: {integrity: sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==} + engines: {node: '>=18'} - stubs@3.0.0: - resolution: {integrity: sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==} + stubborn-fs@2.0.0: + resolution: {integrity: sha512-Y0AvSwDw8y+nlSNFXMm2g6L51rBGdAQT20J3YSOqxC53Lo3bjWRtr2BKcfYoAf352WYpsZSTURrA0tqhfgudPA==} - style-mod@4.1.2: - resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==} + stubborn-utils@1.0.2: + resolution: {integrity: sha512-zOh9jPYI+xrNOyisSelgym4tolKTJCQd5GBhK0+0xJvcYDcwlOoxF/rnFKQ2KRZknXSG9jWAp66fwP6AxN9STg==} - stylehacks@7.0.4: - resolution: {integrity: sha512-i4zfNrGMt9SB4xRK9L83rlsFCgdGANfeDAYacO1pkqcE7cRHPdWHwnKZVz7WY17Veq/FvyYsRAU++Ga+qDFIww==} - engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} - peerDependencies: - postcss: ^8.4.31 + style-mod@4.1.3: + resolution: {integrity: sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==} sudo-prompt@8.2.5: resolution: {integrity: sha512-rlBo3HU/1zAJUrkY6jNxDOC9eVYliG6nS4JA8u8KAshITd07tafMc/Br7xQwCSseXwJ2iCcHCE8SNWX3q8Z+kw==} deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - supports-color@10.0.0: - resolution: {integrity: sha512-HRVVSbCCMbj7/kdWF9Q+bbckjBHLtHMEoJWlkmYzzdwhYMkjkOwubLM6t7NbWKjgKamGDrWL1++KrjUO1t9oAQ==} + super-regex@1.1.0: + resolution: {integrity: sha512-WHkws2ZflZe41zj6AolvvmaTrWds/VuyeYr9iPVv/oQeaIoVxMKaushfFWpOGDT+GuBrM/sVqF8KUCYQlSSTdQ==} + engines: {node: '>=18'} + + supports-color@10.2.2: + resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} engines: {node: '>=18'} supports-color@7.2.0: @@ -5277,91 +6224,79 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} - supports-color@9.4.0: - resolution: {integrity: sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==} - engines: {node: '>=12'} - supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - svgo@3.3.2: - resolution: {integrity: sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==} - engines: {node: '>=14.0.0'} - hasBin: true + swrv@1.1.0: + resolution: {integrity: sha512-pjllRDr2s0iTwiE5Isvip51dZGR7GjLH1gCSVyE8bQnbAx6xackXsFdojau+1O5u98yHF5V73HQGOFxKUXO9gQ==} + peerDependencies: + vue: '>=3.2.26 < 4' - system-architecture@0.1.0: - resolution: {integrity: sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA==} - engines: {node: '>=18'} + tabbable@6.4.0: + resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==} - tabbable@6.2.0: - resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} + tagged-tag@1.0.0: + resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} + engines: {node: '>=20'} - tailwind-merge@2.6.0: - resolution: {integrity: sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==} + tailwind-merge@3.4.0: + resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==} - tailwindcss@4.0.12: - resolution: {integrity: sha512-bT0hJo91FtncsAMSsMzUkoo/iEU0Xs5xgFgVC9XmdM9bw5MhZuQFjPNl6wxAE0SiQF/YTZJa+PndGWYSDtuxAg==} + tailwind-merge@3.5.0: + resolution: {integrity: sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==} - tar-fs@2.1.2: - resolution: {integrity: sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==} + tailwindcss@4.2.1: + resolution: {integrity: sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==} - tar-stream@2.2.0: - resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} - tar-stream@3.1.7: - resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} + tar-fs@2.1.4: + resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==} - tar@7.4.3: - resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} - engines: {node: '>=18'} + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} - teeny-request@9.0.0: - resolution: {integrity: sha512-resvxdc6Mgb7YEThw6G6bExlXKkv6+YbuzGg9xuXxSgxJF7Ozs+o8Y9+2R3sArdWdW8nOokoQb1yrpFB0pQK2g==} - engines: {node: '>=14'} + thread-stream@4.0.0: + resolution: {integrity: sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==} + engines: {node: '>=20'} - terser@5.39.0: - resolution: {integrity: sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==} + time-span@4.0.0: + resolution: {integrity: sha512-MyqZCTGLDZ77u4k+jqg4UlrzPTPZ49NDlaekU6uuFaJLzPIN1woaRXCbGeqOfxwc3Y37ZROGAJ614Rdv7Olt+g==} engines: {node: '>=10'} - hasBin: true - test-exclude@7.0.1: - resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==} - engines: {node: '>=18'} + time-span@5.1.0: + resolution: {integrity: sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==} + engines: {node: '>=12'} - text-decoder@1.2.3: - resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} + tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} - time-span@4.0.0: - resolution: {integrity: sha512-MyqZCTGLDZ77u4k+jqg4UlrzPTPZ49NDlaekU6uuFaJLzPIN1woaRXCbGeqOfxwc3Y37ZROGAJ614Rdv7Olt+g==} - engines: {node: '>=10'} + tiny-warning@1.0.3: + resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - tinyexec@0.3.2: - resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyexec@1.0.4: + resolution: {integrity: sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==} + engines: {node: '>=18'} - tinyglobby@0.2.12: - resolution: {integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==} + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} - tinypool@1.0.2: - resolution: {integrity: sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==} - engines: {node: ^18.0.0 || >=20.0.0} - - tinyrainbow@2.0.0: - resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} - engines: {node: '>=14.0.0'} + tinypool@2.1.0: + resolution: {integrity: sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw==} + engines: {node: ^20.0.0 || >=22.0.0} - tinyspy@3.0.2: - resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} + tinyrainbow@3.1.0: + resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} engines: {node: '>=14.0.0'} - tippy.js@6.3.7: - resolution: {integrity: sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==} - tmp@0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} @@ -5370,10 +6305,18 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + toad-cache@3.7.0: + resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==} + engines: {node: '>=12'} + toidentifier@1.0.1: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} + token-types@6.1.2: + resolution: {integrity: sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==} + engines: {node: '>=14.16'} + tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} @@ -5387,98 +6330,97 @@ packages: trough@2.2.0: resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} - ts-api-utils@2.0.1: - resolution: {integrity: sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==} - engines: {node: '>=18.12'} - peerDependencies: - typescript: '>=4.8.4' + truncate-json@3.0.1: + resolution: {integrity: sha512-QVsbr1WhGLq2F0oDyYbqtOXcf3gcnL8C9H5EX8bBwAr8ZWvWGJzukpPrDrWgJMrNtgDbo74BIjI4kJu3q2xQWw==} + engines: {node: '>=18.18.0'} - ts-deepmerge@7.0.2: - resolution: {integrity: sha512-akcpDTPuez4xzULo5NwuoKwYRtjQJ9eoNfBACiBMaXwNAx7B1PKfe5wqUFJuW5uKzQ68YjDFwPaWHDG1KnFGsA==} + ts-deepmerge@7.0.3: + resolution: {integrity: sha512-Du/ZW2RfwV/D4cmA5rXafYjBQVuvu4qGiEEla4EmEHVHgRdx68Gftx7i66jn2bzHPwSVZY36Ae6OuDn9el4ZKA==} engines: {node: '>=14.13.1'} + tsconfck@3.1.6: + resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==} + engines: {node: ^18 || >=20} + hasBin: true + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsx@4.21.0: + resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} + engines: {node: '>=18.0.0'} + hasBin: true + tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} - type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} + turbo-stream@3.2.0: + resolution: {integrity: sha512-EK+bZ9UVrVh7JLslVFOV0GEMsociOqVOvEMTAd4ixMyffN5YNIEdLZWXUx5PJqDbTxSIBWw04HS9gCY4frYQDQ==} type-fest@0.21.3: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} - type-fest@0.6.0: - resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==} - engines: {node: '>=8'} - - type-fest@0.8.1: - resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} - engines: {node: '>=8'} - - type-fest@4.37.0: - resolution: {integrity: sha512-S/5/0kFftkq27FPNye0XM1e2NsnoD/3FS+pBmbjmmtLT6I+i344KoOf7pvXreaFsDamWeaJX55nczA1m5PsBDg==} + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} - type-is@1.6.18: - resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} - engines: {node: '>= 0.6'} + type-fest@5.4.4: + resolution: {integrity: sha512-JnTrzGu+zPV3aXIUhnyWJj4z/wigMsdYajGLIYakqyOW1nPllzXEJee0QQbHj+CTIQtXGlAjuK0UY+2xTyjVAw==} + engines: {node: '>=20'} - typescript-eslint@8.26.0: - resolution: {integrity: sha512-PtVz9nAnuNJuAVeUFvwztjuUgSnJInODAUx47VDwWPXzd5vismPOtPtt83tzNXyOjVQbPRp786D6WFW/M2koIA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' + type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} - typescript@5.8.2: - resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==} + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} hasBin: true - ufo@1.5.4: - resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} + ufo@1.6.3: + resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} - ultrahtml@1.5.3: - resolution: {integrity: sha512-GykOvZwgDWZlTQMtp5jrD4BVL+gNn2NVlVafjcFUJ7taY20tqYdwdoWBFy6GBJsNTZe1GkGPkSl5knQAjtgceg==} + uint8array-extras@1.5.0: + resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} + engines: {node: '>=18'} - unbuild@3.5.0: - resolution: {integrity: sha512-DPFttsiADnHRb/K+yJ9r9jdn6JyXlsmdT0S12VFC14DFSJD+cxBnHq+v0INmqqPVPxOoUjvJFYUVIb02rWnVeA==} - hasBin: true - peerDependencies: - typescript: ^5.7.3 - peerDependenciesMeta: - typescript: - optional: true + ultrahtml@1.6.0: + resolution: {integrity: sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==} uncrypto@0.1.3: resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} - unctx@2.4.1: - resolution: {integrity: sha512-AbaYw0Nm4mK4qjhns67C+kgxR2YWiwlDBPzxrN8h8C6VtAdCgditAY5Dezu3IJy4XVqAnbrXt9oQJvsn3fyozg==} + unctx@2.5.0: + resolution: {integrity: sha512-p+Rz9x0R7X+CYDkT+Xg8/GhpcShTlU8n+cf9OtOEf7zEQsNcCZO1dPKNRDqvUTaq+P32PMMkxWHwfrxkqfqAYg==} - undici-types@6.20.0: - resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - undici@5.28.5: - resolution: {integrity: sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA==} - engines: {node: '>=14.0'} + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} - undici@7.4.0: - resolution: {integrity: sha512-PUQM3/es3noM24oUn10u3kNNap0AbxESOmnssmW+dOi9yGwlUSi5nTNYl3bNbTkWOF8YZDkx2tCmj9OtQ3iGGw==} + undici@7.18.2: + resolution: {integrity: sha512-y+8YjDFzWdQlSE9N5nzKMT3g4a5UBX1HKowfdXh0uvAnTaqqwqB92Jt4UXBAeKekDs5IaDKyJFR4X1gYVCgXcw==} engines: {node: '>=20.18.1'} - unenv@2.0.0-rc.14: - resolution: {integrity: sha512-od496pShMen7nOy5VmVJCnq8rptd45vh6Nx/r2iPbrba6pa6p+tS2ywuIHRZ/OBvSbQZB0kWvpO9XBNVFXHD3Q==} + undici@7.24.3: + resolution: {integrity: sha512-eJdUmK/Wrx2d+mnWWmwwLRyA7OQCkLap60sk3dOK4ViZR7DKwwptwuIvFBg2HaiP9ESaEdhtpSymQPvytpmkCA==} + engines: {node: '>=20.18.1'} + + unenv@2.0.0-rc.24: + resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==} - unhead@1.11.20: - resolution: {integrity: sha512-3AsNQC0pjwlLqEYHLjtichGWankK8yqmocReITecmpB1H0aOabeESueyy+8X1gyJx4ftZVwo9hqQ4O3fPWffCA==} + unhead@2.1.12: + resolution: {integrity: sha512-iTHdWD9ztTunOErtfUFk6Wr11BxvzumcYJ0CzaSCBUOEtg+DUZ9+gnE99i8QkLFT2q1rZD48BYYGXpOZVDLYkA==} unicorn-magic@0.3.0: resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} @@ -5487,72 +6429,70 @@ packages: unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} - unimport@4.1.2: - resolution: {integrity: sha512-oVUL7PSlyVV3QRhsdcyYEMaDX8HJyS/CnUonEJTYA3//bWO+o/4gG8F7auGWWWkrrxBQBYOO8DKe+C53ktpRXw==} + unimport@6.0.1: + resolution: {integrity: sha512-RbT3PfMshH2eYH5ylQuCf1sUQ1ocygZp57HaBNIp96g1upcTZnIstCfl6ZbZM7KHI88K3jmwhgeMxwtYsWSqug==} engines: {node: '>=18.12.0'} unist-util-find-after@5.0.0: resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==} - unist-util-is@6.0.0: - resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} unist-util-position@5.0.0: resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} - unist-util-stringify-position@2.0.3: - resolution: {integrity: sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==} - unist-util-stringify-position@4.0.0: resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} - unist-util-visit-parents@6.0.1: - resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==} - - unist-util-visit@5.0.0: - resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} - universalify@2.0.1: - resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} - engines: {node: '>= 10.0.0'} + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} - unplugin-utils@0.2.4: - resolution: {integrity: sha512-8U/MtpkPkkk3Atewj1+RcKIjb5WBimZ/WSLhhR3w6SsIj8XJuKTacSP8g+2JhfSGw0Cb125Y+2zA/IzJZDVbhA==} - engines: {node: '>=18.12.0'} - - unplugin@1.16.1: - resolution: {integrity: sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==} - engines: {node: '>=14.0.0'} + unplugin-utils@0.3.1: + resolution: {integrity: sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==} + engines: {node: '>=20.19.0'} - unplugin@2.2.0: - resolution: {integrity: sha512-m1ekpSwuOT5hxkJeZGRxO7gXbXT3gF26NjQ7GdVHoLoF8/nopLcd/QfPigpCy7i51oFHiRJg/CyHhj4vs2+KGw==} + unplugin@2.3.11: + resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} engines: {node: '>=18.12.0'} - unstorage@1.15.0: - resolution: {integrity: sha512-m40eHdGY/gA6xAPqo8eaxqXgBuzQTlAKfmB1iF7oCKXE1HfwHwzDJBywK+qQGn52dta+bPlZluPF7++yR3p/bg==} + unplugin@3.0.0: + resolution: {integrity: sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==} + engines: {node: ^20.19.0 || >=22.12.0} + + unstorage@2.0.0-alpha.6: + resolution: {integrity: sha512-w5vLYCJtnSx3OBtDk7cG4c1p3dfAnHA4WSZq9Xsurjbl2wMj7zqfOIjaHQI1Bl7yKzUxXAi+kbMr8iO2RhJmBA==} peerDependencies: - '@azure/app-configuration': ^1.8.0 - '@azure/cosmos': ^4.2.0 - '@azure/data-tables': ^13.3.0 - '@azure/identity': ^4.6.0 - '@azure/keyvault-secrets': ^4.9.0 - '@azure/storage-blob': ^12.26.0 - '@capacitor/preferences': ^6.0.3 - '@deno/kv': '>=0.9.0' - '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 + '@azure/app-configuration': ^1.11.0 + '@azure/cosmos': ^4.9.1 + '@azure/data-tables': ^13.3.2 + '@azure/identity': ^4.13.0 + '@azure/keyvault-secrets': ^4.10.0 + '@azure/storage-blob': ^12.31.0 + '@capacitor/preferences': ^6 || ^7 || ^8 + '@deno/kv': '>=0.13.0' + '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0 '@planetscale/database': ^1.19.0 - '@upstash/redis': ^1.34.3 - '@vercel/blob': '>=0.27.1' + '@upstash/redis': ^1.36.2 + '@vercel/blob': '>=0.27.3' + '@vercel/functions': ^2.2.12 || ^3.0.0 '@vercel/kv': ^1.0.1 aws4fetch: ^1.0.20 - db0: '>=0.2.1' - idb-keyval: ^6.2.1 - ioredis: ^5.4.2 - uploadthing: ^7.4.4 + chokidar: ^4 || ^5 + db0: '>=0.3.4' + idb-keyval: ^6.2.2 + ioredis: ^5.9.3 + lru-cache: ^11.2.6 + mongodb: ^6 || ^7 + ofetch: '*' + uploadthing: ^7.7.4 peerDependenciesMeta: '@azure/app-configuration': optional: true @@ -5578,32 +6518,38 @@ packages: optional: true '@vercel/blob': optional: true + '@vercel/functions': + optional: true '@vercel/kv': optional: true aws4fetch: optional: true + chokidar: + optional: true db0: optional: true idb-keyval: optional: true ioredis: optional: true + lru-cache: + optional: true + mongodb: + optional: true + ofetch: + optional: true uploadthing: optional: true - untun@0.1.3: - resolution: {integrity: sha512-4luGP9LMYszMRZwsvyUd9MrxgEGZdZuZgpVQHEEX0lCYFESasVRvZd0EYpCkOIbJKHMuv0LskpXc/8Un+MJzEQ==} - hasBin: true - untyped@2.0.0: resolution: {integrity: sha512-nwNCjxJTjNuLCgFr42fEak5OcLuB3ecca+9ksPFNvtfYSLpjf+iJqSIaSnIile6ZPbKYxI5k2AfXqeopGudK/g==} hasBin: true - unwasm@0.3.9: - resolution: {integrity: sha512-LDxTx/2DkFURUd+BU1vUsF/moj0JsoTvl+2tcg2AUOiEzVturhGGx17/IMgGvKUYdZwr33EJHtChCJuhu9Ouvg==} + unwasm@0.5.3: + resolution: {integrity: sha512-keBgTSfp3r6+s9ZcSma+0chwxQdmLbB5+dAD9vjtB21UTMYuKAxHXCU1K2CbCtnP09EaWeRvACnXk0EJtUx+hw==} - update-browserslist-db@1.1.3: - resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -5612,43 +6558,25 @@ packages: resolution: {integrity: sha512-+dwUY4L35XFYEzE+OAL3sarJdUioVovq+8f7lcIJ7wnmnYQV5UD1Y/lcwaMSyaQ6Bj3JMj1XSTjZbNLHn/19yA==} engines: {node: '>=18'} - uqr@0.1.2: - resolution: {integrity: sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA==} - - uri-js-replace@1.0.1: - resolution: {integrity: sha512-W+C9NWNLFOoBI2QWDp4UT9pv65r2w5Cx+3sTYFvtMdDBxkKt1syCqsUdSFAChbEe1uK5TfS04wt/nGwmaeIQ0g==} - - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - - urlpattern-polyfill@8.0.2: - resolution: {integrity: sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ==} + use-sync-external-store@1.6.0: + resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - utils-merge@1.0.1: - resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} - engines: {node: '>= 0.4.0'} - - uuid@10.0.0: - resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} + uuid@11.1.0: + resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} hasBin: true uuid@8.3.2: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} hasBin: true - uuid@9.0.1: - resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} - hasBin: true - valid-url@1.0.9: resolution: {integrity: sha512-QQDsV8OnSf5Uc30CKSwG9lnhMPe6exHtTXLRYX8uMwKENy640pU+2BgBL0LRbDh/eYRahNCS7aewCx0wf3NYVA==} - validate-npm-package-license@3.0.4: - resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} - vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -5656,30 +6584,55 @@ packages: vfile-location@5.0.3: resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} - vfile-message@4.0.2: - resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==} + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} vfile@6.0.3: resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} - vite-node@3.0.8: - resolution: {integrity: sha512-6PhR4H9VGlcwXZ+KWCdMqbtG649xCPZqfI9j2PsK1FcXgEzro5bGHcVKFCTqPLaNKZES8Evqv4LwvZARsq5qlg==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true + vite-plugin-devtools-json@1.0.0: + resolution: {integrity: sha512-MobvwqX76Vqt/O4AbnNMNWoXWGrKUqZbphCUle/J2KXH82yKQiunOeKnz/nqEPosPsoWWPP9FtNuPBSYpiiwkw==} + peerDependencies: + vite: ^8.0.0-beta.18 - vite@6.2.1: - resolution: {integrity: sha512-n2GnqDb6XPhlt9B8olZPrgMD/es/Nd1RdChF6CBD/fHW6pUyUTt2sQW2fPRX5GiD9XEa6+8A6A4f2vT6pSsE7Q==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + vite-plugin-monaco-editor@1.1.0: + resolution: {integrity: sha512-IvtUqZotrRoVqwT0PBBDIZPNraya3BxN/bfcNfnxZ5rkJiGcNtO5eAOWWSgT7zullIAEqQwxMU83yL9J5k7gww==} + peerDependencies: + monaco-editor: '>=0.33.0' + + vite-plugin-solid@2.11.11: + resolution: {integrity: sha512-YMZCXsLw9kyuvQFEdwLP27fuTQJLmjNoHy90AOJnbRuJ6DwShUxKFo38gdFrWn9v11hnGicKCZEaeI/TFs6JKw==} + peerDependencies: + '@testing-library/jest-dom': ^5.16.6 || ^5.17.0 || ^6.* + solid-js: ^1.7.2 + vite: ^8.0.0-beta.18 + peerDependenciesMeta: + '@testing-library/jest-dom': + optional: true + + vite-prerender-plugin@0.5.12: + resolution: {integrity: sha512-EiwhbMn+flg14EysbLTmZSzq8NGTxhytgK3bf4aGRF1evWLGwZiHiUJ1KZDvbxgKbMf2pG6fJWGEa3UZXOnR1g==} + peerDependencies: + vite: ^8.0.0-beta.18 + + vite-tsconfig-paths@6.1.1: + resolution: {integrity: sha512-2cihq7zliibCCZ8P9cKJrQBkfgdvcFkOOc3Y02o3GWUDLgqjWsZudaoiuOwO/gzTzy17cS5F7ZPo4bsnS4DGkg==} + peerDependencies: + vite: ^8.0.0-beta.18 + + vite@7.3.1: + resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} + engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@types/node': ^20.19.0 || >=22.12.0 jiti: '>=1.21.0' - less: '*' + less: ^4.0.0 lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 terser: ^5.16.0 tsx: ^4.8.1 yaml: ^2.4.2 @@ -5707,26 +6660,84 @@ packages: yaml: optional: true - vitest@3.0.8: - resolution: {integrity: sha512-dfqAsNqRGUc8hB9OVR2P0w8PZPEckti2+5rdZip0WIz9WW0MnImJ8XiR61QhqLa92EQzKP2uPkzenKOAHyEIbA==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + vite@8.0.0: + resolution: {integrity: sha512-fPGaRNj9Zytaf8LEiBhY7Z6ijnFKdzU/+mL8EFBaKr7Vw1/FWcTBAMW0wLPJAGMPX38ZPVCVgLceWiEqeoqL2Q==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.0.0-alpha.31 + esbuild: ^0.27.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitefu@1.1.2: + resolution: {integrity: sha512-zpKATdUbzbsycPFBN71nS2uzBUQiVnFoOrr2rvqv34S1lcAgMKKkjWleLGeiJlZ8lwCXvtWaRn7R3ZC16SYRuw==} + peerDependencies: + vite: ^8.0.0-beta.18 + peerDependenciesMeta: + vite: + optional: true + + vitest@4.1.0: + resolution: {integrity: sha512-YbDrMF9jM2Lqc++2530UourxZHmkKLxrs4+mYhEwqWS97WJ7wOYEkcr+QfRgJ3PW9wz3odRijLZjHEaRLTNbqw==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' - '@types/debug': ^4.1.12 - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - '@vitest/browser': 3.0.8 - '@vitest/ui': 3.0.8 + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.1.0 + '@vitest/browser-preview': 4.1.0 + '@vitest/browser-webdriverio': 4.1.0 + '@vitest/ui': 4.1.0 happy-dom: '*' jsdom: '*' + vite: ^8.0.0-beta.18 peerDependenciesMeta: '@edge-runtime/vm': optional: true - '@types/debug': + '@opentelemetry/api': optional: true '@types/node': optional: true - '@vitest/browser': + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': optional: true '@vitest/ui': optional: true @@ -5735,6 +6746,25 @@ packages: jsdom: optional: true + vscode-jsonrpc@8.2.0: + resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} + engines: {node: '>=14.0.0'} + + vscode-languageserver-protocol@3.17.5: + resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} + + vscode-languageserver-textdocument@1.0.12: + resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} + + vscode-languageserver-types@3.17.5: + resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} + + vscode-uri@3.1.0: + resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + + vue-component-type-helpers@3.2.5: + resolution: {integrity: sha512-tkvNr+bU8+xD/onAThIe7CHFvOJ/BO6XCOrxMzeytJq40nTfpGDJuVjyCM8ccGZKfAbGk2YfuZyDMXM56qheZQ==} + vue-demi@0.14.10: resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} engines: {node: '>=12'} @@ -5746,16 +6776,21 @@ packages: '@vue/composition-api': optional: true - vue-router@4.5.0: - resolution: {integrity: sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==} + vue-router@4.6.2: + resolution: {integrity: sha512-my83mxQKXyCms9EegBXZldehOihxBjgSjZqrZwgg4vBacNGl0oBCO+xT//wgOYpLV1RW93ZfqxrjTozd+82nbA==} peerDependencies: - vue: ^3.2.0 + vue: ^3.5.0 + + vue-router@4.6.4: + resolution: {integrity: sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==} + peerDependencies: + vue: ^3.5.0 - vue-sonner@1.3.0: - resolution: {integrity: sha512-jAodBy4Mri8rQjVZGQAPs4ZYymc1ywPiwfa81qU0fFl+Suk7U8NaOxIDdI1oBGLeQJqRZi/oxNIuhCLqsBmOwg==} + vue-sonner@1.3.2: + resolution: {integrity: sha512-UbZ48E9VIya3ToiRHAZUbodKute/z/M1iT8/3fU8zEbwBRE11AKuHikssv18LMk2gTTr6eMQT4qf6JoLHWuj/A==} - vue@3.5.13: - resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==} + vue@3.5.30: + resolution: {integrity: sha512-hTHLc6VNZyzzEH/l7PFGjpcTvUgiaPK5mdLkbjrTeWSRcEfxFrv56g/XckIYlE9ckuobsdwqd5mk2g1sBkMewg==} peerDependencies: typescript: '*' peerDependenciesMeta: @@ -5776,19 +6811,19 @@ packages: web-namespaces@2.0.1: resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + web-worker@1.5.0: + resolution: {integrity: sha512-RiMReJrTAiA+mBjGONMnjVDP2u3p9R1vkcGz6gDIrOMT3oGuYwX2WRMYI9ipkphSuE5XKEhydbhNEJh4NY9mlw==} + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} webpack-virtual-modules@0.6.2: resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} - websocket-driver@0.7.4: - resolution: {integrity: sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==} - engines: {node: '>=0.8.0'} - - websocket-extensions@0.1.4: - resolution: {integrity: sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==} - engines: {node: '>=0.8.0'} + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation whatwg-mimetype@4.0.0: resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} @@ -5797,8 +6832,8 @@ packages: whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - when-exit@2.1.4: - resolution: {integrity: sha512-4rnvd3A1t16PWzrBUcSDZqcAmsUIy4minDXT/CZ8F2mVDgd65i4Aalimgz1aQkRGU0iH5eT5+6Rx2TK8o443Pg==} + when-exit@2.1.5: + resolution: {integrity: sha512-VGkKJ564kzt6Ms1dbgPP/yuIoQCrsFAnRbptpC5wOEsDaNsbCB2bnfnaA8i/vRs5tjUSEOtIuvl9/MyVsvQZCg==} which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} @@ -5814,15 +6849,21 @@ packages: resolution: {integrity: sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==} engines: {node: '>=18'} - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - - workerd@1.20250224.0: - resolution: {integrity: sha512-NntMg1d9SSkbS4vGdjV5NZxe6FUrvJXY7UiQD7fBtCRVpoPpqz9bVgTq86zalMm+vz64lftzabKT4ka4Y9hejQ==} + workerd@1.20260312.1: + resolution: {integrity: sha512-nNpPkw9jaqo79B+iBCOiksx+N62xC+ETIfyzofUEdY3cSOHJg6oNnVSHm7vHevzVblfV76c8Gr0cXHEapYMBEg==} engines: {node: '>=16'} hasBin: true + wrangler@4.73.0: + resolution: {integrity: sha512-VJXsqKDFCp6OtFEHXITSOR5kh95JOknwPY8m7RyQuWJQguSybJy43m4vhoCSt42prutTef7eeuw7L4V4xiynGw==} + engines: {node: '>=20.0.0'} + hasBin: true + peerDependencies: + '@cloudflare/workers-types': ^4.20260312.1 + peerDependenciesMeta: + '@cloudflare/workers-types': + optional: true + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -5831,8 +6872,8 @@ packages: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} engines: {node: '>=12'} - wrap-ansi@9.0.0: - resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==} + wrap-ansi@9.0.2: + resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} engines: {node: '>=18'} wrappy@1.0.2: @@ -5850,6 +6891,10 @@ packages: utf-8-validate: optional: true + wsl-utils@0.1.0: + resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==} + engines: {node: '>=18'} + xdg-basedir@5.1.0: resolution: {integrity: sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==} engines: {node: '>=12'} @@ -5858,27 +6903,24 @@ packages: resolution: {integrity: sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==} engines: {node: '>=4.0.0'} + xmlbuilder2@4.0.3: + resolution: {integrity: sha512-bx8Q1STctnNaaDymWnkfQLKofs0mGNN7rLLapJlGuV3VlvegD7Ls4ggMjE3aUSWItCCzU0PEv45lI87iSigiCA==} + engines: {node: '>=20.0'} + xmlbuilder@11.0.1: resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} engines: {node: '>=4.0'} y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - - yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - - yallist@5.0.0: - resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} - engines: {node: '>=18'} + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} - yaml-ast-parser@0.0.43: - resolution: {integrity: sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==} + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - yaml@2.7.0: - resolution: {integrity: sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==} - engines: {node: '>= 14'} + yaml@2.8.2: + resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} + engines: {node: '>= 14.6'} hasBin: true yargs-parser@21.1.1: @@ -5893,43 +6935,67 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - yoctocolors@2.1.1: - resolution: {integrity: sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==} + yoctocolors@2.1.2: + resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==} engines: {node: '>=18'} - youch-core@0.3.2: - resolution: {integrity: sha512-fusrlIMLeRvTFYLUjJ9KzlGC3N+6MOPJ68HNj/yJv2nz7zq8t4HEviLms2gkdRPUS7F5rZ5n+pYx9r88m6IE1g==} - engines: {node: '>=18'} + youch-core@0.3.3: + resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==} - youch@3.2.3: - resolution: {integrity: sha512-ZBcWz/uzZaQVdCvfV4uk616Bbpf2ee+F/AvuKDR5EwX/Y4v06xWdtMluqTD7+KlZdM93lLm9gMZYo0sKBS0pgw==} + youch@4.1.0: + resolution: {integrity: sha512-cYekNh2tUoU+voS11X0D0UQntVCSO6LQ1h10VriQGmfbpf0mnGTruwZICts23UUNiZCXm8H8hQBtRrdsbhuNNg==} - youch@4.1.0-beta.6: - resolution: {integrity: sha512-y1aNsEeoLXnWb6pI9TvfNPIxySyo4Un3OGxKn7rsNj8+tgSquzXEWkzfA5y6gU0fvzmQgvx3JBn/p51qQ8Xg9A==} - engines: {node: '>=18'} + youch@4.1.0-beta.10: + resolution: {integrity: sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==} + + zephyr-agent@0.1.15: + resolution: {integrity: sha512-aFUGeW5AWFVl77hdmEmyTRDvUWCABLPCE5DTZNCNmjbZQpL1Yfi975PeABgnO+2wMLcCjuIW6lSkYOE2U2JDjA==} + peerDependencies: + https-proxy-agent: ^7.0.6 - zhead@2.2.4: - resolution: {integrity: sha512-8F0OI5dpWIA5IGG5NHUg9staDwz/ZPxZtvGVf01j7vHqSyZ0raHY+78atOVxRqb73AotX22uV1pXt3gYSstGag==} + zephyr-edge-contract@0.1.15: + resolution: {integrity: sha512-SACOfFTuBoRWbHk1vNBgdlidDhyxh2TEiD2hgOD6vlSo+dUh6gwKYBxgd8SRcQBvV64tfA+rdUkJYtBiN6O1kQ==} - zip-stream@6.0.1: - resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} - engines: {node: '>= 14'} + zimmerframe@1.1.4: + resolution: {integrity: sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==} - zod@3.22.3: - resolution: {integrity: sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==} + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - zod@3.24.2: - resolution: {integrity: sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==} + zod@4.3.6: + resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} snapshots: - '@ampproject/remapping@2.3.0': + '@ai-sdk/gateway@3.0.13(zod@4.3.6)': dependencies: - '@jridgewell/gen-mapping': 0.3.8 - '@jridgewell/trace-mapping': 0.3.25 + '@ai-sdk/provider': 3.0.2 + '@ai-sdk/provider-utils': 4.0.5(zod@4.3.6) + '@vercel/oidc': 3.1.0 + zod: 4.3.6 + + '@ai-sdk/provider-utils@4.0.5(zod@4.3.6)': + dependencies: + '@ai-sdk/provider': 3.0.2 + '@standard-schema/spec': 1.1.0 + eventsource-parser: 3.0.6 + zod: 4.3.6 + + '@ai-sdk/provider@3.0.2': + dependencies: + json-schema: 0.4.0 + + '@ai-sdk/vue@3.0.33(vue@3.5.30(typescript@5.9.3))(zod@4.3.6)': + dependencies: + '@ai-sdk/provider-utils': 4.0.5(zod@4.3.6) + ai: 6.0.33(zod@4.3.6) + swrv: 1.1.0(vue@3.5.30(typescript@5.9.3)) + vue: 3.5.30(typescript@5.9.3) + transitivePeerDependencies: + - zod '@azure/abort-controller@1.1.0': dependencies: @@ -5942,11 +7008,11 @@ snapshots: '@azure/arm-appservice@15.0.0': dependencies: '@azure/abort-controller': 1.1.0 - '@azure/core-auth': 1.9.0 - '@azure/core-client': 1.9.3 + '@azure/core-auth': 1.10.1 + '@azure/core-client': 1.10.1 '@azure/core-lro': 2.7.2 '@azure/core-paging': 1.6.2 - '@azure/core-rest-pipeline': 1.19.1 + '@azure/core-rest-pipeline': 1.23.0 tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -5954,41 +7020,43 @@ snapshots: '@azure/arm-resources@5.2.0': dependencies: '@azure/abort-controller': 1.1.0 - '@azure/core-auth': 1.9.0 - '@azure/core-client': 1.9.3 + '@azure/core-auth': 1.10.1 + '@azure/core-client': 1.10.1 '@azure/core-lro': 2.7.2 '@azure/core-paging': 1.6.2 - '@azure/core-rest-pipeline': 1.19.1 + '@azure/core-rest-pipeline': 1.23.0 tslib: 2.8.1 transitivePeerDependencies: - supports-color - '@azure/arm-subscriptions@5.1.0': + '@azure/arm-subscriptions@5.1.1': dependencies: - '@azure/abort-controller': 1.1.0 - '@azure/core-auth': 1.9.0 - '@azure/core-client': 1.9.3 + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.10.1 + '@azure/core-client': 1.10.1 '@azure/core-lro': 2.7.2 '@azure/core-paging': 1.6.2 - '@azure/core-rest-pipeline': 1.19.1 + '@azure/core-rest-pipeline': 1.23.0 tslib: 2.8.1 transitivePeerDependencies: - supports-color - '@azure/core-auth@1.9.0': + '@azure/core-auth@1.10.1': dependencies: '@azure/abort-controller': 2.1.2 - '@azure/core-util': 1.11.0 + '@azure/core-util': 1.13.1 tslib: 2.8.1 + transitivePeerDependencies: + - supports-color - '@azure/core-client@1.9.3': + '@azure/core-client@1.10.1': dependencies: '@azure/abort-controller': 2.1.2 - '@azure/core-auth': 1.9.0 - '@azure/core-rest-pipeline': 1.19.1 - '@azure/core-tracing': 1.2.0 - '@azure/core-util': 1.11.0 - '@azure/logger': 1.1.4 + '@azure/core-auth': 1.10.1 + '@azure/core-rest-pipeline': 1.23.0 + '@azure/core-tracing': 1.3.1 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -5996,35 +7064,39 @@ snapshots: '@azure/core-lro@2.7.2': dependencies: '@azure/abort-controller': 2.1.2 - '@azure/core-util': 1.11.0 - '@azure/logger': 1.1.4 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 tslib: 2.8.1 + transitivePeerDependencies: + - supports-color '@azure/core-paging@1.6.2': dependencies: tslib: 2.8.1 - '@azure/core-rest-pipeline@1.19.1': + '@azure/core-rest-pipeline@1.23.0': dependencies: '@azure/abort-controller': 2.1.2 - '@azure/core-auth': 1.9.0 - '@azure/core-tracing': 1.2.0 - '@azure/core-util': 1.11.0 - '@azure/logger': 1.1.4 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6(supports-color@9.4.0) + '@azure/core-auth': 1.10.1 + '@azure/core-tracing': 1.3.1 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 + '@typespec/ts-http-runtime': 0.3.4 tslib: 2.8.1 transitivePeerDependencies: - supports-color - '@azure/core-tracing@1.2.0': + '@azure/core-tracing@1.3.1': dependencies: tslib: 2.8.1 - '@azure/core-util@1.11.0': + '@azure/core-util@1.13.1': dependencies: '@azure/abort-controller': 2.1.2 + '@typespec/ts-http-runtime': 0.3.4 tslib: 2.8.1 + transitivePeerDependencies: + - supports-color '@azure/functions@3.5.1': dependencies: @@ -6032,64 +7104,64 @@ snapshots: long: 4.0.0 uuid: 8.3.2 - '@azure/identity@4.7.0': + '@azure/identity@4.13.0': dependencies: '@azure/abort-controller': 2.1.2 - '@azure/core-auth': 1.9.0 - '@azure/core-client': 1.9.3 - '@azure/core-rest-pipeline': 1.19.1 - '@azure/core-tracing': 1.2.0 - '@azure/core-util': 1.11.0 - '@azure/logger': 1.1.4 - '@azure/msal-browser': 4.5.1 - '@azure/msal-node': 3.2.3 - events: 3.3.0 - jws: 4.0.0 - open: 10.1.0 - stoppable: 1.1.0 + '@azure/core-auth': 1.10.1 + '@azure/core-client': 1.10.1 + '@azure/core-rest-pipeline': 1.23.0 + '@azure/core-tracing': 1.3.1 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 + '@azure/msal-browser': 4.29.1 + '@azure/msal-node': 3.8.9 + open: 10.2.0 tslib: 2.8.1 transitivePeerDependencies: - supports-color - '@azure/logger@1.1.4': + '@azure/logger@1.3.0': dependencies: + '@typespec/ts-http-runtime': 0.3.4 tslib: 2.8.1 + transitivePeerDependencies: + - supports-color - '@azure/msal-browser@4.5.1': + '@azure/msal-browser@4.29.1': dependencies: - '@azure/msal-common': 15.2.0 + '@azure/msal-common': 15.16.1 - '@azure/msal-common@14.16.0': {} + '@azure/msal-common@14.16.1': {} - '@azure/msal-common@15.2.0': {} + '@azure/msal-common@15.16.1': {} - '@azure/msal-node@3.2.3': + '@azure/msal-node@3.8.9': dependencies: - '@azure/msal-common': 15.2.0 - jsonwebtoken: 9.0.2 + '@azure/msal-common': 15.16.1 + jsonwebtoken: 9.0.3 uuid: 8.3.2 - '@azure/static-web-apps-cli@2.0.4': + '@azure/static-web-apps-cli@2.0.8': dependencies: '@azure/arm-appservice': 15.0.0 '@azure/arm-resources': 5.2.0 - '@azure/arm-subscriptions': 5.1.0 - '@azure/identity': 4.7.0 - '@azure/msal-common': 14.16.0 + '@azure/arm-subscriptions': 5.1.1 + '@azure/identity': 4.13.0 + '@azure/msal-common': 14.16.1 adm-zip: 0.5.16 chalk: 4.1.2 cli-progress: 3.12.0 commander: 9.5.0 concurrently: 7.6.0 cookie: 0.5.0 - devcert: 1.2.2 - dotenv: 16.4.7 - finalhandler: 1.3.1 + devcert: 1.2.3 + dotenv: 16.6.1 + finalhandler: 1.3.2 get-port: 5.1.1 globrex: 0.1.2 http-proxy: 1.18.1 http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6(supports-color@9.4.0) + https-proxy-agent: 7.0.6 internal-ip: 6.2.0 json-schema-library: 9.3.5 json-source-map: 0.6.1 @@ -6097,163 +7169,320 @@ snapshots: keytar: 7.9.0 node-fetch: 2.7.0 open: 8.4.2 + openid-client: 6.8.2 ora: 5.4.1 pem: 1.14.8 prompts: 2.4.2 rimraf: 5.0.10 selfsigned: 2.4.1 - serve-static: 1.16.2 + serve-static: 1.16.3 update-notifier: 7.3.1 wait-on: 7.2.0 - yaml: 2.7.0 + yaml: 2.8.2 transitivePeerDependencies: - debug - encoding - supports-color - '@babel/code-frame@7.26.2': + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/code-frame@7.29.0': dependencies: - '@babel/helper-validator-identifier': 7.25.9 + '@babel/helper-validator-identifier': 7.28.5 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/helper-string-parser@7.25.9': {} + '@babel/compat-data@7.29.0': {} + + '@babel/core@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helpers': 7.28.6 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.1': + dependencies: + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/generator@8.0.0-rc.2': + dependencies: + '@babel/parser': 8.0.0-rc.2 + '@babel/types': 8.0.0-rc.2 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + '@types/jsesc': 2.5.1 + jsesc: 3.1.0 + + '@babel/helper-annotate-as-pure@7.27.3': + dependencies: + '@babel/types': 7.29.0 + + '@babel/helper-compilation-targets@7.28.6': + dependencies: + '@babel/compat-data': 7.29.0 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.1 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.18.6': + dependencies: + '@babel/types': 7.29.0 + + '@babel/helper-module-imports@7.28.6': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.28.6': {} + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-string-parser@8.0.0-rc.2': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/helper-validator-identifier@8.0.0-rc.2': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.28.6': + dependencies: + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + + '@babel/parser@7.29.0': + dependencies: + '@babel/types': 7.29.0 + + '@babel/parser@8.0.0-rc.2': + dependencies: + '@babel/types': 8.0.0-rc.2 + + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-react-jsx-development@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-react-jsx@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/runtime@7.28.6': {} - '@babel/helper-validator-identifier@7.25.9': {} + '@babel/template@7.28.6': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 - '@babel/parser@7.26.9': + '@babel/traverse@7.29.0': dependencies: - '@babel/types': 7.26.9 + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color - '@babel/runtime@7.26.9': + '@babel/types@7.29.0': dependencies: - regenerator-runtime: 0.14.1 + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 - '@babel/types@7.26.9': + '@babel/types@8.0.0-rc.2': dependencies: - '@babel/helper-string-parser': 7.25.9 - '@babel/helper-validator-identifier': 7.25.9 + '@babel/helper-string-parser': 8.0.0-rc.2 + '@babel/helper-validator-identifier': 8.0.0-rc.2 '@bcoe/v8-coverage@1.0.2': {} - '@cloudflare/kv-asset-handler@0.3.4': + '@borewit/text-codec@0.2.2': {} + + '@cloudflare/kv-asset-handler@0.4.2': {} + + '@cloudflare/unenv-preset@2.15.0(unenv@2.0.0-rc.24)(workerd@1.20260312.1)': dependencies: - mime: 3.0.0 + unenv: 2.0.0-rc.24 + optionalDependencies: + workerd: 1.20260312.1 - '@cloudflare/workerd-darwin-64@1.20250224.0': + '@cloudflare/workerd-darwin-64@1.20260312.1': optional: true - '@cloudflare/workerd-darwin-arm64@1.20250224.0': + '@cloudflare/workerd-darwin-arm64@1.20260312.1': optional: true - '@cloudflare/workerd-linux-64@1.20250224.0': + '@cloudflare/workerd-linux-64@1.20260312.1': optional: true - '@cloudflare/workerd-linux-arm64@1.20250224.0': + '@cloudflare/workerd-linux-arm64@1.20260312.1': optional: true - '@cloudflare/workerd-windows-64@1.20250224.0': + '@cloudflare/workerd-windows-64@1.20260312.1': optional: true - '@cloudflare/workers-types@4.20250303.0': {} + '@cloudflare/workers-types@4.20260313.1': {} - '@codemirror/autocomplete@6.18.6': + '@codemirror/autocomplete@6.20.1': dependencies: - '@codemirror/language': 6.10.8 - '@codemirror/state': 6.5.2 - '@codemirror/view': 6.36.4 - '@lezer/common': 1.2.3 + '@codemirror/language': 6.12.2 + '@codemirror/state': 6.6.0 + '@codemirror/view': 6.40.0 + '@lezer/common': 1.5.1 - '@codemirror/commands@6.8.0': + '@codemirror/commands@6.10.3': dependencies: - '@codemirror/language': 6.10.8 - '@codemirror/state': 6.5.2 - '@codemirror/view': 6.36.4 - '@lezer/common': 1.2.3 + '@codemirror/language': 6.12.2 + '@codemirror/state': 6.6.0 + '@codemirror/view': 6.40.0 + '@lezer/common': 1.5.1 '@codemirror/lang-css@6.3.1': dependencies: - '@codemirror/autocomplete': 6.18.6 - '@codemirror/language': 6.10.8 - '@codemirror/state': 6.5.2 - '@lezer/common': 1.2.3 - '@lezer/css': 1.1.10 + '@codemirror/autocomplete': 6.20.1 + '@codemirror/language': 6.12.2 + '@codemirror/state': 6.6.0 + '@lezer/common': 1.5.1 + '@lezer/css': 1.3.1 - '@codemirror/lang-html@6.4.9': + '@codemirror/lang-html@6.4.11': dependencies: - '@codemirror/autocomplete': 6.18.6 + '@codemirror/autocomplete': 6.20.1 '@codemirror/lang-css': 6.3.1 - '@codemirror/lang-javascript': 6.2.3 - '@codemirror/language': 6.10.8 - '@codemirror/state': 6.5.2 - '@codemirror/view': 6.36.4 - '@lezer/common': 1.2.3 - '@lezer/css': 1.1.10 - '@lezer/html': 1.3.10 - - '@codemirror/lang-javascript@6.2.3': - dependencies: - '@codemirror/autocomplete': 6.18.6 - '@codemirror/language': 6.10.8 - '@codemirror/lint': 6.8.4 - '@codemirror/state': 6.5.2 - '@codemirror/view': 6.36.4 - '@lezer/common': 1.2.3 - '@lezer/javascript': 1.4.21 - - '@codemirror/lang-json@6.0.1': - dependencies: - '@codemirror/language': 6.10.8 + '@codemirror/lang-javascript': 6.2.5 + '@codemirror/language': 6.12.2 + '@codemirror/state': 6.6.0 + '@codemirror/view': 6.40.0 + '@lezer/common': 1.5.1 + '@lezer/css': 1.3.1 + '@lezer/html': 1.3.13 + + '@codemirror/lang-javascript@6.2.5': + dependencies: + '@codemirror/autocomplete': 6.20.1 + '@codemirror/language': 6.12.2 + '@codemirror/lint': 6.9.5 + '@codemirror/state': 6.6.0 + '@codemirror/view': 6.40.0 + '@lezer/common': 1.5.1 + '@lezer/javascript': 1.5.4 + + '@codemirror/lang-json@6.0.2': + dependencies: + '@codemirror/language': 6.12.2 '@lezer/json': 1.0.3 '@codemirror/lang-xml@6.1.0': dependencies: - '@codemirror/autocomplete': 6.18.6 - '@codemirror/language': 6.10.8 - '@codemirror/state': 6.5.2 - '@codemirror/view': 6.36.4 - '@lezer/common': 1.2.3 + '@codemirror/autocomplete': 6.20.1 + '@codemirror/language': 6.12.2 + '@codemirror/state': 6.6.0 + '@codemirror/view': 6.40.0 + '@lezer/common': 1.5.1 '@lezer/xml': 1.0.6 '@codemirror/lang-yaml@6.1.2': dependencies: - '@codemirror/autocomplete': 6.18.6 - '@codemirror/language': 6.10.8 - '@codemirror/state': 6.5.2 - '@lezer/common': 1.2.3 - '@lezer/highlight': 1.2.1 - '@lezer/lr': 1.4.2 - '@lezer/yaml': 1.0.3 + '@codemirror/autocomplete': 6.20.1 + '@codemirror/language': 6.12.2 + '@codemirror/state': 6.6.0 + '@lezer/common': 1.5.1 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.8 + '@lezer/yaml': 1.0.4 - '@codemirror/language@6.10.8': + '@codemirror/language@6.12.2': dependencies: - '@codemirror/state': 6.5.2 - '@codemirror/view': 6.36.4 - '@lezer/common': 1.2.3 - '@lezer/highlight': 1.2.1 - '@lezer/lr': 1.4.2 - style-mod: 4.1.2 + '@codemirror/state': 6.6.0 + '@codemirror/view': 6.40.0 + '@lezer/common': 1.5.1 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.8 + style-mod: 4.1.3 - '@codemirror/lint@6.8.4': + '@codemirror/lint@6.9.5': dependencies: - '@codemirror/state': 6.5.2 - '@codemirror/view': 6.36.4 + '@codemirror/state': 6.6.0 + '@codemirror/view': 6.40.0 crelt: 1.0.6 - '@codemirror/search@6.5.10': - dependencies: - '@codemirror/state': 6.5.2 - '@codemirror/view': 6.36.4 - crelt: 1.0.6 - - '@codemirror/state@6.5.2': + '@codemirror/state@6.6.0': dependencies: '@marijn/find-cluster-break': 1.0.2 - '@codemirror/view@6.36.4': + '@codemirror/view@6.40.0': dependencies: - '@codemirror/state': 6.5.2 - style-mod: 4.1.2 + '@codemirror/state': 6.6.0 + crelt: 1.0.6 + style-mod: 4.1.3 w3c-keyname: 2.2.8 '@cspotcode/source-map-support@0.8.1': @@ -6272,590 +7501,648 @@ snapshots: dependencies: '@edge-runtime/primitives': 6.0.0 - '@esbuild/aix-ppc64@0.24.2': + '@emnapi/core@1.9.0': + dependencies: + '@emnapi/wasi-threads': 1.2.0 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.9.0': + dependencies: + tslib: 2.8.1 optional: true - '@esbuild/aix-ppc64@0.25.0': + '@emnapi/wasi-threads@1.2.0': + dependencies: + tslib: 2.8.1 optional: true - '@esbuild/android-arm64@0.24.2': + '@esbuild/aix-ppc64@0.27.3': optional: true - '@esbuild/android-arm64@0.25.0': + '@esbuild/aix-ppc64@0.27.4': optional: true - '@esbuild/android-arm@0.24.2': + '@esbuild/android-arm64@0.27.3': optional: true - '@esbuild/android-arm@0.25.0': + '@esbuild/android-arm64@0.27.4': optional: true - '@esbuild/android-x64@0.24.2': + '@esbuild/android-arm@0.27.3': optional: true - '@esbuild/android-x64@0.25.0': + '@esbuild/android-arm@0.27.4': optional: true - '@esbuild/darwin-arm64@0.24.2': + '@esbuild/android-x64@0.27.3': optional: true - '@esbuild/darwin-arm64@0.25.0': + '@esbuild/android-x64@0.27.4': optional: true - '@esbuild/darwin-x64@0.24.2': + '@esbuild/darwin-arm64@0.27.3': optional: true - '@esbuild/darwin-x64@0.25.0': + '@esbuild/darwin-arm64@0.27.4': optional: true - '@esbuild/freebsd-arm64@0.24.2': + '@esbuild/darwin-x64@0.27.3': optional: true - '@esbuild/freebsd-arm64@0.25.0': + '@esbuild/darwin-x64@0.27.4': optional: true - '@esbuild/freebsd-x64@0.24.2': + '@esbuild/freebsd-arm64@0.27.3': optional: true - '@esbuild/freebsd-x64@0.25.0': + '@esbuild/freebsd-arm64@0.27.4': optional: true - '@esbuild/linux-arm64@0.24.2': + '@esbuild/freebsd-x64@0.27.3': optional: true - '@esbuild/linux-arm64@0.25.0': + '@esbuild/freebsd-x64@0.27.4': optional: true - '@esbuild/linux-arm@0.24.2': + '@esbuild/linux-arm64@0.27.3': optional: true - '@esbuild/linux-arm@0.25.0': + '@esbuild/linux-arm64@0.27.4': optional: true - '@esbuild/linux-ia32@0.24.2': + '@esbuild/linux-arm@0.27.3': optional: true - '@esbuild/linux-ia32@0.25.0': + '@esbuild/linux-arm@0.27.4': optional: true - '@esbuild/linux-loong64@0.24.2': + '@esbuild/linux-ia32@0.27.3': optional: true - '@esbuild/linux-loong64@0.25.0': + '@esbuild/linux-ia32@0.27.4': optional: true - '@esbuild/linux-mips64el@0.24.2': + '@esbuild/linux-loong64@0.27.3': optional: true - '@esbuild/linux-mips64el@0.25.0': + '@esbuild/linux-loong64@0.27.4': optional: true - '@esbuild/linux-ppc64@0.24.2': + '@esbuild/linux-mips64el@0.27.3': optional: true - '@esbuild/linux-ppc64@0.25.0': + '@esbuild/linux-mips64el@0.27.4': optional: true - '@esbuild/linux-riscv64@0.24.2': + '@esbuild/linux-ppc64@0.27.3': optional: true - '@esbuild/linux-riscv64@0.25.0': + '@esbuild/linux-ppc64@0.27.4': optional: true - '@esbuild/linux-s390x@0.24.2': + '@esbuild/linux-riscv64@0.27.3': optional: true - '@esbuild/linux-s390x@0.25.0': + '@esbuild/linux-riscv64@0.27.4': optional: true - '@esbuild/linux-x64@0.24.2': + '@esbuild/linux-s390x@0.27.3': optional: true - '@esbuild/linux-x64@0.25.0': + '@esbuild/linux-s390x@0.27.4': optional: true - '@esbuild/netbsd-arm64@0.24.2': + '@esbuild/linux-x64@0.27.3': optional: true - '@esbuild/netbsd-arm64@0.25.0': + '@esbuild/linux-x64@0.27.4': optional: true - '@esbuild/netbsd-x64@0.24.2': + '@esbuild/netbsd-arm64@0.27.3': optional: true - '@esbuild/netbsd-x64@0.25.0': + '@esbuild/netbsd-arm64@0.27.4': optional: true - '@esbuild/openbsd-arm64@0.24.2': + '@esbuild/netbsd-x64@0.27.3': optional: true - '@esbuild/openbsd-arm64@0.25.0': + '@esbuild/netbsd-x64@0.27.4': optional: true - '@esbuild/openbsd-x64@0.24.2': + '@esbuild/openbsd-arm64@0.27.3': optional: true - '@esbuild/openbsd-x64@0.25.0': + '@esbuild/openbsd-arm64@0.27.4': optional: true - '@esbuild/sunos-x64@0.24.2': + '@esbuild/openbsd-x64@0.27.3': optional: true - '@esbuild/sunos-x64@0.25.0': + '@esbuild/openbsd-x64@0.27.4': optional: true - '@esbuild/win32-arm64@0.24.2': + '@esbuild/openharmony-arm64@0.27.3': optional: true - '@esbuild/win32-arm64@0.25.0': + '@esbuild/openharmony-arm64@0.27.4': optional: true - '@esbuild/win32-ia32@0.24.2': + '@esbuild/sunos-x64@0.27.3': optional: true - '@esbuild/win32-ia32@0.25.0': + '@esbuild/sunos-x64@0.27.4': optional: true - '@esbuild/win32-x64@0.24.2': + '@esbuild/win32-arm64@0.27.3': optional: true - '@esbuild/win32-x64@0.25.0': + '@esbuild/win32-arm64@0.27.4': optional: true - '@eslint-community/eslint-utils@4.4.1(eslint@9.22.0(jiti@2.4.2))': - dependencies: - eslint: 9.22.0(jiti@2.4.2) - eslint-visitor-keys: 3.4.3 + '@esbuild/win32-ia32@0.27.3': + optional: true - '@eslint-community/regexpp@4.12.1': {} + '@esbuild/win32-ia32@0.27.4': + optional: true - '@eslint/config-array@0.19.2': - dependencies: - '@eslint/object-schema': 2.1.6 - debug: 4.4.0(supports-color@9.4.0) - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color + '@esbuild/win32-x64@0.27.3': + optional: true - '@eslint/config-helpers@0.1.0': {} + '@esbuild/win32-x64@0.27.4': + optional: true - '@eslint/core@0.12.0': + '@fastify/ajv-compiler@4.0.5': dependencies: - '@types/json-schema': 7.0.15 + ajv: 8.18.0 + ajv-formats: 3.0.1(ajv@8.18.0) + fast-uri: 3.1.0 - '@eslint/eslintrc@3.3.0': - dependencies: - ajv: 6.12.6 - debug: 4.4.0(supports-color@9.4.0) - espree: 10.3.0 - globals: 14.0.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color + '@fastify/error@4.2.0': {} - '@eslint/js@9.22.0': {} + '@fastify/fast-json-stringify-compiler@5.0.3': + dependencies: + fast-json-stringify: 6.3.0 - '@eslint/object-schema@2.1.6': {} + '@fastify/forwarded@3.0.1': {} - '@eslint/plugin-kit@0.2.7': + '@fastify/merge-json-schemas@0.2.1': dependencies: - '@eslint/core': 0.12.0 - levn: 0.4.1 + dequal: 2.0.3 - '@fastify/busboy@2.1.1': {} + '@fastify/proxy-addr@5.1.0': + dependencies: + '@fastify/forwarded': 3.0.1 + ipaddr.js: 2.3.0 - '@fastify/busboy@3.1.1': {} + '@floating-ui/core@1.7.5': + dependencies: + '@floating-ui/utils': 0.2.11 - '@firebase/app-check-interop-types@0.3.2': {} + '@floating-ui/dom@1.7.6': + dependencies: + '@floating-ui/core': 1.7.5 + '@floating-ui/utils': 0.2.11 - '@firebase/app-types@0.9.2': {} + '@floating-ui/utils@0.2.10': {} - '@firebase/auth-interop-types@0.2.3': {} + '@floating-ui/utils@0.2.11': {} - '@firebase/component@0.6.9': + '@floating-ui/vue@1.1.9(vue@3.5.30(typescript@5.9.3))': dependencies: - '@firebase/util': 1.10.0 - tslib: 2.8.1 + '@floating-ui/dom': 1.7.6 + '@floating-ui/utils': 0.2.10 + vue-demi: 0.14.10(vue@3.5.30(typescript@5.9.3)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue - '@firebase/database-compat@1.0.8': - dependencies: - '@firebase/component': 0.6.9 - '@firebase/database': 1.0.8 - '@firebase/database-types': 1.0.5 - '@firebase/logger': 0.4.2 - '@firebase/util': 1.10.0 - tslib: 2.8.1 + '@hapi/hoek@9.3.0': {} - '@firebase/database-types@1.0.5': + '@hapi/topo@5.1.0': dependencies: - '@firebase/app-types': 0.9.2 - '@firebase/util': 1.10.0 + '@hapi/hoek': 9.3.0 - '@firebase/database@1.0.8': + '@headlessui/tailwindcss@0.2.2(tailwindcss@4.2.1)': dependencies: - '@firebase/app-check-interop-types': 0.3.2 - '@firebase/auth-interop-types': 0.2.3 - '@firebase/component': 0.6.9 - '@firebase/logger': 0.4.2 - '@firebase/util': 1.10.0 - faye-websocket: 0.11.4 - tslib: 2.8.1 + tailwindcss: 4.2.1 - '@firebase/logger@0.4.2': + '@headlessui/vue@1.7.23(vue@3.5.30(typescript@5.9.3))': dependencies: - tslib: 2.8.1 + '@tanstack/vue-virtual': 3.13.22(vue@3.5.30(typescript@5.9.3)) + vue: 3.5.30(typescript@5.9.3) - '@firebase/util@1.10.0': + '@hiogawa/vite-plugin-fullstack@0.0.11(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: - tslib: 2.8.1 + '@rolldown/pluginutils': 1.0.0-beta.55 + magic-string: 0.30.21 + srvx: 0.9.8 + strip-literal: 3.1.0 + vite: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) - '@floating-ui/core@1.6.9': - dependencies: - '@floating-ui/utils': 0.2.9 + '@img/colour@1.1.0': {} - '@floating-ui/dom@1.6.13': - dependencies: - '@floating-ui/core': 1.6.9 - '@floating-ui/utils': 0.2.9 + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true - '@floating-ui/utils@0.2.9': {} + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true - '@floating-ui/vue@1.1.6(vue@3.5.13(typescript@5.8.2))': - dependencies: - '@floating-ui/dom': 1.6.13 - '@floating-ui/utils': 0.2.9 - vue-demi: 0.14.10(vue@3.5.13(typescript@5.8.2)) - transitivePeerDependencies: - - '@vue/composition-api' - - vue + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true - '@google-cloud/firestore@7.11.0': - dependencies: - '@opentelemetry/api': 1.9.0 - fast-deep-equal: 3.1.3 - functional-red-black-tree: 1.0.1 - google-gax: 4.4.1 - protobufjs: 7.4.0 - transitivePeerDependencies: - - encoding - - supports-color + '@img/sharp-libvips-darwin-x64@1.2.4': optional: true - '@google-cloud/paginator@5.0.2': - dependencies: - arrify: 2.0.1 - extend: 3.0.2 + '@img/sharp-libvips-linux-arm64@1.2.4': optional: true - '@google-cloud/projectify@4.0.0': + '@img/sharp-libvips-linux-arm@1.2.4': optional: true - '@google-cloud/promisify@4.1.0': + '@img/sharp-libvips-linux-ppc64@1.2.4': optional: true - '@google-cloud/storage@7.15.2': - dependencies: - '@google-cloud/paginator': 5.0.2 - '@google-cloud/projectify': 4.0.0 - '@google-cloud/promisify': 4.1.0 - abort-controller: 3.0.0 - async-retry: 1.3.3 - duplexify: 4.1.3 - fast-xml-parser: 4.5.3 - gaxios: 6.7.1 - google-auth-library: 9.15.1 - html-entities: 2.5.2 - mime: 3.0.0 - p-limit: 3.1.0 - retry-request: 7.0.2 - teeny-request: 9.0.0 - uuid: 8.3.2 - transitivePeerDependencies: - - encoding - - supports-color + '@img/sharp-libvips-linux-riscv64@1.2.4': optional: true - '@grpc/grpc-js@1.12.6': - dependencies: - '@grpc/proto-loader': 0.7.13 - '@js-sdsl/ordered-map': 4.4.2 + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': optional: true - '@grpc/proto-loader@0.7.13': + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': dependencies: - lodash.camelcase: 4.3.0 - long: 5.3.1 - protobufjs: 7.4.0 - yargs: 17.7.2 + '@emnapi/runtime': 1.9.0 optional: true - '@hapi/hoek@9.3.0': {} + '@img/sharp-win32-arm64@0.34.5': + optional: true - '@hapi/topo@5.1.0': + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@internationalized/date@3.12.0': dependencies: - '@hapi/hoek': 9.3.0 + '@swc/helpers': 0.5.19 - '@headlessui/tailwindcss@0.2.2(tailwindcss@4.0.12)': + '@internationalized/number@3.6.5': dependencies: - tailwindcss: 4.0.12 + '@swc/helpers': 0.5.19 - '@headlessui/vue@1.7.23(vue@3.5.13(typescript@5.8.2))': + '@isaacs/cliui@8.0.2': dependencies: - '@tanstack/vue-virtual': 3.13.2(vue@3.5.13(typescript@5.8.2)) - vue: 3.5.13(typescript@5.8.2) + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.2.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 - '@humanfs/core@0.19.1': {} + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 - '@humanfs/node@0.16.6': + '@jridgewell/remapping@2.3.5': dependencies: - '@humanfs/core': 0.19.1 - '@humanwhocodes/retry': 0.3.1 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 - '@humanwhocodes/module-importer@1.0.1': {} + '@jridgewell/resolve-uri@3.1.2': {} - '@humanwhocodes/retry@0.3.1': {} + '@jridgewell/sourcemap-codec@1.5.5': {} - '@humanwhocodes/retry@0.4.2': {} + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 - '@hyperjump/browser@1.2.0': + '@jridgewell/trace-mapping@0.3.9': dependencies: - '@hyperjump/json-pointer': 1.1.0 - '@hyperjump/uri': 1.3.1 - content-type: 1.0.5 - just-curry-it: 5.3.0 - type-is: 1.6.18 + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 - '@hyperjump/json-pointer@1.1.0': {} + '@lezer/common@1.5.1': {} - '@hyperjump/json-schema@1.11.0(@hyperjump/browser@1.2.0)': + '@lezer/css@1.3.1': dependencies: - '@hyperjump/browser': 1.2.0 - '@hyperjump/json-pointer': 1.1.0 - '@hyperjump/pact': 1.3.0 - '@hyperjump/uri': 1.3.1 - content-type: 1.0.5 - json-stringify-deterministic: 1.0.12 - just-curry-it: 5.3.0 - uuid: 9.0.1 + '@lezer/common': 1.5.1 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.8 + + '@lezer/highlight@1.2.3': + dependencies: + '@lezer/common': 1.5.1 - '@hyperjump/pact@1.3.0': + '@lezer/html@1.3.13': dependencies: - just-curry-it: 5.3.0 + '@lezer/common': 1.5.1 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.8 - '@hyperjump/uri@1.3.1': {} + '@lezer/javascript@1.5.4': + dependencies: + '@lezer/common': 1.5.1 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.8 - '@internationalized/date@3.7.0': + '@lezer/json@1.0.3': dependencies: - '@swc/helpers': 0.5.15 + '@lezer/common': 1.5.1 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.8 - '@internationalized/number@3.6.0': + '@lezer/lr@1.4.8': dependencies: - '@swc/helpers': 0.5.15 + '@lezer/common': 1.5.1 - '@ioredis/commands@1.2.0': {} + '@lezer/xml@1.0.6': + dependencies: + '@lezer/common': 1.5.1 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.8 - '@isaacs/cliui@8.0.2': + '@lezer/yaml@1.0.4': dependencies: - string-width: 5.1.2 - string-width-cjs: string-width@4.2.3 - strip-ansi: 7.1.0 - strip-ansi-cjs: strip-ansi@6.0.1 - wrap-ansi: 8.1.0 - wrap-ansi-cjs: wrap-ansi@7.0.0 + '@lezer/common': 1.5.1 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.8 + + '@marijn/find-cluster-break@1.0.2': {} + + '@napi-rs/wasm-runtime@1.1.1': + dependencies: + '@emnapi/core': 1.9.0 + '@emnapi/runtime': 1.9.0 + '@tybys/wasm-util': 0.10.1 + optional: true - '@isaacs/fs-minipass@4.0.1': + '@netlify/edge-functions@3.0.4': dependencies: - minipass: 7.1.2 + '@netlify/types': 2.4.0 - '@istanbuljs/schema@0.1.3': {} + '@netlify/functions@5.1.3': + dependencies: + '@netlify/types': 2.4.0 + + '@netlify/types@2.4.0': {} + + '@oozcitak/dom@2.0.2': + dependencies: + '@oozcitak/infra': 2.0.2 + '@oozcitak/url': 3.0.0 + '@oozcitak/util': 10.0.0 + + '@oozcitak/infra@2.0.2': + dependencies: + '@oozcitak/util': 10.0.0 + + '@oozcitak/url@3.0.0': + dependencies: + '@oozcitak/infra': 2.0.2 + '@oozcitak/util': 10.0.0 + + '@oozcitak/util@10.0.0': {} + + '@opentelemetry/api@1.9.0': {} + + '@oxc-project/runtime@0.115.0': {} + + '@oxc-project/types@0.115.0': {} + + '@oxfmt/binding-android-arm-eabi@0.40.0': + optional: true + + '@oxfmt/binding-android-arm64@0.40.0': + optional: true + + '@oxfmt/binding-darwin-arm64@0.40.0': + optional: true + + '@oxfmt/binding-darwin-x64@0.40.0': + optional: true + + '@oxfmt/binding-freebsd-x64@0.40.0': + optional: true + + '@oxfmt/binding-linux-arm-gnueabihf@0.40.0': + optional: true + + '@oxfmt/binding-linux-arm-musleabihf@0.40.0': + optional: true + + '@oxfmt/binding-linux-arm64-gnu@0.40.0': + optional: true + + '@oxfmt/binding-linux-arm64-musl@0.40.0': + optional: true + + '@oxfmt/binding-linux-ppc64-gnu@0.40.0': + optional: true - '@jridgewell/gen-mapping@0.3.8': - dependencies: - '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.5.0 - '@jridgewell/trace-mapping': 0.3.25 + '@oxfmt/binding-linux-riscv64-gnu@0.40.0': + optional: true - '@jridgewell/resolve-uri@3.1.2': {} + '@oxfmt/binding-linux-riscv64-musl@0.40.0': + optional: true - '@jridgewell/set-array@1.2.1': {} + '@oxfmt/binding-linux-s390x-gnu@0.40.0': + optional: true - '@jridgewell/source-map@0.3.6': - dependencies: - '@jridgewell/gen-mapping': 0.3.8 - '@jridgewell/trace-mapping': 0.3.25 + '@oxfmt/binding-linux-x64-gnu@0.40.0': + optional: true - '@jridgewell/sourcemap-codec@1.5.0': {} + '@oxfmt/binding-linux-x64-musl@0.40.0': + optional: true - '@jridgewell/trace-mapping@0.3.25': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 + '@oxfmt/binding-openharmony-arm64@0.40.0': + optional: true - '@jridgewell/trace-mapping@0.3.9': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 + '@oxfmt/binding-win32-arm64-msvc@0.40.0': + optional: true - '@js-sdsl/ordered-map@4.4.2': + '@oxfmt/binding-win32-ia32-msvc@0.40.0': optional: true - '@lezer/common@1.2.3': {} + '@oxfmt/binding-win32-x64-msvc@0.40.0': + optional: true - '@lezer/css@1.1.10': - dependencies: - '@lezer/common': 1.2.3 - '@lezer/highlight': 1.2.1 - '@lezer/lr': 1.4.2 + '@oxlint/binding-android-arm-eabi@1.55.0': + optional: true - '@lezer/highlight@1.2.1': - dependencies: - '@lezer/common': 1.2.3 + '@oxlint/binding-android-arm64@1.55.0': + optional: true - '@lezer/html@1.3.10': - dependencies: - '@lezer/common': 1.2.3 - '@lezer/highlight': 1.2.1 - '@lezer/lr': 1.4.2 + '@oxlint/binding-darwin-arm64@1.55.0': + optional: true - '@lezer/javascript@1.4.21': - dependencies: - '@lezer/common': 1.2.3 - '@lezer/highlight': 1.2.1 - '@lezer/lr': 1.4.2 + '@oxlint/binding-darwin-x64@1.55.0': + optional: true - '@lezer/json@1.0.3': - dependencies: - '@lezer/common': 1.2.3 - '@lezer/highlight': 1.2.1 - '@lezer/lr': 1.4.2 + '@oxlint/binding-freebsd-x64@1.55.0': + optional: true - '@lezer/lr@1.4.2': - dependencies: - '@lezer/common': 1.2.3 + '@oxlint/binding-linux-arm-gnueabihf@1.55.0': + optional: true - '@lezer/xml@1.0.6': - dependencies: - '@lezer/common': 1.2.3 - '@lezer/highlight': 1.2.1 - '@lezer/lr': 1.4.2 + '@oxlint/binding-linux-arm-musleabihf@1.55.0': + optional: true - '@lezer/yaml@1.0.3': - dependencies: - '@lezer/common': 1.2.3 - '@lezer/highlight': 1.2.1 - '@lezer/lr': 1.4.2 + '@oxlint/binding-linux-arm64-gnu@1.55.0': + optional: true - '@mapbox/node-pre-gyp@2.0.0': - dependencies: - consola: 3.4.0 - detect-libc: 2.0.3 - https-proxy-agent: 7.0.6(supports-color@9.4.0) - node-fetch: 2.7.0 - nopt: 8.1.0 - semver: 7.7.1 - tar: 7.4.3 - transitivePeerDependencies: - - encoding - - supports-color + '@oxlint/binding-linux-arm64-musl@1.55.0': + optional: true - '@marijn/find-cluster-break@1.0.2': {} + '@oxlint/binding-linux-ppc64-gnu@1.55.0': + optional: true - '@netlify/edge-functions@2.11.1': {} + '@oxlint/binding-linux-riscv64-gnu@1.55.0': + optional: true - '@netlify/functions@3.0.0': - dependencies: - '@netlify/serverless-functions-api': 1.30.1 + '@oxlint/binding-linux-riscv64-musl@1.55.0': + optional: true - '@netlify/node-cookies@0.1.0': {} + '@oxlint/binding-linux-s390x-gnu@1.55.0': + optional: true - '@netlify/serverless-functions-api@1.30.1': - dependencies: - '@netlify/node-cookies': 0.1.0 - urlpattern-polyfill: 8.0.2 + '@oxlint/binding-linux-x64-gnu@1.55.0': + optional: true - '@nodelib/fs.scandir@2.1.5': - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 + '@oxlint/binding-linux-x64-musl@1.55.0': + optional: true - '@nodelib/fs.stat@2.0.5': {} + '@oxlint/binding-openharmony-arm64@1.55.0': + optional: true - '@nodelib/fs.walk@1.2.8': - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.19.1 + '@oxlint/binding-win32-arm64-msvc@1.55.0': + optional: true - '@opentelemetry/api@1.9.0': + '@oxlint/binding-win32-ia32-msvc@1.55.0': optional: true - '@parcel/watcher-android-arm64@2.5.1': + '@oxlint/binding-win32-x64-msvc@1.55.0': optional: true - '@parcel/watcher-darwin-arm64@2.5.1': + '@parcel/watcher-android-arm64@2.5.6': optional: true - '@parcel/watcher-darwin-x64@2.5.1': + '@parcel/watcher-darwin-arm64@2.5.6': optional: true - '@parcel/watcher-freebsd-x64@2.5.1': + '@parcel/watcher-darwin-x64@2.5.6': optional: true - '@parcel/watcher-linux-arm-glibc@2.5.1': + '@parcel/watcher-freebsd-x64@2.5.6': optional: true - '@parcel/watcher-linux-arm-musl@2.5.1': + '@parcel/watcher-linux-arm-glibc@2.5.6': optional: true - '@parcel/watcher-linux-arm64-glibc@2.5.1': + '@parcel/watcher-linux-arm-musl@2.5.6': optional: true - '@parcel/watcher-linux-arm64-musl@2.5.1': + '@parcel/watcher-linux-arm64-glibc@2.5.6': optional: true - '@parcel/watcher-linux-x64-glibc@2.5.1': + '@parcel/watcher-linux-arm64-musl@2.5.6': optional: true - '@parcel/watcher-linux-x64-musl@2.5.1': + '@parcel/watcher-linux-x64-glibc@2.5.6': optional: true - '@parcel/watcher-wasm@2.5.1': - dependencies: - is-glob: 4.0.3 - micromatch: 4.0.8 + '@parcel/watcher-linux-x64-musl@2.5.6': + optional: true - '@parcel/watcher-win32-arm64@2.5.1': + '@parcel/watcher-win32-arm64@2.5.6': optional: true - '@parcel/watcher-win32-ia32@2.5.1': + '@parcel/watcher-win32-ia32@2.5.6': optional: true - '@parcel/watcher-win32-x64@2.5.1': + '@parcel/watcher-win32-x64@2.5.6': optional: true - '@parcel/watcher@2.5.1': + '@parcel/watcher@2.5.6': dependencies: - detect-libc: 1.0.3 + detect-libc: 2.1.2 is-glob: 4.0.3 - micromatch: 4.0.8 node-addon-api: 7.1.1 + picomatch: 4.0.3 optionalDependencies: - '@parcel/watcher-android-arm64': 2.5.1 - '@parcel/watcher-darwin-arm64': 2.5.1 - '@parcel/watcher-darwin-x64': 2.5.1 - '@parcel/watcher-freebsd-x64': 2.5.1 - '@parcel/watcher-linux-arm-glibc': 2.5.1 - '@parcel/watcher-linux-arm-musl': 2.5.1 - '@parcel/watcher-linux-arm64-glibc': 2.5.1 - '@parcel/watcher-linux-arm64-musl': 2.5.1 - '@parcel/watcher-linux-x64-glibc': 2.5.1 - '@parcel/watcher-linux-x64-musl': 2.5.1 - '@parcel/watcher-win32-arm64': 2.5.1 - '@parcel/watcher-win32-ia32': 2.5.1 - '@parcel/watcher-win32-x64': 2.5.1 + '@parcel/watcher-android-arm64': 2.5.6 + '@parcel/watcher-darwin-arm64': 2.5.6 + '@parcel/watcher-darwin-x64': 2.5.6 + '@parcel/watcher-freebsd-x64': 2.5.6 + '@parcel/watcher-linux-arm-glibc': 2.5.6 + '@parcel/watcher-linux-arm-musl': 2.5.6 + '@parcel/watcher-linux-arm64-glibc': 2.5.6 + '@parcel/watcher-linux-arm64-musl': 2.5.6 + '@parcel/watcher-linux-x64-glibc': 2.5.6 + '@parcel/watcher-linux-x64-musl': 2.5.6 + '@parcel/watcher-win32-arm64': 2.5.6 + '@parcel/watcher-win32-ia32': 2.5.6 + '@parcel/watcher-win32-x64': 2.5.6 + + '@phosphor-icons/core@2.1.1': {} + + '@pinojs/redact@0.4.0': {} '@pkgjs/parseargs@0.11.0': optional: true @@ -6866,196 +8153,265 @@ snapshots: dependencies: graceful-fs: 4.2.10 - '@pnpm/npm-conf@2.3.1': + '@pnpm/npm-conf@3.0.2': dependencies: '@pnpm/config.env-replace': 1.1.0 '@pnpm/network.ca-file': 1.0.2 config-chain: 1.1.13 - '@popperjs/core@2.11.8': {} - - '@poppinss/colors@4.1.4': + '@poppinss/colors@4.1.6': dependencies: kleur: 4.1.5 - '@poppinss/dumper@0.6.3': + '@poppinss/dumper@0.6.5': + dependencies: + '@poppinss/colors': 4.1.6 + '@sindresorhus/is': 7.2.0 + supports-color: 10.2.2 + + '@poppinss/dumper@0.7.0': dependencies: - '@poppinss/colors': 4.1.4 - '@sindresorhus/is': 7.0.1 - supports-color: 10.0.0 + '@poppinss/colors': 4.1.6 + '@sindresorhus/is': 7.2.0 + supports-color: 10.2.2 - '@poppinss/exception@1.2.1': {} + '@poppinss/exception@1.2.3': {} + + '@preact/preset-vite@2.10.3(@babel/core@7.29.0)(preact@10.29.0)(rollup@4.59.0)(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.29.0) + '@prefresh/vite': 2.4.12(preact@10.29.0)(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) + babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.29.0) + debug: 4.4.3 + picocolors: 1.1.1 + vite: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + vite-prerender-plugin: 0.5.12(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) + transitivePeerDependencies: + - preact + - rollup + - supports-color - '@protobufjs/aspromise@1.1.2': {} + '@prefresh/babel-plugin@0.5.3': {} - '@protobufjs/base64@1.1.2': {} + '@prefresh/core@1.5.9(preact@10.29.0)': + dependencies: + preact: 10.29.0 - '@protobufjs/codegen@2.0.4': {} + '@prefresh/utils@1.2.1': {} - '@protobufjs/eventemitter@1.1.0': {} + '@prefresh/vite@2.4.12(preact@10.29.0)(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))': + dependencies: + '@babel/core': 7.29.0 + '@prefresh/babel-plugin': 0.5.3 + '@prefresh/core': 1.5.9(preact@10.29.0) + '@prefresh/utils': 1.2.1 + '@rollup/pluginutils': 4.2.1 + preact: 10.29.0 + vite: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + transitivePeerDependencies: + - supports-color - '@protobufjs/fetch@1.1.0': + '@replit/codemirror-css-color-picker@6.3.0(@codemirror/language@6.12.2)(@codemirror/state@6.6.0)(@codemirror/view@6.40.0)': dependencies: - '@protobufjs/aspromise': 1.1.2 - '@protobufjs/inquire': 1.1.0 + '@codemirror/language': 6.12.2 + '@codemirror/state': 6.6.0 + '@codemirror/view': 6.40.0 - '@protobufjs/float@1.0.2': {} + '@rolldown/binding-android-arm64@1.0.0-rc.9': + optional: true - '@protobufjs/inquire@1.1.0': {} + '@rolldown/binding-darwin-arm64@1.0.0-rc.9': + optional: true - '@protobufjs/path@1.1.2': {} + '@rolldown/binding-darwin-x64@1.0.0-rc.9': + optional: true - '@protobufjs/pool@1.1.0': {} + '@rolldown/binding-freebsd-x64@1.0.0-rc.9': + optional: true - '@protobufjs/utf8@1.1.0': {} + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.9': + optional: true - '@redocly/ajv@8.11.2': - dependencies: - fast-deep-equal: 3.1.3 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - uri-js-replace: 1.0.1 + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.9': + optional: true - '@redocly/config@0.22.1': {} + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.9': + optional: true - '@redocly/openapi-core@1.33.0(supports-color@9.4.0)': - dependencies: - '@redocly/ajv': 8.11.2 - '@redocly/config': 0.22.1 - colorette: 1.4.0 - https-proxy-agent: 7.0.6(supports-color@9.4.0) - js-levenshtein: 1.1.6 - js-yaml: 4.1.0 - minimatch: 5.1.6 - pluralize: 8.0.0 - yaml-ast-parser: 0.0.43 - transitivePeerDependencies: - - supports-color + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.9': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.9': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.9': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.0-rc.9': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.9': + optional: true - '@replit/codemirror-css-color-picker@6.3.0(@codemirror/language@6.10.8)(@codemirror/state@6.5.2)(@codemirror/view@6.36.4)': + '@rolldown/binding-wasm32-wasi@1.0.0-rc.9': dependencies: - '@codemirror/language': 6.10.8 - '@codemirror/state': 6.5.2 - '@codemirror/view': 6.36.4 + '@napi-rs/wasm-runtime': 1.1.1 + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.9': + optional: true - '@rollup/plugin-alias@5.1.1(rollup@4.35.0)': + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.9': + optional: true + + '@rolldown/pluginutils@1.0.0-beta.40': {} + + '@rolldown/pluginutils@1.0.0-beta.55': {} + + '@rolldown/pluginutils@1.0.0-rc.2': {} + + '@rolldown/pluginutils@1.0.0-rc.3': {} + + '@rolldown/pluginutils@1.0.0-rc.5': {} + + '@rolldown/pluginutils@1.0.0-rc.9': {} + + '@rollup/plugin-alias@6.0.0(rollup@4.59.0)': optionalDependencies: - rollup: 4.35.0 + rollup: 4.59.0 - '@rollup/plugin-commonjs@28.0.3(rollup@4.35.0)': + '@rollup/plugin-commonjs@29.0.2(rollup@4.59.0)': dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.35.0) + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) commondir: 1.0.1 estree-walker: 2.0.2 - fdir: 6.4.3(picomatch@4.0.2) + fdir: 6.5.0(picomatch@4.0.3) is-reference: 1.2.1 - magic-string: 0.30.17 - picomatch: 4.0.2 + magic-string: 0.30.21 + picomatch: 4.0.3 optionalDependencies: - rollup: 4.35.0 + rollup: 4.59.0 - '@rollup/plugin-inject@5.0.5(rollup@4.35.0)': + '@rollup/plugin-inject@5.0.5(rollup@4.59.0)': dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.35.0) + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) estree-walker: 2.0.2 - magic-string: 0.30.17 + magic-string: 0.30.21 optionalDependencies: - rollup: 4.35.0 + rollup: 4.59.0 - '@rollup/plugin-json@6.1.0(rollup@4.35.0)': + '@rollup/plugin-json@6.1.0(rollup@4.59.0)': dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.35.0) + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) optionalDependencies: - rollup: 4.35.0 + rollup: 4.59.0 - '@rollup/plugin-node-resolve@16.0.0(rollup@4.35.0)': + '@rollup/plugin-node-resolve@16.0.3(rollup@4.59.0)': dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.35.0) + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 - resolve: 1.22.10 + resolve: 1.22.11 optionalDependencies: - rollup: 4.35.0 + rollup: 4.59.0 - '@rollup/plugin-replace@6.0.2(rollup@4.35.0)': + '@rollup/plugin-replace@6.0.3(rollup@4.59.0)': dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.35.0) - magic-string: 0.30.17 + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) + magic-string: 0.30.21 optionalDependencies: - rollup: 4.35.0 + rollup: 4.59.0 - '@rollup/plugin-terser@0.4.4(rollup@4.35.0)': + '@rollup/pluginutils@4.2.1': dependencies: - serialize-javascript: 6.0.2 - smob: 1.5.0 - terser: 5.39.0 - optionalDependencies: - rollup: 4.35.0 + estree-walker: 2.0.2 + picomatch: 2.3.1 - '@rollup/pluginutils@5.1.4(rollup@4.35.0)': + '@rollup/pluginutils@5.3.0(rollup@4.59.0)': dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.8 estree-walker: 2.0.2 - picomatch: 4.0.2 + picomatch: 4.0.3 optionalDependencies: - rollup: 4.35.0 + rollup: 4.59.0 + + '@rollup/rollup-android-arm-eabi@4.59.0': + optional: true + + '@rollup/rollup-android-arm64@4.59.0': + optional: true + + '@rollup/rollup-darwin-arm64@4.59.0': + optional: true + + '@rollup/rollup-darwin-x64@4.59.0': + optional: true + + '@rollup/rollup-freebsd-arm64@4.59.0': + optional: true + + '@rollup/rollup-freebsd-x64@4.59.0': + optional: true - '@rollup/rollup-android-arm-eabi@4.35.0': + '@rollup/rollup-linux-arm-gnueabihf@4.59.0': optional: true - '@rollup/rollup-android-arm64@4.35.0': + '@rollup/rollup-linux-arm-musleabihf@4.59.0': optional: true - '@rollup/rollup-darwin-arm64@4.35.0': + '@rollup/rollup-linux-arm64-gnu@4.59.0': optional: true - '@rollup/rollup-darwin-x64@4.35.0': + '@rollup/rollup-linux-arm64-musl@4.59.0': optional: true - '@rollup/rollup-freebsd-arm64@4.35.0': + '@rollup/rollup-linux-loong64-gnu@4.59.0': optional: true - '@rollup/rollup-freebsd-x64@4.35.0': + '@rollup/rollup-linux-loong64-musl@4.59.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.35.0': + '@rollup/rollup-linux-ppc64-gnu@4.59.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.35.0': + '@rollup/rollup-linux-ppc64-musl@4.59.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.35.0': + '@rollup/rollup-linux-riscv64-gnu@4.59.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.35.0': + '@rollup/rollup-linux-riscv64-musl@4.59.0': optional: true - '@rollup/rollup-linux-loongarch64-gnu@4.35.0': + '@rollup/rollup-linux-s390x-gnu@4.59.0': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.35.0': + '@rollup/rollup-linux-x64-gnu@4.59.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.35.0': + '@rollup/rollup-linux-x64-musl@4.59.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.35.0': + '@rollup/rollup-openbsd-x64@4.59.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.35.0': + '@rollup/rollup-openharmony-arm64@4.59.0': optional: true - '@rollup/rollup-linux-x64-musl@4.35.0': + '@rollup/rollup-win32-arm64-msvc@4.59.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.35.0': + '@rollup/rollup-win32-ia32-msvc@4.59.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.35.0': + '@rollup/rollup-win32-x64-gnu@4.59.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.35.0': + '@rollup/rollup-win32-x64-msvc@4.59.0': optional: true '@sagold/json-pointer@5.1.2': {} @@ -7065,42 +8421,92 @@ snapshots: '@sagold/json-pointer': 5.1.2 ebnf: 1.9.1 - '@scalar/api-client@2.2.59(@hyperjump/browser@1.2.0)(axios@1.8.2)(change-case@5.4.4)(jwt-decode@4.0.0)(tailwindcss@4.0.12)(typescript@5.8.2)': - dependencies: - '@headlessui/tailwindcss': 0.2.2(tailwindcss@4.0.12) - '@headlessui/vue': 1.7.23(vue@3.5.13(typescript@5.8.2)) - '@scalar/components': 0.13.31(typescript@5.8.2) - '@scalar/draggable': 0.1.11(typescript@5.8.2) - '@scalar/icons': 0.1.3(typescript@5.8.2) - '@scalar/import': 0.2.33(@hyperjump/browser@1.2.0) - '@scalar/oas-utils': 0.2.113(@hyperjump/browser@1.2.0) - '@scalar/object-utils': 1.1.13 - '@scalar/openapi-parser': 0.10.9 - '@scalar/openapi-types': 0.1.9 - '@scalar/postman-to-openapi': 0.1.36(@hyperjump/browser@1.2.0) - '@scalar/snippetz': 0.2.16 - '@scalar/themes': 0.9.74 - '@scalar/types': 0.0.39 - '@scalar/use-codemirror': 0.11.76(typescript@5.8.2) - '@scalar/use-hooks': 0.1.28(typescript@5.8.2) - '@scalar/use-toasts': 0.7.9(typescript@5.8.2) - '@scalar/use-tooltip': 1.0.6(typescript@5.8.2) - '@vueuse/core': 10.11.1(vue@3.5.13(typescript@5.8.2)) - '@vueuse/integrations': 11.3.0(axios@1.8.2)(change-case@5.4.4)(focus-trap@7.6.4)(fuse.js@7.1.0)(jwt-decode@4.0.0)(vue@3.5.13(typescript@5.8.2)) - focus-trap: 7.6.4 + '@scalar/agent-chat@0.9.7(axios@1.13.6(debug@4.4.3))(jwt-decode@4.0.0)(tailwindcss@4.2.1)(typescript@5.9.3)': + dependencies: + '@ai-sdk/vue': 3.0.33(vue@3.5.30(typescript@5.9.3))(zod@4.3.6) + '@scalar/api-client': 2.37.0(axios@1.13.6(debug@4.4.3))(jwt-decode@4.0.0)(tailwindcss@4.2.1)(typescript@5.9.3) + '@scalar/components': 0.20.7(typescript@5.9.3) + '@scalar/helpers': 0.4.1 + '@scalar/icons': 0.6.0(typescript@5.9.3) + '@scalar/json-magic': 0.12.3 + '@scalar/openapi-types': 0.6.0 + '@scalar/themes': 0.15.0 + '@scalar/types': 0.7.3 + '@scalar/use-toasts': 0.10.0(typescript@5.9.3) + '@scalar/workspace-store': 0.40.0(typescript@5.9.3) + '@vueuse/core': 13.9.0(vue@3.5.30(typescript@5.9.3)) + ai: 6.0.33(zod@4.3.6) + neverpanic: 0.0.5(typescript@5.9.3) + truncate-json: 3.0.1 + vue: 3.5.30(typescript@5.9.3) + whatwg-mimetype: 4.0.0 + zod: 4.3.6 + transitivePeerDependencies: + - '@vue/composition-api' + - async-validator + - axios + - change-case + - drauu + - idb-keyval + - jwt-decode + - nprogress + - qrcode + - sortablejs + - supports-color + - tailwindcss + - typescript + - universal-cookie + + '@scalar/analytics-client@1.1.0': + dependencies: + zod: 4.3.6 + + '@scalar/api-client@2.37.0(axios@1.13.6(debug@4.4.3))(jwt-decode@4.0.0)(tailwindcss@4.2.1)(typescript@5.9.3)': + dependencies: + '@headlessui/tailwindcss': 0.2.2(tailwindcss@4.2.1) + '@headlessui/vue': 1.7.23(vue@3.5.30(typescript@5.9.3)) + '@scalar/analytics-client': 1.1.0 + '@scalar/components': 0.20.7(typescript@5.9.3) + '@scalar/draggable': 0.4.0(typescript@5.9.3) + '@scalar/helpers': 0.4.1 + '@scalar/icons': 0.6.0(typescript@5.9.3) + '@scalar/import': 0.5.2 + '@scalar/json-magic': 0.12.3 + '@scalar/oas-utils': 0.10.6(typescript@5.9.3) + '@scalar/object-utils': 1.3.2 + '@scalar/openapi-parser': 0.25.3 + '@scalar/openapi-types': 0.6.0 + '@scalar/postman-to-openapi': 0.5.2 + '@scalar/sidebar': 0.8.7(typescript@5.9.3) + '@scalar/snippetz': 0.7.4 + '@scalar/themes': 0.15.0 + '@scalar/typebox': 0.1.3 + '@scalar/types': 0.7.3 + '@scalar/use-codemirror': 0.14.7(typescript@5.9.3) + '@scalar/use-hooks': 0.4.0(typescript@5.9.3) + '@scalar/use-toasts': 0.10.0(typescript@5.9.3) + '@scalar/workspace-store': 0.40.0(typescript@5.9.3) + '@types/har-format': 1.2.16 + '@vueuse/core': 13.9.0(vue@3.5.30(typescript@5.9.3)) + '@vueuse/integrations': 13.9.0(axios@1.13.6(debug@4.4.3))(focus-trap@7.8.0)(fuse.js@7.1.0)(jwt-decode@4.0.0)(vue@3.5.30(typescript@5.9.3)) + focus-trap: 7.8.0 fuse.js: 7.1.0 + js-base64: 3.7.8 microdiff: 1.5.0 - nanoid: 5.1.3 - pretty-bytes: 6.1.1 - pretty-ms: 8.0.0 - shell-quote: 1.8.2 - vue: 3.5.13(typescript@5.8.2) - vue-router: 4.5.0(vue@3.5.13(typescript@5.8.2)) + monaco-editor: 0.54.0 + monaco-yaml: 5.2.3(monaco-editor@0.54.0) + nanoid: 5.1.6 + pretty-bytes: 7.1.0 + pretty-ms: 9.3.0 + shell-quote: 1.8.3 + type-fest: 5.4.4 + vite-plugin-monaco-editor: 1.1.0(monaco-editor@0.54.0) + vue: 3.5.30(typescript@5.9.3) + vue-router: 4.6.2(vue@3.5.30(typescript@5.9.3)) whatwg-mimetype: 4.0.0 - yaml: 2.7.0 - zod: 3.24.2 + yaml: 2.8.2 + zod: 4.3.6 transitivePeerDependencies: - - '@hyperjump/browser' - '@vue/composition-api' - async-validator - axios @@ -7116,30 +8522,33 @@ snapshots: - typescript - universal-cookie - '@scalar/api-reference@1.25.130(@hyperjump/browser@1.2.0)(axios@1.8.2)(change-case@5.4.4)(jwt-decode@4.0.0)(tailwindcss@4.0.12)(typescript@5.8.2)': - dependencies: - '@floating-ui/vue': 1.1.6(vue@3.5.13(typescript@5.8.2)) - '@headlessui/vue': 1.7.23(vue@3.5.13(typescript@5.8.2)) - '@scalar/api-client': 2.2.59(@hyperjump/browser@1.2.0)(axios@1.8.2)(change-case@5.4.4)(jwt-decode@4.0.0)(tailwindcss@4.0.12)(typescript@5.8.2) - '@scalar/code-highlight': 0.0.23 - '@scalar/components': 0.13.31(typescript@5.8.2) - '@scalar/oas-utils': 0.2.113(@hyperjump/browser@1.2.0) - '@scalar/openapi-parser': 0.10.9 - '@scalar/openapi-types': 0.1.9 - '@scalar/snippetz': 0.2.16 - '@scalar/themes': 0.9.74 - '@scalar/types': 0.0.39 - '@scalar/use-hooks': 0.1.28(typescript@5.8.2) - '@scalar/use-toasts': 0.7.9(typescript@5.8.2) - '@unhead/vue': 1.11.20(vue@3.5.13(typescript@5.8.2)) - '@vueuse/core': 10.11.1(vue@3.5.13(typescript@5.8.2)) + '@scalar/api-reference@1.48.7(axios@1.13.6(debug@4.4.3))(jwt-decode@4.0.0)(tailwindcss@4.2.1)(typescript@5.9.3)': + dependencies: + '@headlessui/vue': 1.7.23(vue@3.5.30(typescript@5.9.3)) + '@scalar/agent-chat': 0.9.7(axios@1.13.6(debug@4.4.3))(jwt-decode@4.0.0)(tailwindcss@4.2.1)(typescript@5.9.3) + '@scalar/api-client': 2.37.0(axios@1.13.6(debug@4.4.3))(jwt-decode@4.0.0)(tailwindcss@4.2.1)(typescript@5.9.3) + '@scalar/code-highlight': 0.3.0 + '@scalar/components': 0.20.7(typescript@5.9.3) + '@scalar/helpers': 0.4.1 + '@scalar/icons': 0.6.0(typescript@5.9.3) + '@scalar/oas-utils': 0.10.6(typescript@5.9.3) + '@scalar/openapi-parser': 0.25.3 + '@scalar/openapi-types': 0.6.0 + '@scalar/sidebar': 0.8.7(typescript@5.9.3) + '@scalar/snippetz': 0.7.4 + '@scalar/themes': 0.15.0 + '@scalar/types': 0.7.3 + '@scalar/use-hooks': 0.4.0(typescript@5.9.3) + '@scalar/use-toasts': 0.10.0(typescript@5.9.3) + '@scalar/workspace-store': 0.40.0(typescript@5.9.3) + '@unhead/vue': 2.1.12(vue@3.5.30(typescript@5.9.3)) + '@vueuse/core': 13.9.0(vue@3.5.30(typescript@5.9.3)) fuse.js: 7.1.0 github-slugger: 2.0.0 - nanoid: 5.1.3 - vue: 3.5.13(typescript@5.8.2) - zod: 3.24.2 + microdiff: 1.5.0 + nanoid: 5.1.6 + vue: 3.5.30(typescript@5.9.3) transitivePeerDependencies: - - '@hyperjump/browser' - '@vue/composition-api' - async-validator - axios @@ -7155,12 +8564,11 @@ snapshots: - typescript - universal-cookie - '@scalar/code-highlight@0.0.23': + '@scalar/code-highlight@0.3.0': dependencies: hast-util-to-text: 4.0.2 highlight.js: 11.11.1 highlightjs-curl: 1.3.0 - highlightjs-vue: 1.0.0 lowlight: 3.3.0 rehype-external-links: 3.0.0 rehype-format: 5.0.1 @@ -7170,216 +8578,607 @@ snapshots: rehype-stringify: 10.0.1 remark-gfm: 4.0.1 remark-parse: 11.0.0 - remark-rehype: 11.1.1 + remark-rehype: 11.1.2 remark-stringify: 11.0.0 unified: 11.0.5 - unist-util-visit: 5.0.0 + unist-util-visit: 5.1.0 transitivePeerDependencies: - supports-color - '@scalar/components@0.13.31(typescript@5.8.2)': - dependencies: - '@floating-ui/utils': 0.2.9 - '@floating-ui/vue': 1.1.6(vue@3.5.13(typescript@5.8.2)) - '@headlessui/vue': 1.7.23(vue@3.5.13(typescript@5.8.2)) - '@scalar/code-highlight': 0.0.23 - '@scalar/themes': 0.9.74 - '@scalar/use-hooks': 0.1.28(typescript@5.8.2) - '@scalar/use-toasts': 0.7.9(typescript@5.8.2) - '@vueuse/core': 10.11.1(vue@3.5.13(typescript@5.8.2)) - cva: 1.0.0-beta.2(typescript@5.8.2) - nanoid: 5.1.3 - pretty-bytes: 6.1.1 - radix-vue: 1.9.17(vue@3.5.13(typescript@5.8.2)) - tailwind-merge: 2.6.0 - vue: 3.5.13(typescript@5.8.2) + '@scalar/components@0.20.7(typescript@5.9.3)': + dependencies: + '@floating-ui/utils': 0.2.10 + '@floating-ui/vue': 1.1.9(vue@3.5.30(typescript@5.9.3)) + '@headlessui/vue': 1.7.23(vue@3.5.30(typescript@5.9.3)) + '@scalar/code-highlight': 0.3.0 + '@scalar/helpers': 0.4.1 + '@scalar/icons': 0.6.0(typescript@5.9.3) + '@scalar/oas-utils': 0.10.6(typescript@5.9.3) + '@scalar/themes': 0.15.0 + '@scalar/use-hooks': 0.4.0(typescript@5.9.3) + '@vueuse/core': 13.9.0(vue@3.5.30(typescript@5.9.3)) + cva: 1.0.0-beta.4(typescript@5.9.3) + nanoid: 5.1.6 + pretty-bytes: 7.1.0 + radix-vue: 1.9.17(vue@3.5.30(typescript@5.9.3)) + vue: 3.5.30(typescript@5.9.3) + vue-component-type-helpers: 3.2.5 transitivePeerDependencies: - '@vue/composition-api' - supports-color - typescript - '@scalar/draggable@0.1.11(typescript@5.8.2)': + '@scalar/draggable@0.4.0(typescript@5.9.3)': dependencies: - vue: 3.5.13(typescript@5.8.2) + vue: 3.5.30(typescript@5.9.3) transitivePeerDependencies: - typescript - '@scalar/icons@0.1.3(typescript@5.8.2)': + '@scalar/helpers@0.4.1': {} + + '@scalar/icons@0.6.0(typescript@5.9.3)': dependencies: - vue: 3.5.13(typescript@5.8.2) + '@phosphor-icons/core': 2.1.1 + '@types/node': 24.12.0 + chalk: 5.6.2 + vue: 3.5.30(typescript@5.9.3) transitivePeerDependencies: - typescript - '@scalar/import@0.2.33(@hyperjump/browser@1.2.0)': + '@scalar/import@0.5.2': dependencies: - '@scalar/oas-utils': 0.2.113(@hyperjump/browser@1.2.0) - '@scalar/openapi-parser': 0.10.9 - yaml: 2.7.0 - transitivePeerDependencies: - - '@hyperjump/browser' + '@scalar/helpers': 0.4.1 + yaml: 2.8.2 - '@scalar/oas-utils@0.2.113(@hyperjump/browser@1.2.0)': + '@scalar/json-magic@0.12.3': dependencies: - '@hyperjump/json-schema': 1.11.0(@hyperjump/browser@1.2.0) - '@scalar/object-utils': 1.1.13 - '@scalar/openapi-types': 0.1.9 - '@scalar/themes': 0.9.74 - '@scalar/types': 0.0.39 - flatted: 3.3.3 - microdiff: 1.5.0 - nanoid: 5.1.3 - yaml: 2.7.0 - zod: 3.24.2 + '@scalar/helpers': 0.4.1 + pathe: 2.0.3 + yaml: 2.8.2 + + '@scalar/oas-utils@0.10.6(typescript@5.9.3)': + dependencies: + '@scalar/helpers': 0.4.1 + '@scalar/json-magic': 0.12.3 + '@scalar/object-utils': 1.3.2 + '@scalar/openapi-types': 0.6.0 + '@scalar/themes': 0.15.0 + '@scalar/types': 0.7.3 + '@scalar/workspace-store': 0.40.0(typescript@5.9.3) + flatted: 3.4.1 + github-slugger: 2.0.0 + type-fest: 5.4.4 + vue: 3.5.30(typescript@5.9.3) + yaml: 2.8.2 + zod: 4.3.6 transitivePeerDependencies: - - '@hyperjump/browser' + - supports-color + - typescript - '@scalar/object-utils@1.1.13': + '@scalar/object-utils@1.3.2': dependencies: - flatted: 3.3.3 + '@scalar/helpers': 0.4.1 + flatted: 3.4.1 just-clone: 6.2.0 - ts-deepmerge: 7.0.2 + ts-deepmerge: 7.0.3 - '@scalar/openapi-parser@0.10.9': + '@scalar/openapi-parser@0.25.3': dependencies: - ajv: 8.17.1 - ajv-draft-04: 1.0.0(ajv@8.17.1) - ajv-formats: 3.0.1(ajv@8.17.1) + '@scalar/helpers': 0.4.1 + '@scalar/json-magic': 0.12.3 + '@scalar/openapi-types': 0.6.0 + '@scalar/openapi-upgrader': 0.2.0 + ajv: 8.18.0 + ajv-draft-04: 1.0.0(ajv@8.18.0) + ajv-formats: 3.0.1(ajv@8.18.0) jsonpointer: 5.0.1 - leven: 4.0.0 - yaml: 2.7.0 + leven: 4.1.0 + yaml: 2.8.2 + + '@scalar/openapi-types@0.6.0': + dependencies: + zod: 4.3.6 + + '@scalar/openapi-upgrader@0.2.0': + dependencies: + '@scalar/openapi-types': 0.6.0 + + '@scalar/postman-to-openapi@0.5.2': + dependencies: + '@scalar/helpers': 0.4.1 + '@scalar/openapi-types': 0.6.0 + + '@scalar/sidebar@0.8.7(typescript@5.9.3)': + dependencies: + '@scalar/components': 0.20.7(typescript@5.9.3) + '@scalar/helpers': 0.4.1 + '@scalar/icons': 0.6.0(typescript@5.9.3) + '@scalar/themes': 0.15.0 + '@scalar/use-hooks': 0.4.0(typescript@5.9.3) + '@scalar/workspace-store': 0.40.0(typescript@5.9.3) + vue: 3.5.30(typescript@5.9.3) + transitivePeerDependencies: + - '@vue/composition-api' + - supports-color + - typescript + + '@scalar/snippetz@0.7.4': + dependencies: + '@scalar/types': 0.7.3 + js-base64: 3.7.8 + stringify-object: 6.0.0 + + '@scalar/themes@0.15.0': + dependencies: + nanoid: 5.1.6 + + '@scalar/typebox@0.1.3': {} + + '@scalar/types@0.7.3': + dependencies: + '@scalar/helpers': 0.4.1 + nanoid: 5.1.6 + type-fest: 5.4.4 + zod: 4.3.6 + + '@scalar/use-codemirror@0.14.7(typescript@5.9.3)': + dependencies: + '@codemirror/autocomplete': 6.20.1 + '@codemirror/commands': 6.10.3 + '@codemirror/lang-css': 6.3.1 + '@codemirror/lang-html': 6.4.11 + '@codemirror/lang-json': 6.0.2 + '@codemirror/lang-xml': 6.1.0 + '@codemirror/lang-yaml': 6.1.2 + '@codemirror/language': 6.12.2 + '@codemirror/lint': 6.9.5 + '@codemirror/state': 6.6.0 + '@codemirror/view': 6.40.0 + '@lezer/common': 1.5.1 + '@lezer/highlight': 1.2.3 + '@replit/codemirror-css-color-picker': 6.3.0(@codemirror/language@6.12.2)(@codemirror/state@6.6.0)(@codemirror/view@6.40.0) + '@scalar/components': 0.20.7(typescript@5.9.3) + vue: 3.5.30(typescript@5.9.3) + transitivePeerDependencies: + - '@vue/composition-api' + - supports-color + - typescript + + '@scalar/use-hooks@0.4.0(typescript@5.9.3)': + dependencies: + '@scalar/use-toasts': 0.10.0(typescript@5.9.3) + '@vueuse/core': 13.9.0(vue@3.5.30(typescript@5.9.3)) + cva: 1.0.0-beta.2(typescript@5.9.3) + tailwind-merge: 3.4.0 + vue: 3.5.30(typescript@5.9.3) + zod: 4.3.6 + transitivePeerDependencies: + - typescript + + '@scalar/use-toasts@0.10.0(typescript@5.9.3)': + dependencies: + vue: 3.5.30(typescript@5.9.3) + vue-sonner: 1.3.2 + transitivePeerDependencies: + - typescript + + '@scalar/workspace-store@0.40.0(typescript@5.9.3)': + dependencies: + '@scalar/code-highlight': 0.3.0 + '@scalar/helpers': 0.4.1 + '@scalar/json-magic': 0.12.3 + '@scalar/object-utils': 1.3.2 + '@scalar/openapi-upgrader': 0.2.0 + '@scalar/snippetz': 0.7.4 + '@scalar/typebox': 0.1.3 + '@scalar/types': 0.7.3 + github-slugger: 2.0.0 + type-fest: 5.4.4 + vue: 3.5.30(typescript@5.9.3) + yaml: 2.8.2 + transitivePeerDependencies: + - supports-color + - typescript + + '@sec-ant/readable-stream@0.4.1': {} + + '@shikijs/core@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 - '@scalar/openapi-types@0.1.9': {} + '@shikijs/engine-javascript@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + '@shikijs/vscode-textmate': 10.0.2 + oniguruma-to-es: 4.3.4 + + '@shikijs/engine-oniguruma@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + '@shikijs/vscode-textmate': 10.0.2 + + '@shikijs/langs@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + + '@shikijs/themes@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + + '@shikijs/types@3.23.0': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + '@shikijs/vscode-textmate@10.0.2': {} + + '@sideway/address@4.1.5': + dependencies: + '@hapi/hoek': 9.3.0 + + '@sideway/formula@3.0.1': {} + + '@sideway/pinpoint@2.0.0': {} + + '@sinclair/typebox@0.34.48': {} + + '@sindresorhus/is@7.2.0': {} + + '@sindresorhus/merge-streams@4.0.0': {} + + '@speed-highlight/core@1.2.14': {} + + '@standard-schema/spec@1.1.0': {} + + '@swc/helpers@0.5.19': + dependencies: + tslib: 2.8.1 + + '@tailwindcss/node@4.2.1': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.20.0 + jiti: 2.6.1 + lightningcss: 1.31.1 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.2.1 + + '@tailwindcss/oxide-android-arm64@4.2.1': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.2.1': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.2.1': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.2.1': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.2.1': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.2.1': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.2.1': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.2.1': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.2.1': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.2.1': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.2.1': + optional: true + + '@tailwindcss/oxide@4.2.1': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.2.1 + '@tailwindcss/oxide-darwin-arm64': 4.2.1 + '@tailwindcss/oxide-darwin-x64': 4.2.1 + '@tailwindcss/oxide-freebsd-x64': 4.2.1 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.1 + '@tailwindcss/oxide-linux-arm64-gnu': 4.2.1 + '@tailwindcss/oxide-linux-arm64-musl': 4.2.1 + '@tailwindcss/oxide-linux-x64-gnu': 4.2.1 + '@tailwindcss/oxide-linux-x64-musl': 4.2.1 + '@tailwindcss/oxide-wasm32-wasi': 4.2.1 + '@tailwindcss/oxide-win32-arm64-msvc': 4.2.1 + '@tailwindcss/oxide-win32-x64-msvc': 4.2.1 + + '@tailwindcss/vite@4.2.1(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))': + dependencies: + '@tailwindcss/node': 4.2.1 + '@tailwindcss/oxide': 4.2.1 + tailwindcss: 4.2.1 + vite: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + + '@tanstack/history@1.161.4': {} + + '@tanstack/react-router-devtools@1.166.7(@tanstack/react-router@1.167.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.167.0)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/react-router': 1.167.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-devtools-core': 1.166.7(@tanstack/router-core@1.167.0)(csstype@3.2.3) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@tanstack/router-core': 1.167.0 + transitivePeerDependencies: + - csstype + + '@tanstack/react-router@1.167.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/history': 1.161.4 + '@tanstack/react-store': 0.9.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-core': 1.167.0 + isbot: 5.1.36 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + tiny-invariant: 1.3.3 + tiny-warning: 1.0.3 + + '@tanstack/react-start-client@1.166.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/react-router': 1.167.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-core': 1.167.0 + '@tanstack/start-client-core': 1.166.8 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + tiny-invariant: 1.3.3 + tiny-warning: 1.0.3 + + '@tanstack/react-start-server@1.166.9(crossws@0.4.4(srvx@0.11.9))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/history': 1.161.4 + '@tanstack/react-router': 1.167.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-core': 1.167.0 + '@tanstack/start-client-core': 1.166.8 + '@tanstack/start-server-core': 1.166.8(crossws@0.4.4(srvx@0.11.9)) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + transitivePeerDependencies: + - crossws - '@scalar/postman-to-openapi@0.1.36(@hyperjump/browser@1.2.0)': + '@tanstack/react-start@1.166.11(crossws@0.4.4(srvx@0.11.9))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite-plugin-solid@2.11.11(solid-js@1.9.11)(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: - '@scalar/oas-utils': 0.2.113(@hyperjump/browser@1.2.0) - '@scalar/openapi-types': 0.1.9 + '@tanstack/react-router': 1.167.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-start-client': 1.166.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-start-server': 1.166.9(crossws@0.4.4(srvx@0.11.9))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-utils': 1.161.4 + '@tanstack/start-client-core': 1.166.8 + '@tanstack/start-plugin-core': 1.166.11(@tanstack/react-router@1.167.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(crossws@0.4.4(srvx@0.11.9))(vite-plugin-solid@2.11.11(solid-js@1.9.11)(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) + '@tanstack/start-server-core': 1.166.8(crossws@0.4.4(srvx@0.11.9)) + pathe: 2.0.3 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + vite: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - - '@hyperjump/browser' + - '@rsbuild/core' + - crossws + - supports-color + - vite-plugin-solid + - webpack - '@scalar/snippetz@0.2.16': + '@tanstack/react-store@0.9.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - stringify-object: 5.0.0 + '@tanstack/store': 0.9.2 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + use-sync-external-store: 1.6.0(react@19.2.4) - '@scalar/themes@0.9.74': + '@tanstack/router-core@1.167.0': dependencies: - '@scalar/types': 0.0.39 + '@tanstack/history': 1.161.4 + '@tanstack/store': 0.9.2 + cookie-es: 2.0.0 + seroval: 1.5.1 + seroval-plugins: 1.5.1(seroval@1.5.1) + tiny-invariant: 1.3.3 + tiny-warning: 1.0.3 - '@scalar/types@0.0.39': + '@tanstack/router-devtools-core@1.166.7(@tanstack/router-core@1.167.0)(csstype@3.2.3)': dependencies: - '@scalar/openapi-types': 0.1.9 - '@unhead/schema': 1.11.20 - zod: 3.24.2 + '@tanstack/router-core': 1.167.0 + clsx: 2.1.1 + goober: 2.1.18(csstype@3.2.3) + tiny-invariant: 1.3.3 + optionalDependencies: + csstype: 3.2.3 + + '@tanstack/router-generator@1.166.8': + dependencies: + '@tanstack/router-core': 1.167.0 + '@tanstack/router-utils': 1.161.4 + '@tanstack/virtual-file-routes': 1.161.4 + prettier: 3.8.1 + recast: 0.23.11 + source-map: 0.7.6 + tsx: 4.21.0 + zod: 3.25.76 + transitivePeerDependencies: + - supports-color - '@scalar/use-codemirror@0.11.76(typescript@5.8.2)': - dependencies: - '@codemirror/autocomplete': 6.18.6 - '@codemirror/commands': 6.8.0 - '@codemirror/lang-css': 6.3.1 - '@codemirror/lang-html': 6.4.9 - '@codemirror/lang-json': 6.0.1 - '@codemirror/lang-xml': 6.1.0 - '@codemirror/lang-yaml': 6.1.2 - '@codemirror/language': 6.10.8 - '@codemirror/lint': 6.8.4 - '@codemirror/state': 6.5.2 - '@codemirror/view': 6.36.4 - '@lezer/common': 1.2.3 - '@lezer/highlight': 1.2.1 - '@lezer/lr': 1.4.2 - '@replit/codemirror-css-color-picker': 6.3.0(@codemirror/language@6.10.8)(@codemirror/state@6.5.2)(@codemirror/view@6.36.4) - '@scalar/components': 0.13.31(typescript@5.8.2) - codemirror: 6.0.1 - style-mod: 4.1.2 - vue: 3.5.13(typescript@5.8.2) + '@tanstack/router-plugin@1.166.9(@tanstack/react-router@1.167.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite-plugin-solid@2.11.11(solid-js@1.9.11)(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@tanstack/router-core': 1.167.0 + '@tanstack/router-generator': 1.166.8 + '@tanstack/router-utils': 1.161.4 + '@tanstack/virtual-file-routes': 1.161.4 + chokidar: 3.6.0 + unplugin: 2.3.11 + zod: 3.25.76 + optionalDependencies: + '@tanstack/react-router': 1.167.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + vite: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + vite-plugin-solid: 2.11.11(solid-js@1.9.11)(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) transitivePeerDependencies: - - '@vue/composition-api' - supports-color - - typescript - '@scalar/use-hooks@0.1.28(typescript@5.8.2)': + '@tanstack/router-utils@1.161.4': dependencies: - '@scalar/themes': 0.9.74 - '@scalar/use-toasts': 0.7.9(typescript@5.8.2) - '@vueuse/core': 10.11.1(vue@3.5.13(typescript@5.8.2)) - vue: 3.5.13(typescript@5.8.2) - zod: 3.24.2 + '@babel/core': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + ansis: 4.2.0 + babel-dead-code-elimination: 1.0.12 + diff: 8.0.3 + pathe: 2.0.3 + tinyglobby: 0.2.15 transitivePeerDependencies: - - '@vue/composition-api' - - typescript + - supports-color - '@scalar/use-toasts@0.7.9(typescript@5.8.2)': - dependencies: - nanoid: 5.1.3 - vue: 3.5.13(typescript@5.8.2) - vue-sonner: 1.3.0 + '@tanstack/start-client-core@1.166.8': + dependencies: + '@tanstack/router-core': 1.167.0 + '@tanstack/start-fn-stubs': 1.161.4 + '@tanstack/start-storage-context': 1.166.8 + seroval: 1.5.1 + tiny-invariant: 1.3.3 + tiny-warning: 1.0.3 + + '@tanstack/start-fn-stubs@1.161.4': {} + + '@tanstack/start-plugin-core@1.166.11(@tanstack/react-router@1.167.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(crossws@0.4.4(srvx@0.11.9))(vite-plugin-solid@2.11.11(solid-js@1.9.11)(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/core': 7.29.0 + '@babel/types': 7.29.0 + '@rolldown/pluginutils': 1.0.0-beta.40 + '@tanstack/router-core': 1.167.0 + '@tanstack/router-generator': 1.166.8 + '@tanstack/router-plugin': 1.166.9(@tanstack/react-router@1.167.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite-plugin-solid@2.11.11(solid-js@1.9.11)(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)))(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) + '@tanstack/router-utils': 1.161.4 + '@tanstack/start-client-core': 1.166.8 + '@tanstack/start-server-core': 1.166.8(crossws@0.4.4(srvx@0.11.9)) + cheerio: 1.2.0 + exsolve: 1.0.8 + pathe: 2.0.3 + picomatch: 4.0.3 + source-map: 0.7.6 + srvx: 0.11.9 + tinyglobby: 0.2.15 + ufo: 1.6.3 + vite: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + vitefu: 1.1.2(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) + xmlbuilder2: 4.0.3 + zod: 3.25.76 transitivePeerDependencies: - - typescript + - '@rsbuild/core' + - '@tanstack/react-router' + - crossws + - supports-color + - vite-plugin-solid + - webpack + + '@tanstack/start-server-core@1.166.8(crossws@0.4.4(srvx@0.11.9))': + dependencies: + '@tanstack/history': 1.161.4 + '@tanstack/router-core': 1.167.0 + '@tanstack/start-client-core': 1.166.8 + '@tanstack/start-storage-context': 1.166.8 + h3-v2: h3@2.0.1-rc.16(crossws@0.4.4(srvx@0.11.9)) + seroval: 1.5.1 + tiny-invariant: 1.3.3 + transitivePeerDependencies: + - crossws - '@scalar/use-tooltip@1.0.6(typescript@5.8.2)': + '@tanstack/start-storage-context@1.166.8': dependencies: - tippy.js: 6.3.7 - vue: 3.5.13(typescript@5.8.2) - transitivePeerDependencies: - - typescript + '@tanstack/router-core': 1.167.0 - '@sec-ant/readable-stream@0.4.1': {} + '@tanstack/store@0.9.2': {} - '@sideway/address@4.1.5': - dependencies: - '@hapi/hoek': 9.3.0 + '@tanstack/virtual-core@3.13.22': {} - '@sideway/formula@3.0.1': {} + '@tanstack/virtual-file-routes@1.161.4': {} - '@sideway/pinpoint@2.0.0': {} + '@tanstack/vue-virtual@3.13.22(vue@3.5.30(typescript@5.9.3))': + dependencies: + '@tanstack/virtual-core': 3.13.22 + vue: 3.5.30(typescript@5.9.3) + + '@tokenizer/inflate@0.4.1': + dependencies: + debug: 4.4.3 + token-types: 6.1.2 + transitivePeerDependencies: + - supports-color - '@sindresorhus/is@7.0.1': {} + '@tokenizer/token@0.3.0': {} - '@sindresorhus/merge-streams@2.3.0': {} + '@toon-format/toon@0.9.0': {} - '@sindresorhus/merge-streams@4.0.0': {} + '@trpc/client@11.12.0(@trpc/server@11.12.0(typescript@5.9.3))(typescript@5.9.3)': + dependencies: + '@trpc/server': 11.12.0(typescript@5.9.3) + typescript: 5.9.3 - '@speed-highlight/core@1.2.7': {} + '@trpc/server@11.12.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 - '@swc/helpers@0.5.15': + '@tybys/wasm-util@0.10.1': dependencies: tslib: 2.8.1 + optional: true - '@tanstack/virtual-core@3.13.2': {} + '@types/aws-lambda@8.10.161': {} - '@tanstack/vue-virtual@3.13.2(vue@3.5.13(typescript@5.8.2))': + '@types/babel__core@7.20.5': dependencies: - '@tanstack/virtual-core': 3.13.2 - vue: 3.5.13(typescript@5.8.2) - - '@tootallnate/once@2.0.0': - optional: true + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 - '@trysound/sax@0.2.0': {} + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.29.0 - '@types/archiver@6.0.3': + '@types/babel__template@7.4.4': dependencies: - '@types/readdir-glob': 1.1.5 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 - '@types/aws-lambda@8.10.147': {} + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.29.0 - '@types/body-parser@1.19.5': + '@types/body-parser@1.19.6': dependencies: '@types/connect': 3.4.38 - '@types/node': 22.13.10 + '@types/node': 25.5.0 - '@types/caseless@0.12.5': - optional: true + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 '@types/configstore@2.1.1': {} '@types/connect@3.4.38': dependencies: - '@types/node': 22.13.10 - - '@types/cors@2.8.17': - dependencies: - '@types/node': 22.13.10 + '@types/node': 25.5.0 '@types/debug@0.0.30': {} @@ -7387,506 +9186,394 @@ snapshots: dependencies: '@types/ms': 2.1.0 - '@types/estree@1.0.6': {} + '@types/deep-eql@4.0.2': {} - '@types/etag@1.8.3': - dependencies: - '@types/node': 22.13.10 + '@types/estree@1.0.8': {} - '@types/express-serve-static-core@4.19.6': + '@types/etag@1.8.4': dependencies: - '@types/node': 22.13.10 - '@types/qs': 6.9.18 - '@types/range-parser': 1.2.7 - '@types/send': 0.17.4 + '@types/node': 25.5.0 - '@types/express-serve-static-core@5.0.6': + '@types/express-serve-static-core@5.1.1': dependencies: - '@types/node': 22.13.10 - '@types/qs': 6.9.18 + '@types/node': 25.5.0 + '@types/qs': 6.15.0 '@types/range-parser': 1.2.7 - '@types/send': 0.17.4 - - '@types/express@4.17.21': - dependencies: - '@types/body-parser': 1.19.5 - '@types/express-serve-static-core': 4.19.6 - '@types/qs': 6.9.18 - '@types/serve-static': 1.15.7 + '@types/send': 1.2.1 - '@types/express@4.17.3': + '@types/express@5.0.6': dependencies: - '@types/body-parser': 1.19.5 - '@types/express-serve-static-core': 5.0.6 - '@types/serve-static': 1.15.7 - - '@types/fs-extra@11.0.4': - dependencies: - '@types/jsonfile': 6.1.4 - '@types/node': 22.13.10 + '@types/body-parser': 1.19.6 + '@types/express-serve-static-core': 5.1.1 + '@types/serve-static': 2.2.0 '@types/get-port@3.2.0': {} '@types/glob@5.0.38': dependencies: - '@types/minimatch': 5.1.2 - '@types/node': 8.10.66 + '@types/minimatch': 6.0.0 + '@types/node': 25.5.0 + + '@types/har-format@1.2.16': {} '@types/hast@3.0.4': dependencies: '@types/unist': 3.0.3 - '@types/http-errors@2.0.4': {} - - '@types/http-proxy@1.17.16': - dependencies: - '@types/node': 22.13.10 - - '@types/json-schema@7.0.15': {} - - '@types/jsonfile@6.1.4': - dependencies: - '@types/node': 22.13.10 + '@types/http-errors@2.0.5': {} - '@types/jsonwebtoken@9.0.9': + '@types/http-proxy@1.17.17': dependencies: - '@types/ms': 2.1.0 - '@types/node': 22.13.10 + '@types/node': 25.5.0 - '@types/lodash@4.17.16': {} - - '@types/long@4.0.2': - optional: true + '@types/jsesc@2.5.1': {} - '@types/mdast@3.0.15': - dependencies: - '@types/unist': 2.0.11 + '@types/lodash@4.17.24': {} '@types/mdast@4.0.4': dependencies: '@types/unist': 3.0.3 - '@types/mime@1.3.5': {} - - '@types/minimatch@5.1.2': {} + '@types/minimatch@6.0.0': + dependencies: + minimatch: 10.2.4 '@types/mkdirp@0.5.2': dependencies: - '@types/node': 8.10.66 + '@types/node': 25.5.0 '@types/ms@2.1.0': {} - '@types/node-fetch@2.6.12': + '@types/node-fetch@2.6.13': dependencies: - '@types/node': 22.13.10 - form-data: 4.0.2 + '@types/node': 25.5.0 + form-data: 4.0.5 - '@types/node-forge@1.3.11': + '@types/node-forge@1.3.14': dependencies: - '@types/node': 22.13.10 + '@types/node': 25.5.0 - '@types/node@22.13.10': + '@types/node@24.12.0': dependencies: - undici-types: 6.20.0 + undici-types: 7.16.0 - '@types/node@8.10.66': {} + '@types/node@25.5.0': + dependencies: + undici-types: 7.18.2 - '@types/normalize-package-data@2.4.4': {} + '@types/node@8.10.66': {} - '@types/qs@6.9.18': {} + '@types/qs@6.15.0': {} '@types/range-parser@1.2.7': {} - '@types/readdir-glob@1.1.5': + '@types/react-dom@19.2.3(@types/react@19.2.14)': dependencies: - '@types/node': 22.13.10 + '@types/react': 19.2.14 - '@types/request@2.48.12': + '@types/react@19.2.14': dependencies: - '@types/caseless': 0.12.5 - '@types/node': 22.13.10 - '@types/tough-cookie': 4.0.5 - form-data: 2.5.3 - optional: true + csstype: 3.2.3 '@types/resolve@1.20.2': {} '@types/rimraf@2.0.5': dependencies: '@types/glob': 5.0.38 - '@types/node': 8.10.66 + '@types/node': 25.5.0 - '@types/semver@7.5.8': {} + '@types/semver@7.7.1': {} - '@types/send@0.17.4': + '@types/send@1.2.1': dependencies: - '@types/mime': 1.3.5 - '@types/node': 22.13.10 + '@types/node': 25.5.0 - '@types/serve-static@1.15.7': + '@types/serve-static@2.2.0': dependencies: - '@types/http-errors': 2.0.4 - '@types/node': 22.13.10 - '@types/send': 0.17.4 + '@types/http-errors': 2.0.5 + '@types/node': 25.5.0 '@types/tmp@0.0.33': {} - '@types/tough-cookie@4.0.5': - optional: true - - '@types/unist@2.0.11': {} - '@types/unist@3.0.3': {} '@types/web-bluetooth@0.0.20': {} + '@types/web-bluetooth@0.0.21': {} + '@types/xml2js@0.4.14': dependencies: - '@types/node': 22.13.10 - - '@typescript-eslint/eslint-plugin@8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)': - dependencies: - '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) - '@typescript-eslint/scope-manager': 8.26.0 - '@typescript-eslint/type-utils': 8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) - '@typescript-eslint/utils': 8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) - '@typescript-eslint/visitor-keys': 8.26.0 - eslint: 9.22.0(jiti@2.4.2) - graphemer: 1.4.0 - ignore: 5.3.2 - natural-compare: 1.4.0 - ts-api-utils: 2.0.1(typescript@5.8.2) - typescript: 5.8.2 - transitivePeerDependencies: - - supports-color + '@types/node': 25.5.0 - '@typescript-eslint/parser@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)': - dependencies: - '@typescript-eslint/scope-manager': 8.26.0 - '@typescript-eslint/types': 8.26.0 - '@typescript-eslint/typescript-estree': 8.26.0(typescript@5.8.2) - '@typescript-eslint/visitor-keys': 8.26.0 - debug: 4.4.0(supports-color@9.4.0) - eslint: 9.22.0(jiti@2.4.2) - typescript: 5.8.2 - transitivePeerDependencies: - - supports-color + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260314.1': + optional: true - '@typescript-eslint/scope-manager@8.26.0': - dependencies: - '@typescript-eslint/types': 8.26.0 - '@typescript-eslint/visitor-keys': 8.26.0 + '@typescript/native-preview-darwin-x64@7.0.0-dev.20260314.1': + optional: true - '@typescript-eslint/type-utils@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)': - dependencies: - '@typescript-eslint/typescript-estree': 8.26.0(typescript@5.8.2) - '@typescript-eslint/utils': 8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) - debug: 4.4.0(supports-color@9.4.0) - eslint: 9.22.0(jiti@2.4.2) - ts-api-utils: 2.0.1(typescript@5.8.2) - typescript: 5.8.2 - transitivePeerDependencies: - - supports-color + '@typescript/native-preview-linux-arm64@7.0.0-dev.20260314.1': + optional: true - '@typescript-eslint/types@8.26.0': {} + '@typescript/native-preview-linux-arm@7.0.0-dev.20260314.1': + optional: true - '@typescript-eslint/typescript-estree@8.26.0(typescript@5.8.2)': - dependencies: - '@typescript-eslint/types': 8.26.0 - '@typescript-eslint/visitor-keys': 8.26.0 - debug: 4.4.0(supports-color@9.4.0) - fast-glob: 3.3.3 - is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.7.1 - ts-api-utils: 2.0.1(typescript@5.8.2) - typescript: 5.8.2 - transitivePeerDependencies: - - supports-color + '@typescript/native-preview-linux-x64@7.0.0-dev.20260314.1': + optional: true + + '@typescript/native-preview-win32-arm64@7.0.0-dev.20260314.1': + optional: true + + '@typescript/native-preview-win32-x64@7.0.0-dev.20260314.1': + optional: true + + '@typescript/native-preview@7.0.0-dev.20260314.1': + optionalDependencies: + '@typescript/native-preview-darwin-arm64': 7.0.0-dev.20260314.1 + '@typescript/native-preview-darwin-x64': 7.0.0-dev.20260314.1 + '@typescript/native-preview-linux-arm': 7.0.0-dev.20260314.1 + '@typescript/native-preview-linux-arm64': 7.0.0-dev.20260314.1 + '@typescript/native-preview-linux-x64': 7.0.0-dev.20260314.1 + '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260314.1 + '@typescript/native-preview-win32-x64': 7.0.0-dev.20260314.1 - '@typescript-eslint/utils@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)': + '@typespec/ts-http-runtime@0.3.4': dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.22.0(jiti@2.4.2)) - '@typescript-eslint/scope-manager': 8.26.0 - '@typescript-eslint/types': 8.26.0 - '@typescript-eslint/typescript-estree': 8.26.0(typescript@5.8.2) - eslint: 9.22.0(jiti@2.4.2) - typescript: 5.8.2 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + tslib: 2.8.1 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.26.0': - dependencies: - '@typescript-eslint/types': 8.26.0 - eslint-visitor-keys: 4.2.0 - '@ungap/structured-clone@1.3.0': {} - '@unhead/dom@1.11.20': + '@unhead/vue@2.1.12(vue@3.5.30(typescript@5.9.3))': dependencies: - '@unhead/schema': 1.11.20 - '@unhead/shared': 1.11.20 + hookable: 6.0.1 + unhead: 2.1.12 + vue: 3.5.30(typescript@5.9.3) - '@unhead/schema@1.11.20': - dependencies: - hookable: 5.5.3 - zhead: 2.2.4 + '@vercel/oidc@3.1.0': {} - '@unhead/shared@1.11.20': + '@vitejs/plugin-react@5.2.0(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: - '@unhead/schema': 1.11.20 - packrup: 0.1.2 + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) + '@rolldown/pluginutils': 1.0.0-rc.3 + '@types/babel__core': 7.20.5 + react-refresh: 0.18.0 + vite: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + transitivePeerDependencies: + - supports-color - '@unhead/vue@1.11.20(vue@3.5.13(typescript@5.8.2))': + '@vitejs/plugin-rsc@0.5.21(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: - '@unhead/schema': 1.11.20 - '@unhead/shared': 1.11.20 - hookable: 5.5.3 - unhead: 1.11.20 - vue: 3.5.13(typescript@5.8.2) + '@rolldown/pluginutils': 1.0.0-rc.5 + es-module-lexer: 2.0.0 + estree-walker: 3.0.3 + magic-string: 0.30.21 + periscopic: 4.0.2 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + srvx: 0.11.9 + strip-literal: 3.1.0 + turbo-stream: 3.2.0 + vite: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + vitefu: 1.1.2(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) - '@vercel/nft@0.29.2(rollup@4.35.0)': + '@vitejs/plugin-vue@6.0.5(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.30(typescript@5.9.3))': dependencies: - '@mapbox/node-pre-gyp': 2.0.0 - '@rollup/pluginutils': 5.1.4(rollup@4.35.0) - acorn: 8.14.1 - acorn-import-attributes: 1.9.5(acorn@8.14.1) - async-sema: 3.1.1 - bindings: 1.5.0 - estree-walker: 2.0.2 - glob: 10.4.5 - graceful-fs: 4.2.11 - node-gyp-build: 4.8.4 - picomatch: 4.0.2 - resolve-from: 5.0.0 - transitivePeerDependencies: - - encoding - - rollup - - supports-color + '@rolldown/pluginutils': 1.0.0-rc.2 + vite: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + vue: 3.5.30(typescript@5.9.3) - '@vitest/coverage-v8@3.0.8(vitest@3.0.8(@edge-runtime/vm@5.0.0)(@types/debug@4.1.12)(@types/node@22.13.10)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.0))': + '@vitest/coverage-v8@4.1.0(vitest@4.1.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@25.5.0)(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)))': dependencies: - '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 1.0.2 - debug: 4.4.0(supports-color@9.4.0) + '@vitest/utils': 4.1.0 + ast-v8-to-istanbul: 1.0.0 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 5.0.6 - istanbul-reports: 3.1.7 - magic-string: 0.30.17 - magicast: 0.3.5 - std-env: 3.8.1 - test-exclude: 7.0.1 - tinyrainbow: 2.0.0 - vitest: 3.0.8(@edge-runtime/vm@5.0.0)(@types/debug@4.1.12)(@types/node@22.13.10)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.0) - transitivePeerDependencies: - - supports-color + istanbul-reports: 3.2.0 + magicast: 0.5.2 + obug: 2.1.1 + std-env: 4.0.0 + tinyrainbow: 3.1.0 + vitest: 4.1.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@25.5.0)(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) - '@vitest/expect@3.0.8': + '@vitest/expect@4.1.0': dependencies: - '@vitest/spy': 3.0.8 - '@vitest/utils': 3.0.8 - chai: 5.2.0 - tinyrainbow: 2.0.0 + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.1.0 + '@vitest/utils': 4.1.0 + chai: 6.2.2 + tinyrainbow: 3.1.0 - '@vitest/mocker@3.0.8(vite@6.2.1(@types/node@22.13.10)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.0))': + '@vitest/mocker@4.1.0(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: - '@vitest/spy': 3.0.8 + '@vitest/spy': 4.1.0 estree-walker: 3.0.3 - magic-string: 0.30.17 + magic-string: 0.30.21 optionalDependencies: - vite: 6.2.1(@types/node@22.13.10)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.0) + vite: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) - '@vitest/pretty-format@3.0.8': + '@vitest/pretty-format@4.1.0': dependencies: - tinyrainbow: 2.0.0 + tinyrainbow: 3.1.0 - '@vitest/runner@3.0.8': + '@vitest/runner@4.1.0': dependencies: - '@vitest/utils': 3.0.8 + '@vitest/utils': 4.1.0 pathe: 2.0.3 - '@vitest/snapshot@3.0.8': + '@vitest/snapshot@4.1.0': dependencies: - '@vitest/pretty-format': 3.0.8 - magic-string: 0.30.17 + '@vitest/pretty-format': 4.1.0 + '@vitest/utils': 4.1.0 + magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@3.0.8': - dependencies: - tinyspy: 3.0.2 + '@vitest/spy@4.1.0': {} - '@vitest/utils@3.0.8': + '@vitest/utils@4.1.0': dependencies: - '@vitest/pretty-format': 3.0.8 - loupe: 3.1.3 - tinyrainbow: 2.0.0 + '@vitest/pretty-format': 4.1.0 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.0 - '@vue/compiler-core@3.5.13': + '@vue/compiler-core@3.5.30': dependencies: - '@babel/parser': 7.26.9 - '@vue/shared': 3.5.13 - entities: 4.5.0 + '@babel/parser': 7.29.0 + '@vue/shared': 3.5.30 + entities: 7.0.1 estree-walker: 2.0.2 source-map-js: 1.2.1 - '@vue/compiler-dom@3.5.13': + '@vue/compiler-dom@3.5.30': dependencies: - '@vue/compiler-core': 3.5.13 - '@vue/shared': 3.5.13 + '@vue/compiler-core': 3.5.30 + '@vue/shared': 3.5.30 - '@vue/compiler-sfc@3.5.13': + '@vue/compiler-sfc@3.5.30': dependencies: - '@babel/parser': 7.26.9 - '@vue/compiler-core': 3.5.13 - '@vue/compiler-dom': 3.5.13 - '@vue/compiler-ssr': 3.5.13 - '@vue/shared': 3.5.13 + '@babel/parser': 7.29.0 + '@vue/compiler-core': 3.5.30 + '@vue/compiler-dom': 3.5.30 + '@vue/compiler-ssr': 3.5.30 + '@vue/shared': 3.5.30 estree-walker: 2.0.2 - magic-string: 0.30.17 - postcss: 8.5.3 + magic-string: 0.30.21 + postcss: 8.5.8 source-map-js: 1.2.1 - '@vue/compiler-ssr@3.5.13': + '@vue/compiler-ssr@3.5.30': dependencies: - '@vue/compiler-dom': 3.5.13 - '@vue/shared': 3.5.13 + '@vue/compiler-dom': 3.5.30 + '@vue/shared': 3.5.30 '@vue/devtools-api@6.6.4': {} - '@vue/reactivity@3.5.13': + '@vue/reactivity@3.5.30': dependencies: - '@vue/shared': 3.5.13 + '@vue/shared': 3.5.30 - '@vue/runtime-core@3.5.13': + '@vue/runtime-core@3.5.30': dependencies: - '@vue/reactivity': 3.5.13 - '@vue/shared': 3.5.13 + '@vue/reactivity': 3.5.30 + '@vue/shared': 3.5.30 - '@vue/runtime-dom@3.5.13': + '@vue/runtime-dom@3.5.30': dependencies: - '@vue/reactivity': 3.5.13 - '@vue/runtime-core': 3.5.13 - '@vue/shared': 3.5.13 - csstype: 3.1.3 + '@vue/reactivity': 3.5.30 + '@vue/runtime-core': 3.5.30 + '@vue/shared': 3.5.30 + csstype: 3.2.3 - '@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.8.2))': + '@vue/server-renderer@3.5.30(vue@3.5.30(typescript@5.9.3))': dependencies: - '@vue/compiler-ssr': 3.5.13 - '@vue/shared': 3.5.13 - vue: 3.5.13(typescript@5.8.2) + '@vue/compiler-ssr': 3.5.30 + '@vue/shared': 3.5.30 + vue: 3.5.30(typescript@5.9.3) - '@vue/shared@3.5.13': {} + '@vue/shared@3.5.30': {} - '@vueuse/core@10.11.1(vue@3.5.13(typescript@5.8.2))': + '@vueuse/core@10.11.1(vue@3.5.30(typescript@5.9.3))': dependencies: '@types/web-bluetooth': 0.0.20 '@vueuse/metadata': 10.11.1 - '@vueuse/shared': 10.11.1(vue@3.5.13(typescript@5.8.2)) - vue-demi: 0.14.10(vue@3.5.13(typescript@5.8.2)) + '@vueuse/shared': 10.11.1(vue@3.5.30(typescript@5.9.3)) + vue-demi: 0.14.10(vue@3.5.30(typescript@5.9.3)) transitivePeerDependencies: - '@vue/composition-api' - vue - '@vueuse/core@11.3.0(vue@3.5.13(typescript@5.8.2))': + '@vueuse/core@13.9.0(vue@3.5.30(typescript@5.9.3))': dependencies: - '@types/web-bluetooth': 0.0.20 - '@vueuse/metadata': 11.3.0 - '@vueuse/shared': 11.3.0(vue@3.5.13(typescript@5.8.2)) - vue-demi: 0.14.10(vue@3.5.13(typescript@5.8.2)) - transitivePeerDependencies: - - '@vue/composition-api' - - vue + '@types/web-bluetooth': 0.0.21 + '@vueuse/metadata': 13.9.0 + '@vueuse/shared': 13.9.0(vue@3.5.30(typescript@5.9.3)) + vue: 3.5.30(typescript@5.9.3) - '@vueuse/integrations@11.3.0(axios@1.8.2)(change-case@5.4.4)(focus-trap@7.6.4)(fuse.js@7.1.0)(jwt-decode@4.0.0)(vue@3.5.13(typescript@5.8.2))': + '@vueuse/integrations@13.9.0(axios@1.13.6(debug@4.4.3))(focus-trap@7.8.0)(fuse.js@7.1.0)(jwt-decode@4.0.0)(vue@3.5.30(typescript@5.9.3))': dependencies: - '@vueuse/core': 11.3.0(vue@3.5.13(typescript@5.8.2)) - '@vueuse/shared': 11.3.0(vue@3.5.13(typescript@5.8.2)) - vue-demi: 0.14.10(vue@3.5.13(typescript@5.8.2)) + '@vueuse/core': 13.9.0(vue@3.5.30(typescript@5.9.3)) + '@vueuse/shared': 13.9.0(vue@3.5.30(typescript@5.9.3)) + vue: 3.5.30(typescript@5.9.3) optionalDependencies: - axios: 1.8.2 - change-case: 5.4.4 - focus-trap: 7.6.4 + axios: 1.13.6(debug@4.4.3) + focus-trap: 7.8.0 fuse.js: 7.1.0 jwt-decode: 4.0.0 - transitivePeerDependencies: - - '@vue/composition-api' - - vue '@vueuse/metadata@10.11.1': {} - '@vueuse/metadata@11.3.0': {} - - '@vueuse/shared@10.11.1(vue@3.5.13(typescript@5.8.2))': - dependencies: - vue-demi: 0.14.10(vue@3.5.13(typescript@5.8.2)) - transitivePeerDependencies: - - '@vue/composition-api' - - vue + '@vueuse/metadata@13.9.0': {} - '@vueuse/shared@11.3.0(vue@3.5.13(typescript@5.8.2))': + '@vueuse/shared@10.11.1(vue@3.5.30(typescript@5.9.3))': dependencies: - vue-demi: 0.14.10(vue@3.5.13(typescript@5.8.2)) + vue-demi: 0.14.10(vue@3.5.30(typescript@5.9.3)) transitivePeerDependencies: - '@vue/composition-api' - vue - abbrev@3.0.0: {} - - abort-controller@3.0.0: + '@vueuse/shared@13.9.0(vue@3.5.30(typescript@5.9.3))': dependencies: - event-target-shim: 5.0.1 + vue: 3.5.30(typescript@5.9.3) - accepts@1.3.8: - dependencies: - mime-types: 2.1.35 - negotiator: 0.6.3 - - acorn-import-attributes@1.9.5(acorn@8.14.1): - dependencies: - acorn: 8.14.1 + abstract-logging@2.0.1: {} - acorn-jsx@5.3.2(acorn@8.14.1): + accepts@2.0.0: dependencies: - acorn: 8.14.1 + mime-types: 3.0.2 + negotiator: 1.0.0 - acorn-walk@8.3.2: {} - - acorn@8.14.0: {} - - acorn@8.14.1: {} + acorn@8.16.0: {} adm-zip@0.5.16: {} - agent-base@6.0.2: - dependencies: - debug: 4.4.0(supports-color@9.4.0) - transitivePeerDependencies: - - supports-color - optional: true + agent-base@7.1.4: {} - agent-base@7.1.3: {} + ai@6.0.33(zod@4.3.6): + dependencies: + '@ai-sdk/gateway': 3.0.13(zod@4.3.6) + '@ai-sdk/provider': 3.0.2 + '@ai-sdk/provider-utils': 4.0.5(zod@4.3.6) + '@opentelemetry/api': 1.9.0 + zod: 4.3.6 - ajv-draft-04@1.0.0(ajv@8.17.1): + ajv-draft-04@1.0.0(ajv@8.18.0): optionalDependencies: - ajv: 8.17.1 + ajv: 8.18.0 - ajv-formats@3.0.1(ajv@8.17.1): + ajv-formats@3.0.1(ajv@8.18.0): optionalDependencies: - ajv: 8.17.1 + ajv: 8.18.0 - ajv@6.12.6: + ajv@8.18.0: dependencies: fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - - ajv@8.17.1: - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.0.6 + fast-uri: 3.1.0 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -7894,21 +9581,21 @@ snapshots: dependencies: string-width: 4.2.3 - ansi-colors@4.1.3: {} - ansi-escapes@4.3.2: dependencies: type-fest: 0.21.3 ansi-regex@5.0.1: {} - ansi-regex@6.1.0: {} + ansi-regex@6.2.2: {} ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 - ansi-styles@6.2.1: {} + ansi-styles@6.2.3: {} + + ansis@4.2.0: {} anymatch@3.1.3: dependencies: @@ -7917,118 +9604,125 @@ snapshots: application-config-path@0.1.1: {} - archiver-utils@5.0.2: - dependencies: - glob: 10.4.5 - graceful-fs: 4.2.11 - is-stream: 2.0.1 - lazystream: 1.0.1 - lodash: 4.17.21 - normalize-path: 3.0.0 - readable-stream: 4.7.0 - - archiver@7.0.1: - dependencies: - archiver-utils: 5.0.2 - async: 3.2.6 - buffer-crc32: 1.0.0 - readable-stream: 4.7.0 - readdir-glob: 1.1.3 - tar-stream: 3.1.7 - zip-stream: 6.0.1 - argparse@2.0.1: {} - aria-hidden@1.2.4: + aria-hidden@1.2.6: dependencies: tslib: 2.8.1 - array-flatten@1.1.1: {} - - arrify@2.0.1: - optional: true - - as-table@1.0.55: - dependencies: - printable-characters: 1.0.42 + array-find-index@1.0.2: {} assertion-error@2.0.1: {} - async-listen@3.0.1: {} + ast-kit@3.0.0-beta.1: + dependencies: + '@babel/parser': 8.0.0-rc.2 + estree-walker: 3.0.3 + pathe: 2.0.3 - async-retry@1.3.3: + ast-types@0.16.1: dependencies: - retry: 0.13.1 - optional: true + tslib: 2.8.1 - async-sema@3.1.1: {} + ast-v8-to-istanbul@1.0.0: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + estree-walker: 3.0.3 + js-tokens: 10.0.0 - async@3.2.6: {} + async-listen@3.0.1: {} asynckit@0.4.0: {} - atomically@2.0.3: + atomic-sleep@1.0.0: {} + + atomically@2.1.1: dependencies: - stubborn-fs: 1.2.5 - when-exit: 2.1.4 + stubborn-fs: 2.0.0 + when-exit: 2.1.5 - automd@0.4.0(magicast@0.3.5): + automd@0.4.3(magicast@0.5.2): dependencies: - '@parcel/watcher': 2.5.1 - c12: 3.0.2(magicast@0.3.5) - citty: 0.1.6 - consola: 3.4.0 + '@parcel/watcher': 2.5.6 + c12: 3.3.3(magicast@0.5.2) + citty: 0.2.1 + consola: 3.4.2 defu: 6.1.4 - destr: 2.0.3 + destr: 2.0.5 didyoumean2: 7.0.4 - magic-string: 0.30.17 + magic-string: 0.30.21 mdbox: 0.1.1 - mlly: 1.7.4 - ofetch: 1.4.1 + mlly: 1.8.1 + ofetch: 1.5.1 pathe: 2.0.3 - perfect-debounce: 1.0.0 - pkg-types: 2.1.0 + perfect-debounce: 2.1.0 + pkg-types: 2.3.0 scule: 1.3.0 - tinyglobby: 0.2.12 + tinyglobby: 0.2.15 untyped: 2.0.0 transitivePeerDependencies: - magicast - autoprefixer@10.4.20(postcss@8.5.3): + avvio@9.2.0: dependencies: - browserslist: 4.24.4 - caniuse-lite: 1.0.30001702 - fraction.js: 4.3.7 - normalize-range: 0.1.2 - picocolors: 1.1.1 - postcss: 8.5.3 - postcss-value-parser: 4.2.0 + '@fastify/error': 4.2.0 + fastq: 1.20.1 - axios@1.8.2: + axios-retry@4.5.0(axios@1.13.6(debug@4.4.3)): dependencies: - follow-redirects: 1.15.9 - form-data: 4.0.2 + axios: 1.13.6(debug@4.4.3) + is-retry-allowed: 2.2.0 + + axios@1.13.6(debug@4.4.3): + dependencies: + follow-redirects: 1.15.11(debug@4.4.3) + form-data: 4.0.5 proxy-from-env: 1.1.0 transitivePeerDependencies: - debug - b4a@1.6.7: {} + babel-dead-code-elimination@1.0.12: + dependencies: + '@babel/core': 7.29.0 + '@babel/parser': 7.29.0 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-jsx-dom-expressions@0.40.5(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.18.6 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/types': 7.29.0 + html-entities: 2.3.3 + parse5: 7.3.0 + + babel-plugin-transform-hook-names@1.0.2(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + + babel-preset-solid@1.9.10(@babel/core@7.29.0)(solid-js@1.9.11): + dependencies: + '@babel/core': 7.29.0 + babel-plugin-jsx-dom-expressions: 0.40.5(@babel/core@7.29.0) + optionalDependencies: + solid-js: 1.9.11 bail@2.0.2: {} balanced-match@1.0.2: {} - bare-events@2.5.4: - optional: true + balanced-match@4.0.4: {} base64-js@1.5.1: {} - bignumber.js@9.1.2: - optional: true + baseline-browser-mapping@2.10.8: {} - bindings@1.5.0: - dependencies: - file-uri-to-path: 1.0.0 + binary-extensions@2.3.0: {} + + birpc@4.0.0: {} bl@4.1.0: dependencies: @@ -8036,20 +9730,19 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 - body-parser@1.20.3: + blake3-wasm@2.1.5: {} + + body-parser@2.2.2: dependencies: bytes: 3.1.2 content-type: 1.0.5 - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - http-errors: 2.0.0 - iconv-lite: 0.4.24 + debug: 4.4.3 + http-errors: 2.0.1 + iconv-lite: 0.7.2 on-finished: 2.4.1 - qs: 6.13.0 - raw-body: 2.5.2 - type-is: 1.6.18 - unpipe: 1.0.0 + qs: 6.15.0 + raw-body: 3.0.2 + type-is: 2.0.1 transitivePeerDependencies: - supports-color @@ -8059,75 +9752,84 @@ snapshots: dependencies: ansi-align: 3.0.1 camelcase: 8.0.0 - chalk: 5.4.1 + chalk: 5.6.2 cli-boxes: 3.0.0 string-width: 7.2.0 - type-fest: 4.37.0 + type-fest: 4.41.0 widest-line: 5.0.0 - wrap-ansi: 9.0.0 + wrap-ansi: 9.0.2 - brace-expansion@1.1.11: + brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@2.0.1: + brace-expansion@2.0.2: dependencies: balanced-match: 1.0.2 + brace-expansion@5.0.4: + dependencies: + balanced-match: 4.0.4 + braces@3.0.3: dependencies: fill-range: 7.1.1 - browserslist@4.24.4: + browserslist@4.28.1: dependencies: - caniuse-lite: 1.0.30001702 - electron-to-chromium: 1.5.113 - node-releases: 2.0.19 - update-browserslist-db: 1.1.3(browserslist@4.24.4) - - buffer-crc32@1.0.0: {} + baseline-browser-mapping: 2.10.8 + caniuse-lite: 1.0.30001778 + electron-to-chromium: 1.5.313 + node-releases: 2.0.36 + update-browserslist-db: 1.2.3(browserslist@4.28.1) buffer-equal-constant-time@1.0.1: {} - buffer-from@1.1.2: {} - buffer@5.7.1: dependencies: base64-js: 1.5.1 ieee754: 1.2.1 - buffer@6.0.3: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - - builtin-modules@3.3.0: {} - bundle-name@4.1.0: dependencies: - run-applescript: 7.0.0 + run-applescript: 7.1.0 bytes@3.1.2: {} - c12@3.0.2(magicast@0.3.5): + c12@3.3.3(magicast@0.5.2): dependencies: - chokidar: 4.0.3 - confbox: 0.1.8 + chokidar: 5.0.0 + confbox: 0.2.4 defu: 6.1.4 - dotenv: 16.4.7 - exsolve: 1.0.4 + dotenv: 17.3.1 + exsolve: 1.0.8 giget: 2.0.0 - jiti: 2.4.2 + jiti: 2.6.1 ohash: 2.0.11 pathe: 2.0.3 - perfect-debounce: 1.0.0 - pkg-types: 2.1.0 + perfect-debounce: 2.1.0 + pkg-types: 2.3.0 rc9: 2.1.2 optionalDependencies: - magicast: 0.3.5 + magicast: 0.5.2 + + c12@4.0.0-beta.3(chokidar@5.0.0)(dotenv@17.3.1)(giget@3.1.2)(jiti@2.6.1)(magicast@0.5.2): + dependencies: + confbox: 0.2.4 + defu: 6.1.4 + exsolve: 1.0.8 + pathe: 2.0.3 + pkg-types: 2.3.0 + rc9: 3.0.0 + optionalDependencies: + chokidar: 5.0.0 + dotenv: 17.3.1 + giget: 3.1.2 + jiti: 2.6.1 + magicast: 0.5.2 - cac@6.7.14: {} + cac@7.0.0: {} call-bind-apply-helpers@1.0.2: dependencies: @@ -8139,89 +9841,95 @@ snapshots: call-bind-apply-helpers: 1.0.2 get-intrinsic: 1.3.0 - callsites@3.1.0: {} - camelcase@8.0.0: {} - caniuse-api@3.0.0: - dependencies: - browserslist: 4.24.4 - caniuse-lite: 1.0.30001702 - lodash.memoize: 4.1.2 - lodash.uniq: 4.5.0 - - caniuse-lite@1.0.30001702: {} + caniuse-lite@1.0.30001778: {} ccount@2.0.1: {} - chai@5.2.0: - dependencies: - assertion-error: 2.0.1 - check-error: 2.1.1 - deep-eql: 5.0.2 - loupe: 3.1.3 - pathval: 2.0.0 + chai@6.2.2: {} chalk@4.1.2: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 - chalk@5.4.1: {} - - change-case@5.4.4: {} + chalk@5.6.2: {} - changelogen@0.6.1(magicast@0.3.5): + changelogen@0.6.2(magicast@0.5.2): dependencies: - c12: 3.0.2(magicast@0.3.5) - confbox: 0.2.1 - consola: 3.4.0 + c12: 3.3.3(magicast@0.5.2) + confbox: 0.2.4 + consola: 3.4.2 convert-gitmoji: 0.1.5 mri: 1.2.0 - node-fetch-native: 1.6.6 - ofetch: 1.4.1 - open: 10.1.0 + node-fetch-native: 1.6.7 + ofetch: 1.5.1 + open: 10.2.0 pathe: 2.0.3 - pkg-types: 2.1.0 + pkg-types: 2.3.0 scule: 1.3.0 - semver: 7.7.1 - std-env: 3.8.1 + semver: 7.7.4 + std-env: 3.10.0 transitivePeerDependencies: - magicast character-entities-html4@2.1.0: {} - character-entities-legacy@1.1.4: {} - character-entities-legacy@3.0.0: {} - character-entities@1.2.4: {} - character-entities@2.0.2: {} - character-reference-invalid@1.1.4: {} - charenc@0.0.2: {} - check-error@2.1.1: {} + cheerio-select@2.1.0: + dependencies: + boolbase: 1.0.0 + css-select: 5.2.2 + css-what: 6.2.2 + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 - chokidar@4.0.3: + cheerio@1.2.0: dependencies: - readdirp: 4.1.2 + cheerio-select: 2.1.0 + dom-serializer: 2.0.0 + domhandler: 5.0.3 + domutils: 3.2.2 + encoding-sniffer: 0.2.1 + htmlparser2: 10.1.0 + parse5: 7.3.0 + parse5-htmlparser2-tree-adapter: 7.1.0 + parse5-parser-stream: 7.1.2 + undici: 7.24.3 + whatwg-mimetype: 4.0.0 - chownr@1.1.4: {} + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + chokidar@5.0.0: + dependencies: + readdirp: 5.0.0 - chownr@3.0.0: {} + chownr@1.1.4: {} - ci-info@4.1.0: {} + ci-info@4.4.0: {} citty@0.1.6: dependencies: - consola: 3.4.0 + consola: 3.4.2 - clean-regexp@1.0.0: - dependencies: - escape-string-regexp: 1.0.5 + citty@0.2.1: {} cli-boxes@3.0.0: {} @@ -8235,12 +9943,6 @@ snapshots: cli-spinners@2.9.2: {} - clipboardy@4.0.0: - dependencies: - execa: 8.0.1 - is-wsl: 3.1.0 - is64bit: 2.0.0 - cliui@8.0.1: dependencies: string-width: 4.2.3 @@ -8251,28 +9953,12 @@ snapshots: clsx@2.1.1: {} - cluster-key-slot@1.1.2: {} - - codemirror@6.0.1: - dependencies: - '@codemirror/autocomplete': 6.18.6 - '@codemirror/commands': 6.8.0 - '@codemirror/language': 6.10.8 - '@codemirror/lint': 6.8.4 - '@codemirror/search': 6.5.10 - '@codemirror/state': 6.5.2 - '@codemirror/view': 6.36.4 - color-convert@2.0.1: dependencies: color-name: 1.1.4 color-name@1.1.4: {} - colord@2.9.3: {} - - colorette@1.4.0: {} - combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 @@ -8283,21 +9969,13 @@ snapshots: commander@2.20.3: {} - commander@7.2.0: {} - commander@9.5.0: {} - commondir@1.0.1: {} + commenting@1.1.0: {} - compatx@0.1.8: {} + commondir@1.0.1: {} - compress-commons@6.0.2: - dependencies: - crc-32: 1.2.2 - crc32-stream: 6.0.0 - is-stream: 2.0.1 - normalize-path: 3.0.0 - readable-stream: 4.7.0 + compatx@0.2.0: {} concat-map@0.0.1: {} @@ -8305,9 +9983,9 @@ snapshots: dependencies: chalk: 4.1.2 date-fns: 2.30.0 - lodash: 4.17.21 + lodash: 4.17.23 rxjs: 7.8.2 - shell-quote: 1.8.2 + shell-quote: 1.8.3 spawn-command: 0.0.2 supports-color: 8.1.1 tree-kill: 1.2.2 @@ -8315,25 +9993,23 @@ snapshots: confbox@0.1.8: {} - confbox@0.2.1: {} + confbox@0.2.4: {} config-chain@1.1.13: dependencies: ini: 1.3.8 proto-list: 1.2.4 - configstore@7.0.0: + configstore@7.1.0: dependencies: - atomically: 2.0.3 + atomically: 2.1.1 dot-prop: 9.0.0 graceful-fs: 4.2.11 xdg-basedir: 5.1.0 - consola@3.4.0: {} + consola@3.4.2: {} - content-disposition@0.5.4: - dependencies: - safe-buffer: 5.2.1 + content-disposition@1.0.1: {} content-type@1.0.5: {} @@ -8341,39 +10017,23 @@ snapshots: convert-hrtime@3.0.0: {} - cookie-es@1.2.2: {} - - cookie-es@2.0.0: {} - - cookie-signature@1.0.6: {} - - cookie@0.5.0: {} - - cookie@0.7.1: {} + convert-hrtime@5.0.0: {} - cookie@1.0.2: {} + convert-source-map@2.0.0: {} - core-js-compat@3.41.0: - dependencies: - browserslist: 4.24.4 + cookie-es@2.0.0: {} - core-util-is@1.0.3: {} + cookie-signature@1.2.2: {} - cors@2.8.5: - dependencies: - object-assign: 4.1.1 - vary: 1.1.2 + cookie@0.5.0: {} - crc-32@1.2.2: {} + cookie@0.7.2: {} - crc32-stream@6.0.0: - dependencies: - crc-32: 1.2.2 - readable-stream: 4.7.0 + cookie@1.1.1: {} crelt@1.0.6: {} - croner@9.0.0: {} + croner@10.0.1: {} cross-spawn@7.0.6: dependencies: @@ -8381,101 +10041,41 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - crossws@0.3.4: - dependencies: - uncrypto: 0.1.3 + crossws@0.4.4(srvx@0.11.9): + optionalDependencies: + srvx: 0.11.9 crypt@0.0.2: {} - css-declaration-sorter@7.2.0(postcss@8.5.3): - dependencies: - postcss: 8.5.3 - - css-select@5.1.0: + css-select@5.2.2: dependencies: boolbase: 1.0.0 - css-what: 6.1.0 + css-what: 6.2.2 domhandler: 5.0.3 domutils: 3.2.2 nth-check: 2.1.1 - css-tree@2.2.1: - dependencies: - mdn-data: 2.0.28 - source-map-js: 1.2.1 + css-what@6.2.2: {} - css-tree@2.3.1: - dependencies: - mdn-data: 2.0.30 - source-map-js: 1.2.1 + csstype@3.2.3: {} - css-what@6.1.0: {} - - cssesc@3.0.0: {} - - cssnano-preset-default@7.0.6(postcss@8.5.3): - dependencies: - browserslist: 4.24.4 - css-declaration-sorter: 7.2.0(postcss@8.5.3) - cssnano-utils: 5.0.0(postcss@8.5.3) - postcss: 8.5.3 - postcss-calc: 10.1.1(postcss@8.5.3) - postcss-colormin: 7.0.2(postcss@8.5.3) - postcss-convert-values: 7.0.4(postcss@8.5.3) - postcss-discard-comments: 7.0.3(postcss@8.5.3) - postcss-discard-duplicates: 7.0.1(postcss@8.5.3) - postcss-discard-empty: 7.0.0(postcss@8.5.3) - postcss-discard-overridden: 7.0.0(postcss@8.5.3) - postcss-merge-longhand: 7.0.4(postcss@8.5.3) - postcss-merge-rules: 7.0.4(postcss@8.5.3) - postcss-minify-font-values: 7.0.0(postcss@8.5.3) - postcss-minify-gradients: 7.0.0(postcss@8.5.3) - postcss-minify-params: 7.0.2(postcss@8.5.3) - postcss-minify-selectors: 7.0.4(postcss@8.5.3) - postcss-normalize-charset: 7.0.0(postcss@8.5.3) - postcss-normalize-display-values: 7.0.0(postcss@8.5.3) - postcss-normalize-positions: 7.0.0(postcss@8.5.3) - postcss-normalize-repeat-style: 7.0.0(postcss@8.5.3) - postcss-normalize-string: 7.0.0(postcss@8.5.3) - postcss-normalize-timing-functions: 7.0.0(postcss@8.5.3) - postcss-normalize-unicode: 7.0.2(postcss@8.5.3) - postcss-normalize-url: 7.0.0(postcss@8.5.3) - postcss-normalize-whitespace: 7.0.0(postcss@8.5.3) - postcss-ordered-values: 7.0.1(postcss@8.5.3) - postcss-reduce-initial: 7.0.2(postcss@8.5.3) - postcss-reduce-transforms: 7.0.0(postcss@8.5.3) - postcss-svgo: 7.0.1(postcss@8.5.3) - postcss-unique-selectors: 7.0.3(postcss@8.5.3) - - cssnano-utils@5.0.0(postcss@8.5.3): - dependencies: - postcss: 8.5.3 - - cssnano@7.0.6(postcss@8.5.3): - dependencies: - cssnano-preset-default: 7.0.6(postcss@8.5.3) - lilconfig: 3.1.3 - postcss: 8.5.3 - - csso@5.0.5: - dependencies: - css-tree: 2.2.1 - - csstype@3.1.3: {} - - cva@1.0.0-beta.2(typescript@5.8.2): + cva@1.0.0-beta.2(typescript@5.9.3): dependencies: clsx: 2.1.1 optionalDependencies: - typescript: 5.8.2 + typescript: 5.9.3 - data-uri-to-buffer@2.0.2: {} + cva@1.0.0-beta.4(typescript@5.9.3): + dependencies: + clsx: 2.1.1 + optionalDependencies: + typescript: 5.9.3 date-fns@2.30.0: dependencies: - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.28.6 - db0@0.3.1: {} + db0@0.3.4: {} debug@2.6.9: dependencies: @@ -8485,13 +10085,11 @@ snapshots: dependencies: ms: 2.1.3 - debug@4.4.0(supports-color@9.4.0): + debug@4.4.3: dependencies: ms: 2.1.3 - optionalDependencies: - supports-color: 9.4.0 - decode-named-character-reference@1.1.0: + decode-named-character-reference@1.3.0: dependencies: character-entities: 2.0.2 @@ -8499,20 +10097,16 @@ snapshots: dependencies: mimic-response: 3.1.0 - deep-eql@5.0.2: {} - deep-extend@0.6.0: {} - deep-is@0.1.4: {} - deepmerge@4.3.1: {} - default-browser-id@5.0.0: {} + default-browser-id@5.0.1: {} - default-browser@5.2.1: + default-browser@5.5.0: dependencies: bundle-name: 4.1.0 - default-browser-id: 5.0.0 + default-browser-id: 5.0.1 default-gateway@6.0.3: dependencies: @@ -8530,27 +10124,23 @@ snapshots: delayed-stream@1.0.0: {} - denque@2.1.0: {} - depd@2.0.0: {} dequal@2.0.3: {} - destr@2.0.3: {} + destr@2.0.5: {} destroy@1.2.0: {} - detect-libc@1.0.3: {} - - detect-libc@2.0.3: {} + detect-libc@2.1.2: {} - devcert@1.2.2: + devcert@1.2.3: dependencies: '@types/configstore': 2.1.1 '@types/debug': 0.0.30 '@types/get-port': 3.2.0 '@types/glob': 5.0.38 - '@types/lodash': 4.17.16 + '@types/lodash': 4.17.24 '@types/mkdirp': 0.5.2 '@types/node': 8.10.66 '@types/rimraf': 2.0.5 @@ -8562,7 +10152,7 @@ snapshots: get-port: 3.2.0 glob: 7.2.3 is-valid-domain: 0.1.6 - lodash: 4.17.21 + lodash: 4.17.23 mkdirp: 0.5.6 password-prompt: 1.1.3 rimraf: 2.7.1 @@ -8578,10 +10168,12 @@ snapshots: didyoumean2@7.0.4: dependencies: - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.28.6 fastest-levenshtein: 1.0.16 lodash.deburr: 4.1.0 + diff@8.0.3: {} + discontinuous-range@1.0.0: {} dom-serializer@2.0.0: @@ -8596,17 +10188,27 @@ snapshots: dependencies: domelementtype: 2.3.0 + dompurify@3.1.7: {} + domutils@3.2.2: dependencies: dom-serializer: 2.0.0 domelementtype: 2.3.0 domhandler: 5.0.3 + dot-prop@10.1.0: + dependencies: + type-fest: 5.4.4 + dot-prop@9.0.0: dependencies: - type-fest: 4.37.0 + type-fest: 4.41.0 + + dotenv@16.6.1: {} + + dotenv@17.3.1: {} - dotenv@16.4.7: {} + dts-resolver@2.1.3: {} dunder-proto@1.0.1: dependencies: @@ -8616,14 +10218,6 @@ snapshots: duplexer@0.1.2: {} - duplexify@4.1.3: - dependencies: - end-of-stream: 1.4.4 - inherits: 2.0.4 - readable-stream: 3.6.2 - stream-shift: 1.0.3 - optional: true - eastasianwidth@0.2.0: {} ebnf@1.9.1: {} @@ -8646,29 +10240,57 @@ snapshots: ee-first@1.1.1: {} - electron-to-chromium@1.5.113: {} + electron-to-chromium@1.5.313: {} + + elysia@1.4.27(@sinclair/typebox@0.34.48)(exact-mirror@0.2.7(@sinclair/typebox@0.34.48))(file-type@21.3.2)(openapi-types@12.1.3)(typescript@5.9.3): + dependencies: + '@sinclair/typebox': 0.34.48 + cookie: 1.1.1 + exact-mirror: 0.2.7(@sinclair/typebox@0.34.48) + fast-decode-uri-component: 1.0.1 + file-type: 21.3.2 + memoirist: 0.4.0 + openapi-types: 12.1.3 + optionalDependencies: + typescript: 5.9.3 - emoji-regex@10.4.0: {} + emoji-regex@10.6.0: {} emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} - encodeurl@1.0.2: {} - encodeurl@2.0.0: {} - end-of-stream@1.4.4: + encoding-sniffer@0.2.1: + dependencies: + iconv-lite: 0.6.3 + whatwg-encoding: 3.1.1 + + end-of-stream@1.4.5: dependencies: once: 1.4.0 + enhanced-resolve@5.20.0: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.0 + entities@4.5.0: {} - eol@0.9.1: {} + entities@6.0.1: {} - error-ex@1.3.2: + entities@7.0.1: {} + + env-runner@0.1.6(miniflare@4.20260312.0): dependencies: - is-arrayish: 0.2.1 + crossws: 0.4.4(srvx@0.11.9) + httpxy: 0.3.1 + srvx: 0.11.9 + optionalDependencies: + miniflare: 4.20260312.0 + + eol@0.9.1: {} error-stack-parser-es@1.0.5: {} @@ -8676,7 +10298,7 @@ snapshots: es-errors@1.3.0: {} - es-module-lexer@1.6.0: {} + es-module-lexer@2.0.0: {} es-object-atoms@1.1.1: dependencies: @@ -8691,61 +10313,63 @@ snapshots: es6-promisify@7.0.0: {} - esbuild@0.24.2: + esbuild@0.27.3: optionalDependencies: - '@esbuild/aix-ppc64': 0.24.2 - '@esbuild/android-arm': 0.24.2 - '@esbuild/android-arm64': 0.24.2 - '@esbuild/android-x64': 0.24.2 - '@esbuild/darwin-arm64': 0.24.2 - '@esbuild/darwin-x64': 0.24.2 - '@esbuild/freebsd-arm64': 0.24.2 - '@esbuild/freebsd-x64': 0.24.2 - '@esbuild/linux-arm': 0.24.2 - '@esbuild/linux-arm64': 0.24.2 - '@esbuild/linux-ia32': 0.24.2 - '@esbuild/linux-loong64': 0.24.2 - '@esbuild/linux-mips64el': 0.24.2 - '@esbuild/linux-ppc64': 0.24.2 - '@esbuild/linux-riscv64': 0.24.2 - '@esbuild/linux-s390x': 0.24.2 - '@esbuild/linux-x64': 0.24.2 - '@esbuild/netbsd-arm64': 0.24.2 - '@esbuild/netbsd-x64': 0.24.2 - '@esbuild/openbsd-arm64': 0.24.2 - '@esbuild/openbsd-x64': 0.24.2 - '@esbuild/sunos-x64': 0.24.2 - '@esbuild/win32-arm64': 0.24.2 - '@esbuild/win32-ia32': 0.24.2 - '@esbuild/win32-x64': 0.24.2 - - esbuild@0.25.0: + '@esbuild/aix-ppc64': 0.27.3 + '@esbuild/android-arm': 0.27.3 + '@esbuild/android-arm64': 0.27.3 + '@esbuild/android-x64': 0.27.3 + '@esbuild/darwin-arm64': 0.27.3 + '@esbuild/darwin-x64': 0.27.3 + '@esbuild/freebsd-arm64': 0.27.3 + '@esbuild/freebsd-x64': 0.27.3 + '@esbuild/linux-arm': 0.27.3 + '@esbuild/linux-arm64': 0.27.3 + '@esbuild/linux-ia32': 0.27.3 + '@esbuild/linux-loong64': 0.27.3 + '@esbuild/linux-mips64el': 0.27.3 + '@esbuild/linux-ppc64': 0.27.3 + '@esbuild/linux-riscv64': 0.27.3 + '@esbuild/linux-s390x': 0.27.3 + '@esbuild/linux-x64': 0.27.3 + '@esbuild/netbsd-arm64': 0.27.3 + '@esbuild/netbsd-x64': 0.27.3 + '@esbuild/openbsd-arm64': 0.27.3 + '@esbuild/openbsd-x64': 0.27.3 + '@esbuild/openharmony-arm64': 0.27.3 + '@esbuild/sunos-x64': 0.27.3 + '@esbuild/win32-arm64': 0.27.3 + '@esbuild/win32-ia32': 0.27.3 + '@esbuild/win32-x64': 0.27.3 + + esbuild@0.27.4: optionalDependencies: - '@esbuild/aix-ppc64': 0.25.0 - '@esbuild/android-arm': 0.25.0 - '@esbuild/android-arm64': 0.25.0 - '@esbuild/android-x64': 0.25.0 - '@esbuild/darwin-arm64': 0.25.0 - '@esbuild/darwin-x64': 0.25.0 - '@esbuild/freebsd-arm64': 0.25.0 - '@esbuild/freebsd-x64': 0.25.0 - '@esbuild/linux-arm': 0.25.0 - '@esbuild/linux-arm64': 0.25.0 - '@esbuild/linux-ia32': 0.25.0 - '@esbuild/linux-loong64': 0.25.0 - '@esbuild/linux-mips64el': 0.25.0 - '@esbuild/linux-ppc64': 0.25.0 - '@esbuild/linux-riscv64': 0.25.0 - '@esbuild/linux-s390x': 0.25.0 - '@esbuild/linux-x64': 0.25.0 - '@esbuild/netbsd-arm64': 0.25.0 - '@esbuild/netbsd-x64': 0.25.0 - '@esbuild/openbsd-arm64': 0.25.0 - '@esbuild/openbsd-x64': 0.25.0 - '@esbuild/sunos-x64': 0.25.0 - '@esbuild/win32-arm64': 0.25.0 - '@esbuild/win32-ia32': 0.25.0 - '@esbuild/win32-x64': 0.25.0 + '@esbuild/aix-ppc64': 0.27.4 + '@esbuild/android-arm': 0.27.4 + '@esbuild/android-arm64': 0.27.4 + '@esbuild/android-x64': 0.27.4 + '@esbuild/darwin-arm64': 0.27.4 + '@esbuild/darwin-x64': 0.27.4 + '@esbuild/freebsd-arm64': 0.27.4 + '@esbuild/freebsd-x64': 0.27.4 + '@esbuild/linux-arm': 0.27.4 + '@esbuild/linux-arm64': 0.27.4 + '@esbuild/linux-ia32': 0.27.4 + '@esbuild/linux-loong64': 0.27.4 + '@esbuild/linux-mips64el': 0.27.4 + '@esbuild/linux-ppc64': 0.27.4 + '@esbuild/linux-riscv64': 0.27.4 + '@esbuild/linux-s390x': 0.27.4 + '@esbuild/linux-x64': 0.27.4 + '@esbuild/netbsd-arm64': 0.27.4 + '@esbuild/netbsd-x64': 0.27.4 + '@esbuild/openbsd-arm64': 0.27.4 + '@esbuild/openbsd-x64': 0.27.4 + '@esbuild/openharmony-arm64': 0.27.4 + '@esbuild/sunos-x64': 0.27.4 + '@esbuild/win32-arm64': 0.27.4 + '@esbuild/win32-ia32': 0.27.4 + '@esbuild/win32-x64': 0.27.4 escalade@3.2.0: {} @@ -8753,133 +10377,29 @@ snapshots: escape-html@1.0.3: {} - escape-string-regexp@1.0.5: {} - - escape-string-regexp@4.0.0: {} - escape-string-regexp@5.0.0: {} - eslint-config-unjs@0.4.2(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2): - dependencies: - '@eslint/js': 9.22.0 - eslint: 9.22.0(jiti@2.4.2) - eslint-plugin-markdown: 5.1.0(eslint@9.22.0(jiti@2.4.2)) - eslint-plugin-unicorn: 56.0.1(eslint@9.22.0(jiti@2.4.2)) - globals: 15.15.0 - typescript: 5.8.2 - typescript-eslint: 8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) - transitivePeerDependencies: - - supports-color - - eslint-plugin-markdown@5.1.0(eslint@9.22.0(jiti@2.4.2)): - dependencies: - eslint: 9.22.0(jiti@2.4.2) - mdast-util-from-markdown: 0.8.5 - transitivePeerDependencies: - - supports-color - - eslint-plugin-unicorn@56.0.1(eslint@9.22.0(jiti@2.4.2)): - dependencies: - '@babel/helper-validator-identifier': 7.25.9 - '@eslint-community/eslint-utils': 4.4.1(eslint@9.22.0(jiti@2.4.2)) - ci-info: 4.1.0 - clean-regexp: 1.0.0 - core-js-compat: 3.41.0 - eslint: 9.22.0(jiti@2.4.2) - esquery: 1.6.0 - globals: 15.15.0 - indent-string: 4.0.0 - is-builtin-module: 3.2.1 - jsesc: 3.1.0 - pluralize: 8.0.0 - read-pkg-up: 7.0.1 - regexp-tree: 0.1.27 - regjsparser: 0.10.0 - semver: 7.7.1 - strip-indent: 3.0.0 - - eslint-scope@8.3.0: - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - - eslint-visitor-keys@3.4.3: {} - - eslint-visitor-keys@4.2.0: {} - - eslint@9.22.0(jiti@2.4.2): - dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.22.0(jiti@2.4.2)) - '@eslint-community/regexpp': 4.12.1 - '@eslint/config-array': 0.19.2 - '@eslint/config-helpers': 0.1.0 - '@eslint/core': 0.12.0 - '@eslint/eslintrc': 3.3.0 - '@eslint/js': 9.22.0 - '@eslint/plugin-kit': 0.2.7 - '@humanfs/node': 0.16.6 - '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.4.2 - '@types/estree': 1.0.6 - '@types/json-schema': 7.0.15 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.0(supports-color@9.4.0) - escape-string-regexp: 4.0.0 - eslint-scope: 8.3.0 - eslint-visitor-keys: 4.2.0 - espree: 10.3.0 - esquery: 1.6.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 - find-up: 5.0.0 - glob-parent: 6.0.2 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - json-stable-stringify-without-jsonify: 1.0.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.4 - optionalDependencies: - jiti: 2.4.2 - transitivePeerDependencies: - - supports-color - - espree@10.3.0: - dependencies: - acorn: 8.14.1 - acorn-jsx: 5.3.2(acorn@8.14.1) - eslint-visitor-keys: 4.2.0 - - esquery@1.6.0: - dependencies: - estraverse: 5.3.0 - - esrecurse@4.3.0: - dependencies: - estraverse: 5.3.0 - - estraverse@5.3.0: {} + esprima@4.0.1: {} estree-walker@2.0.2: {} estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.6 - - esutils@2.0.3: {} + '@types/estree': 1.0.8 etag@1.8.1: {} - event-target-shim@5.0.1: {} - eventemitter3@4.0.7: {} - events@3.3.0: {} + eventsource-parser@3.0.6: {} + + eventsource@4.1.0: + dependencies: + eventsource-parser: 3.0.6 + + exact-mirror@0.2.7(@sinclair/typebox@0.34.48): + optionalDependencies: + '@sinclair/typebox': 0.34.48 execa@5.1.1: dependencies: @@ -8893,238 +10413,187 @@ snapshots: signal-exit: 3.0.7 strip-final-newline: 2.0.0 - execa@8.0.1: - dependencies: - cross-spawn: 7.0.6 - get-stream: 8.0.1 - human-signals: 5.0.0 - is-stream: 3.0.0 - merge-stream: 2.0.0 - npm-run-path: 5.3.0 - onetime: 6.0.0 - signal-exit: 4.1.0 - strip-final-newline: 3.0.0 - - execa@9.5.2: + execa@9.6.1: dependencies: '@sindresorhus/merge-streams': 4.0.0 cross-spawn: 7.0.6 figures: 6.1.0 get-stream: 9.0.1 - human-signals: 8.0.0 + human-signals: 8.0.1 is-plain-obj: 4.1.0 is-stream: 4.0.1 npm-run-path: 6.0.0 - pretty-ms: 9.2.0 + pretty-ms: 9.3.0 signal-exit: 4.1.0 strip-final-newline: 4.0.0 - yoctocolors: 2.1.1 - - exit-hook@2.2.1: {} + yoctocolors: 2.1.2 expand-template@2.0.3: {} - expect-type@1.2.0: {} + expect-type@1.3.0: {} - express@4.21.2: + express@5.2.1: dependencies: - accepts: 1.3.8 - array-flatten: 1.1.1 - body-parser: 1.20.3 - content-disposition: 0.5.4 + accepts: 2.0.0 + body-parser: 2.2.2 + content-disposition: 1.0.1 content-type: 1.0.5 - cookie: 0.7.1 - cookie-signature: 1.0.6 - debug: 2.6.9 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3 depd: 2.0.0 encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 - finalhandler: 1.3.1 - fresh: 0.5.2 - http-errors: 2.0.0 - merge-descriptors: 1.0.3 - methods: 1.1.2 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 on-finished: 2.4.1 + once: 1.4.0 parseurl: 1.3.3 - path-to-regexp: 0.1.12 proxy-addr: 2.0.7 - qs: 6.13.0 + qs: 6.15.0 range-parser: 1.2.1 - safe-buffer: 5.2.1 - send: 0.19.0 - serve-static: 1.16.2 - setprototypeof: 1.2.0 - statuses: 2.0.1 - type-is: 1.6.18 - utils-merge: 1.0.1 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.0.1 vary: 1.1.2 transitivePeerDependencies: - supports-color - exsolve@1.0.4: {} + exsolve@1.0.8: {} extend@3.0.2: {} - farmhash-modern@1.1.0: {} - fast-copy@3.0.2: {} - fast-deep-equal@3.1.3: {} + fast-decode-uri-component@1.0.1: {} - fast-fifo@1.3.2: {} + fast-deep-equal@3.1.3: {} - fast-glob@3.3.3: + fast-json-stringify@6.3.0: dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.8 - - fast-json-stable-stringify@2.1.0: {} - - fast-levenshtein@2.0.6: {} + '@fastify/merge-json-schemas': 0.2.1 + ajv: 8.18.0 + ajv-formats: 3.0.1(ajv@8.18.0) + fast-uri: 3.1.0 + json-schema-ref-resolver: 3.0.0 + rfdc: 1.4.1 - fast-uri@3.0.6: {} - - fast-xml-parser@4.5.3: + fast-querystring@1.1.2: dependencies: - strnum: 1.1.2 - optional: true + fast-decode-uri-component: 1.0.1 + + fast-uri@3.1.0: {} fastest-levenshtein@1.0.16: {} - fastq@1.19.1: + fastify@5.8.2: + dependencies: + '@fastify/ajv-compiler': 4.0.5 + '@fastify/error': 4.2.0 + '@fastify/fast-json-stringify-compiler': 5.0.3 + '@fastify/proxy-addr': 5.1.0 + abstract-logging: 2.0.1 + avvio: 9.2.0 + fast-json-stringify: 6.3.0 + find-my-way: 9.5.0 + light-my-request: 6.6.0 + pino: 10.3.1 + process-warning: 5.0.0 + rfdc: 1.4.1 + secure-json-parse: 4.1.0 + semver: 7.7.4 + toad-cache: 3.7.0 + + fastq@1.20.1: dependencies: reusify: 1.1.0 - faye-websocket@0.11.4: - dependencies: - websocket-driver: 0.7.4 - - fdir@6.4.3(picomatch@4.0.2): + fdir@6.5.0(picomatch@4.0.3): optionalDependencies: - picomatch: 4.0.2 + picomatch: 4.0.3 figures@6.1.0: dependencies: is-unicode-supported: 2.1.0 - file-entry-cache@8.0.0: + file-type@21.3.2: dependencies: - flat-cache: 4.0.1 - - file-uri-to-path@1.0.0: {} + '@tokenizer/inflate': 0.4.1 + strtok3: 10.3.4 + token-types: 6.1.2 + uint8array-extras: 1.5.0 + transitivePeerDependencies: + - supports-color fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 - finalhandler@1.3.1: + finalhandler@1.3.2: dependencies: debug: 2.6.9 encodeurl: 2.0.0 escape-html: 1.0.3 on-finished: 2.4.1 parseurl: 1.3.3 - statuses: 2.0.1 + statuses: 2.0.2 unpipe: 1.0.0 transitivePeerDependencies: - supports-color - find-up@4.1.0: - dependencies: - locate-path: 5.0.0 - path-exists: 4.0.0 - - find-up@5.0.0: - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - firebase-admin@12.7.0: - dependencies: - '@fastify/busboy': 3.1.1 - '@firebase/database-compat': 1.0.8 - '@firebase/database-types': 1.0.5 - '@types/node': 22.13.10 - farmhash-modern: 1.1.0 - jsonwebtoken: 9.0.2 - jwks-rsa: 3.1.0 - node-forge: 1.3.1 - uuid: 10.0.0 - optionalDependencies: - '@google-cloud/firestore': 7.11.0 - '@google-cloud/storage': 7.15.2 - transitivePeerDependencies: - - encoding - - supports-color - - firebase-functions@4.9.0(firebase-admin@12.7.0): + finalhandler@2.1.1: dependencies: - '@types/cors': 2.8.17 - '@types/express': 4.17.3 - cors: 2.8.5 - express: 4.21.2 - firebase-admin: 12.7.0 - protobufjs: 7.4.0 + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 transitivePeerDependencies: - supports-color - fix-dts-default-cjs-exports@1.0.0: - dependencies: - magic-string: 0.30.17 - mlly: 1.7.4 - rollup: 4.35.0 - - flat-cache@4.0.1: + find-my-way@9.5.0: dependencies: - flatted: 3.3.3 - keyv: 4.5.4 + fast-deep-equal: 3.1.3 + fast-querystring: 1.1.2 + safe-regex2: 5.1.0 - flatted@3.3.3: {} + flatted@3.4.1: {} - focus-trap@7.6.4: + focus-trap@7.8.0: dependencies: - tabbable: 6.2.0 + tabbable: 6.4.0 - follow-redirects@1.15.9: {} + follow-redirects@1.15.11(debug@4.4.3): + optionalDependencies: + debug: 4.4.3 foreground-child@3.3.1: dependencies: cross-spawn: 7.0.6 signal-exit: 4.1.0 - form-data@2.5.3: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - es-set-tostringtag: 2.1.0 - mime-types: 2.1.35 - safe-buffer: 5.2.1 - optional: true - - form-data@4.0.2: + form-data@4.0.5: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 es-set-tostringtag: 2.1.0 + hasown: 2.0.2 mime-types: 2.1.35 forwarded@0.2.0: {} - fraction.js@4.3.7: {} - fresh@0.5.2: {} - fs-constants@1.0.0: {} + fresh@2.0.0: {} - fs-extra@11.3.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.1.0 - universalify: 2.0.1 + fs-constants@1.0.0: {} fs.realpath@1.0.0: {} @@ -9133,36 +10602,15 @@ snapshots: function-bind@1.1.2: {} - functional-red-black-tree@1.0.1: - optional: true + function-timeout@1.0.2: {} fuse.js@7.1.0: {} - gaxios@6.7.1: - dependencies: - extend: 3.0.2 - https-proxy-agent: 7.0.6(supports-color@9.4.0) - is-stream: 2.0.1 - node-fetch: 2.7.0 - uuid: 9.0.1 - transitivePeerDependencies: - - encoding - - supports-color - optional: true - - gcp-metadata@6.1.1: - dependencies: - gaxios: 6.7.1 - google-logging-utils: 0.0.2 - json-bigint: 1.0.0 - transitivePeerDependencies: - - encoding - - supports-color - optional: true + gensync@1.0.0-beta.2: {} get-caller-file@2.0.5: {} - get-east-asian-width@1.3.0: {} + get-east-asian-width@1.5.0: {} get-intrinsic@1.3.0: dependencies: @@ -9179,7 +10627,7 @@ snapshots: get-own-enumerable-keys@1.0.0: {} - get-port-please@3.1.2: {} + get-port-please@3.2.0: {} get-port@3.2.0: {} @@ -9190,29 +10638,37 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 - get-source@2.0.12: - dependencies: - data-uri-to-buffer: 2.0.2 - source-map: 0.6.1 - get-stream@6.0.1: {} - get-stream@8.0.1: {} - get-stream@9.0.1: dependencies: '@sec-ant/readable-stream': 0.4.1 is-stream: 4.0.1 + get-tsconfig@4.13.6: + dependencies: + resolve-pkg-maps: 1.0.0 + giget@2.0.0: dependencies: citty: 0.1.6 - consola: 3.4.0 + consola: 3.4.2 defu: 6.1.4 - node-fetch-native: 1.6.6 - nypm: 0.6.0 + node-fetch-native: 1.6.7 + nypm: 0.6.5 pathe: 2.0.3 + giget@3.1.2: {} + + git-up@7.0.0: + dependencies: + is-ssh: 1.4.1 + parse-url: 8.1.0 + + git-url-parse@15.0.0: + dependencies: + git-up: 7.0.0 + github-from-package@0.0.0: {} github-slugger@2.0.0: {} @@ -9221,18 +10677,12 @@ snapshots: dependencies: is-glob: 4.0.3 - glob-parent@6.0.2: - dependencies: - is-glob: 4.0.3 - - glob-to-regexp@0.4.1: {} - - glob@10.4.5: + glob@10.5.0: dependencies: foreground-child: 3.3.1 jackspeak: 3.4.3 - minimatch: 9.0.5 - minipass: 7.1.2 + minimatch: 9.0.9 + minipass: 7.1.3 package-json-from-dist: 1.0.1 path-scurry: 1.11.1 @@ -9241,7 +10691,7 @@ snapshots: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 - minimatch: 3.1.2 + minimatch: 3.1.5 once: 1.4.0 path-is-absolute: 1.0.1 @@ -9249,55 +10699,11 @@ snapshots: dependencies: ini: 4.1.1 - globals@14.0.0: {} - - globals@15.15.0: {} - - globby@14.1.0: - dependencies: - '@sindresorhus/merge-streams': 2.3.0 - fast-glob: 3.3.3 - ignore: 7.0.3 - path-type: 6.0.0 - slash: 5.1.0 - unicorn-magic: 0.3.0 - globrex@0.1.2: {} - google-auth-library@9.15.1: - dependencies: - base64-js: 1.5.1 - ecdsa-sig-formatter: 1.0.11 - gaxios: 6.7.1 - gcp-metadata: 6.1.1 - gtoken: 7.1.0 - jws: 4.0.0 - transitivePeerDependencies: - - encoding - - supports-color - optional: true - - google-gax@4.4.1: + goober@2.1.18(csstype@3.2.3): dependencies: - '@grpc/grpc-js': 1.12.6 - '@grpc/proto-loader': 0.7.13 - '@types/long': 4.0.2 - abort-controller: 3.0.0 - duplexify: 4.1.3 - google-auth-library: 9.15.1 - node-fetch: 2.7.0 - object-hash: 3.0.0 - proto3-json-serializer: 2.0.2 - protobufjs: 7.4.0 - retry-request: 7.0.2 - uuid: 9.0.1 - transitivePeerDependencies: - - encoding - - supports-color - optional: true - - google-logging-utils@0.0.2: - optional: true + csstype: 3.2.3 gopd@1.2.0: {} @@ -9305,32 +10711,18 @@ snapshots: graceful-fs@4.2.11: {} - graphemer@1.4.0: {} - - gtoken@7.1.0: - dependencies: - gaxios: 6.7.1 - jws: 4.0.0 - transitivePeerDependencies: - - encoding - - supports-color - optional: true + guess-json-indent@3.0.1: {} gzip-size@7.0.0: dependencies: duplexer: 0.1.2 - h3@1.15.1: + h3@2.0.1-rc.16(crossws@0.4.4(srvx@0.11.9)): dependencies: - cookie-es: 1.2.2 - crossws: 0.3.4 - defu: 6.1.4 - destr: 2.0.3 - iron-webcrypto: 1.2.1 - node-mock-http: 1.0.0 - radix3: 1.1.2 - ufo: 1.5.4 - uncrypto: 0.1.3 + rou3: 0.8.1 + srvx: 0.11.9 + optionalDependencies: + crossws: 0.4.4(srvx@0.11.9) has-flag@4.0.0: {} @@ -9357,16 +10749,16 @@ snapshots: hast-util-phrasing: 3.0.1 hast-util-whitespace: 3.0.0 html-whitespace-sensitive-tag-names: 3.0.1 - unist-util-visit-parents: 6.0.1 + unist-util-visit-parents: 6.0.2 hast-util-from-html@2.0.3: dependencies: '@types/hast': 3.0.4 devlop: 1.1.0 hast-util-from-parse5: 8.0.3 - parse5: 7.2.1 + parse5: 7.3.0 vfile: 6.0.3 - vfile-message: 4.0.2 + vfile-message: 4.0.3 hast-util-from-parse5@8.0.3: dependencies: @@ -9374,7 +10766,7 @@ snapshots: '@types/unist': 3.0.3 devlop: 1.1.0 hastscript: 9.0.1 - property-information: 7.0.0 + property-information: 7.1.0 vfile: 6.0.3 vfile-location: 5.0.3 web-namespaces: 2.0.1 @@ -9397,7 +10789,7 @@ snapshots: hast-util-embedded: 3.0.0 hast-util-is-element: 3.0.0 hast-util-whitespace: 3.0.0 - unist-util-is: 6.0.0 + unist-util-is: 6.0.1 hast-util-parse-selector@4.0.0: dependencies: @@ -9417,12 +10809,12 @@ snapshots: '@types/unist': 3.0.3 '@ungap/structured-clone': 1.3.0 hast-util-from-parse5: 8.0.3 - hast-util-to-parse5: 8.0.0 + hast-util-to-parse5: 8.0.1 html-void-elements: 3.0.0 - mdast-util-to-hast: 13.2.0 - parse5: 7.2.1 + mdast-util-to-hast: 13.2.1 + parse5: 7.3.0 unist-util-position: 5.0.0 - unist-util-visit: 5.0.0 + unist-util-visit: 5.1.0 vfile: 6.0.3 web-namespaces: 2.0.1 zwitch: 2.0.4 @@ -9441,18 +10833,18 @@ snapshots: comma-separated-tokens: 2.0.3 hast-util-whitespace: 3.0.0 html-void-elements: 3.0.0 - mdast-util-to-hast: 13.2.0 - property-information: 7.0.0 + mdast-util-to-hast: 13.2.1 + property-information: 7.1.0 space-separated-tokens: 2.0.2 stringify-entities: 4.0.4 zwitch: 2.0.4 - hast-util-to-parse5@8.0.0: + hast-util-to-parse5@8.0.1: dependencies: '@types/hast': 3.0.4 comma-separated-tokens: 2.0.3 devlop: 1.1.0 - property-information: 6.5.0 + property-information: 7.1.0 space-separated-tokens: 2.0.2 web-namespaces: 2.0.1 zwitch: 2.0.4 @@ -9473,21 +10865,20 @@ snapshots: '@types/hast': 3.0.4 comma-separated-tokens: 2.0.3 hast-util-parse-selector: 4.0.0 - property-information: 7.0.0 + property-information: 7.1.0 space-separated-tokens: 2.0.2 + he@1.2.0: {} + highlight.js@11.11.1: {} highlightjs-curl@1.3.0: {} - highlightjs-vue@1.0.0: {} - - hookable@5.5.3: {} + hono@4.12.8: {} - hosted-git-info@2.8.9: {} + hookable@6.0.1: {} - html-entities@2.5.2: - optional: true + html-entities@2.3.3: {} html-escaper@2.0.2: {} @@ -9495,89 +10886,62 @@ snapshots: html-whitespace-sensitive-tag-names@3.0.1: {} - http-errors@2.0.0: + htmlparser2@10.1.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + entities: 7.0.1 + + http-errors@2.0.1: dependencies: depd: 2.0.0 inherits: 2.0.4 setprototypeof: 1.2.0 - statuses: 2.0.1 + statuses: 2.0.2 toidentifier: 1.0.1 - http-parser-js@0.5.9: {} - - http-proxy-agent@5.0.0: - dependencies: - '@tootallnate/once': 2.0.0 - agent-base: 6.0.2 - debug: 4.4.0(supports-color@9.4.0) - transitivePeerDependencies: - - supports-color - optional: true - http-proxy-agent@7.0.2: dependencies: - agent-base: 7.1.3 - debug: 4.4.0(supports-color@9.4.0) + agent-base: 7.1.4 + debug: 4.4.3 transitivePeerDependencies: - supports-color http-proxy@1.18.1: dependencies: eventemitter3: 4.0.7 - follow-redirects: 1.15.9 + follow-redirects: 1.15.11(debug@4.4.3) requires-port: 1.0.0 transitivePeerDependencies: - debug - http-shutdown@1.2.2: {} - - https-proxy-agent@5.0.1: - dependencies: - agent-base: 6.0.2 - debug: 4.4.0(supports-color@9.4.0) - transitivePeerDependencies: - - supports-color - optional: true - - https-proxy-agent@7.0.6(supports-color@9.4.0): + https-proxy-agent@7.0.6: dependencies: - agent-base: 7.1.3 - debug: 4.4.0(supports-color@9.4.0) + agent-base: 7.1.4 + debug: 4.4.3 transitivePeerDependencies: - supports-color - httpxy@0.1.7: {} + httpxy@0.3.1: {} human-signals@2.1.0: {} - human-signals@5.0.0: {} - - human-signals@8.0.0: {} + human-signals@8.0.1: {} - iconv-lite@0.4.24: + iconv-lite@0.6.3: dependencies: safer-buffer: 2.1.2 - iconv-lite@0.6.3: + iconv-lite@0.7.2: dependencies: safer-buffer: 2.1.2 - ieee754@1.2.1: {} - - ignore@5.3.2: {} - - ignore@7.0.3: {} - - import-fresh@3.3.1: + identifier-regex@1.0.1: dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - - imurmurhash@0.1.4: {} - - indent-string@4.0.0: {} + reserved-identifiers: 1.2.0 - index-to-position@0.1.2: {} + ieee754@1.2.1: {} inflight@1.0.6: dependencies: @@ -9597,49 +10961,28 @@ snapshots: is-ip: 3.1.0 p-event: 4.2.0 - ioredis@5.6.0: - dependencies: - '@ioredis/commands': 1.2.0 - cluster-key-slot: 1.1.2 - debug: 4.4.0(supports-color@9.4.0) - denque: 2.1.0 - lodash.defaults: 4.2.0 - lodash.isarguments: 3.1.0 - redis-errors: 1.2.0 - redis-parser: 3.0.0 - standard-as-callback: 2.1.0 - transitivePeerDependencies: - - supports-color - ip-regex@4.3.0: {} ipaddr.js@1.9.1: {} - iron-webcrypto@1.2.1: {} + ipaddr.js@2.3.0: {} is-absolute-url@4.0.1: {} - is-alphabetical@1.0.4: {} - - is-alphanumerical@1.0.4: + is-binary-path@2.1.0: dependencies: - is-alphabetical: 1.0.4 - is-decimal: 1.0.4 - - is-arrayish@0.2.1: {} + binary-extensions: 2.3.0 is-buffer@1.1.6: {} - is-builtin-module@3.2.1: + is-ci@4.1.0: dependencies: - builtin-modules: 3.3.0 + ci-info: 4.4.0 is-core-module@2.16.1: dependencies: hasown: 2.0.2 - is-decimal@1.0.4: {} - is-docker@2.2.1: {} is-docker@3.0.0: {} @@ -9652,7 +10995,10 @@ snapshots: dependencies: is-extglob: 2.1.1 - is-hexadecimal@1.0.4: {} + is-identifier@1.0.1: + dependencies: + identifier-regex: 1.0.1 + super-regex: 1.1.0 is-in-ci@1.0.0: {} @@ -9673,7 +11019,7 @@ snapshots: is-module@1.0.0: {} - is-npm@6.0.0: {} + is-npm@6.1.0: {} is-number@7.0.0: {} @@ -9683,15 +11029,25 @@ snapshots: is-plain-obj@4.1.0: {} + is-promise@4.0.0: {} + is-reference@1.2.1: dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.8 + + is-reference@3.0.3: + dependencies: + '@types/estree': 1.0.8 is-regexp@3.1.0: {} - is-stream@2.0.1: {} + is-retry-allowed@2.2.0: {} - is-stream@3.0.0: {} + is-ssh@1.4.1: + dependencies: + protocols: 2.0.2 + + is-stream@2.0.1: {} is-stream@4.0.1: {} @@ -9703,19 +11059,17 @@ snapshots: dependencies: punycode: 2.3.1 + is-what@4.1.16: {} + is-wsl@2.2.0: dependencies: is-docker: 2.2.1 - is-wsl@3.1.0: + is-wsl@3.1.1: dependencies: is-inside-container: 1.0.0 - is64bit@2.0.0: - dependencies: - system-architecture: 0.1.0 - - isarray@1.0.0: {} + isbot@5.1.36: {} isexe@2.0.0: {} @@ -9727,15 +11081,7 @@ snapshots: make-dir: 4.0.0 supports-color: 7.2.0 - istanbul-lib-source-maps@5.0.6: - dependencies: - '@jridgewell/trace-mapping': 0.3.25 - debug: 4.4.0(supports-color@9.4.0) - istanbul-lib-coverage: 3.2.2 - transitivePeerDependencies: - - supports-color - - istanbul-reports@3.1.7: + istanbul-reports@3.2.0: dependencies: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 @@ -9746,9 +11092,7 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 - jiti@1.21.7: {} - - jiti@2.4.2: {} + jiti@2.6.1: {} joi@17.13.3: dependencies: @@ -9758,31 +11102,24 @@ snapshots: '@sideway/formula': 3.0.1 '@sideway/pinpoint': 2.0.0 - jose@4.15.9: {} + jose@5.10.0: {} - js-levenshtein@1.1.6: {} + jose@6.2.1: {} + + js-base64@3.7.8: {} + + js-tokens@10.0.0: {} js-tokens@4.0.0: {} js-tokens@9.0.1: {} - js-yaml@4.1.0: + js-yaml@4.1.1: dependencies: argparse: 2.0.1 - jsesc@0.5.0: {} - jsesc@3.1.0: {} - json-bigint@1.0.0: - dependencies: - bignumber.js: 9.1.2 - optional: true - - json-buffer@3.0.1: {} - - json-parse-even-better-errors@2.3.1: {} - json-schema-library@9.3.5: dependencies: '@sagold/json-pointer': 5.1.2 @@ -9793,27 +11130,25 @@ snapshots: smtp-address-parser: 1.0.10 valid-url: 1.0.9 - json-schema-traverse@0.4.1: {} + json-schema-ref-resolver@3.0.0: + dependencies: + dequal: 2.0.3 json-schema-traverse@1.0.0: {} - json-source-map@0.6.1: {} + json-schema@0.4.0: {} - json-stable-stringify-without-jsonify@1.0.1: {} + json-source-map@0.6.1: {} - json-stringify-deterministic@1.0.12: {} + json5@2.2.3: {} - jsonfile@6.1.0: - dependencies: - universalify: 2.0.1 - optionalDependencies: - graceful-fs: 4.2.11 + jsonc-parser@3.3.1: {} jsonpointer@5.0.1: {} - jsonwebtoken@9.0.2: + jsonwebtoken@9.0.3: dependencies: - jws: 3.2.2 + jws: 4.0.1 lodash.includes: 4.3.0 lodash.isboolean: 3.0.3 lodash.isinteger: 4.0.4 @@ -9822,43 +11157,19 @@ snapshots: lodash.isstring: 4.0.1 lodash.once: 4.1.1 ms: 2.1.3 - semver: 7.7.1 + semver: 7.7.4 just-clone@6.2.0: {} - just-curry-it@5.3.0: {} - - jwa@1.4.1: + jwa@2.0.1: dependencies: buffer-equal-constant-time: 1.0.1 ecdsa-sig-formatter: 1.0.11 safe-buffer: 5.2.1 - jwa@2.0.0: - dependencies: - buffer-equal-constant-time: 1.0.1 - ecdsa-sig-formatter: 1.0.11 - safe-buffer: 5.2.1 - - jwks-rsa@3.1.0: - dependencies: - '@types/express': 4.17.21 - '@types/jsonwebtoken': 9.0.9 - debug: 4.4.0(supports-color@9.4.0) - jose: 4.15.9 - limiter: 1.1.5 - lru-memoizer: 2.3.0 - transitivePeerDependencies: - - supports-color - - jws@3.2.2: - dependencies: - jwa: 1.4.1 - safe-buffer: 5.2.1 - - jws@4.0.0: + jws@4.0.1: dependencies: - jwa: 2.0.0 + jwa: 2.0.1 safe-buffer: 5.2.1 jwt-decode@4.0.0: {} @@ -9868,88 +11179,137 @@ snapshots: node-addon-api: 4.3.0 prebuild-install: 7.1.3 - keyv@4.5.4: - dependencies: - json-buffer: 3.0.1 - kleur@3.0.3: {} kleur@4.1.5: {} klona@2.0.6: {} - knitwork@1.2.0: {} + knitwork@1.3.0: {} - ky@1.7.5: {} + kolorist@1.8.0: {} + + ky@1.14.3: {} latest-version@9.0.0: dependencies: package-json: 10.0.1 - lazystream@1.0.1: + leven@4.1.0: {} + + light-my-request@6.6.0: dependencies: - readable-stream: 2.3.8 + cookie: 1.1.1 + process-warning: 4.0.1 + set-cookie-parser: 2.7.2 - leven@4.0.0: {} + lightningcss-android-arm64@1.31.1: + optional: true - levn@0.4.1: - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 + lightningcss-android-arm64@1.32.0: + optional: true - lilconfig@3.1.3: {} + lightningcss-darwin-arm64@1.31.1: + optional: true - limiter@1.1.5: {} + lightningcss-darwin-arm64@1.32.0: + optional: true - lines-and-columns@1.2.4: {} + lightningcss-darwin-x64@1.31.1: + optional: true - listhen@1.9.0: - dependencies: - '@parcel/watcher': 2.5.1 - '@parcel/watcher-wasm': 2.5.1 - citty: 0.1.6 - clipboardy: 4.0.0 - consola: 3.4.0 - crossws: 0.3.4 - defu: 6.1.4 - get-port-please: 3.1.2 - h3: 1.15.1 - http-shutdown: 1.2.2 - jiti: 2.4.2 - mlly: 1.7.4 - node-forge: 1.3.1 - pathe: 1.1.2 - std-env: 3.8.1 - ufo: 1.5.4 - untun: 0.1.3 - uqr: 0.1.2 + lightningcss-darwin-x64@1.32.0: + optional: true - local-pkg@1.1.1: - dependencies: - mlly: 1.7.4 - pkg-types: 2.1.0 - quansync: 0.2.8 + lightningcss-freebsd-x64@1.31.1: + optional: true - locate-path@5.0.0: - dependencies: - p-locate: 4.1.0 + lightningcss-freebsd-x64@1.32.0: + optional: true - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 + lightningcss-linux-arm-gnueabihf@1.31.1: + optional: true - lodash.camelcase@4.3.0: + lightningcss-linux-arm-gnueabihf@1.32.0: optional: true - lodash.clonedeep@4.5.0: {} + lightningcss-linux-arm64-gnu@1.31.1: + optional: true - lodash.deburr@4.1.0: {} + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.31.1: + optional: true - lodash.defaults@4.2.0: {} + lightningcss-linux-arm64-musl@1.32.0: + optional: true - lodash.includes@4.3.0: {} + lightningcss-linux-x64-gnu@1.31.1: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.31.1: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.31.1: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.31.1: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.31.1: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.31.1 + lightningcss-darwin-arm64: 1.31.1 + lightningcss-darwin-x64: 1.31.1 + lightningcss-freebsd-x64: 1.31.1 + lightningcss-linux-arm-gnueabihf: 1.31.1 + lightningcss-linux-arm64-gnu: 1.31.1 + lightningcss-linux-arm64-musl: 1.31.1 + lightningcss-linux-x64-gnu: 1.31.1 + lightningcss-linux-x64-musl: 1.31.1 + lightningcss-win32-arm64-msvc: 1.31.1 + lightningcss-win32-x64-msvc: 1.31.1 + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + local-pkg@1.1.2: + dependencies: + mlly: 1.8.1 + pkg-types: 2.3.0 + quansync: 0.2.11 + + lodash.deburr@4.1.0: {} - lodash.isarguments@3.1.0: {} + lodash.includes@4.3.0: {} lodash.isboolean@3.0.3: {} @@ -9961,15 +11321,9 @@ snapshots: lodash.isstring@4.0.1: {} - lodash.memoize@4.1.2: {} - - lodash.merge@4.6.2: {} - lodash.once@4.1.1: {} - lodash.uniq@4.5.0: {} - - lodash@4.17.21: {} + lodash@4.17.23: {} log-symbols@4.1.0: dependencies: @@ -9978,12 +11332,8 @@ snapshots: long@4.0.0: {} - long@5.3.1: {} - longest-streak@3.1.0: {} - loupe@3.1.3: {} - lowlight@3.3.0: dependencies: '@types/hast': 3.0.4 @@ -9992,34 +11342,39 @@ snapshots: lru-cache@10.4.3: {} - lru-cache@6.0.0: + lru-cache@5.1.1: dependencies: - yallist: 4.0.0 + yallist: 3.1.1 - lru-memoizer@2.3.0: + magic-string@0.30.21: dependencies: - lodash.clonedeep: 4.5.0 - lru-cache: 6.0.0 + '@jridgewell/sourcemap-codec': 1.5.5 - magic-string@0.30.17: + magicast@0.5.2: dependencies: - '@jridgewell/sourcemap-codec': 1.5.0 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + source-map-js: 1.2.1 - magicast@0.3.5: + make-asynchronous@1.1.0: dependencies: - '@babel/parser': 7.26.9 - '@babel/types': 7.26.9 - source-map-js: 1.2.1 + p-event: 6.0.1 + type-fest: 4.41.0 + web-worker: 1.5.0 make-dir@4.0.0: dependencies: - semver: 7.7.1 + semver: 7.7.4 markdown-table@3.0.4: {} + marked@14.0.0: {} + math-intrinsics@1.1.0: {} - md4w@0.2.6: {} + md4w@0.2.7: {} + + md4x@0.0.25: {} md5@2.3.0: dependencies: @@ -10031,24 +11386,14 @@ snapshots: dependencies: '@types/mdast': 4.0.4 escape-string-regexp: 5.0.0 - unist-util-is: 6.0.0 - unist-util-visit-parents: 6.0.1 - - mdast-util-from-markdown@0.8.5: - dependencies: - '@types/mdast': 3.0.15 - mdast-util-to-string: 2.0.0 - micromark: 2.11.4 - parse-entities: 2.0.0 - unist-util-stringify-position: 2.0.3 - transitivePeerDependencies: - - supports-color + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 - mdast-util-from-markdown@2.0.2: + mdast-util-from-markdown@2.0.3: dependencies: '@types/mdast': 4.0.4 '@types/unist': 3.0.3 - decode-named-character-reference: 1.1.0 + decode-named-character-reference: 1.3.0 devlop: 1.1.0 mdast-util-to-string: 4.0.0 micromark: 4.0.2 @@ -10073,7 +11418,7 @@ snapshots: dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 micromark-util-normalize-identifier: 2.0.1 transitivePeerDependencies: @@ -10082,7 +11427,7 @@ snapshots: mdast-util-gfm-strikethrough@2.0.0: dependencies: '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color @@ -10092,7 +11437,7 @@ snapshots: '@types/mdast': 4.0.4 devlop: 1.1.0 markdown-table: 3.0.4 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color @@ -10101,14 +11446,14 @@ snapshots: dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color mdast-util-gfm@3.1.0: dependencies: - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-gfm-autolink-literal: 2.0.1 mdast-util-gfm-footnote: 2.1.0 mdast-util-gfm-strikethrough: 2.0.0 @@ -10121,9 +11466,9 @@ snapshots: mdast-util-phrasing@4.1.0: dependencies: '@types/mdast': 4.0.4 - unist-util-is: 6.0.0 + unist-util-is: 6.0.1 - mdast-util-to-hast@13.2.0: + mdast-util-to-hast@13.2.1: dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 @@ -10132,7 +11477,7 @@ snapshots: micromark-util-sanitize-uri: 2.0.1 trim-lines: 3.0.1 unist-util-position: 5.0.0 - unist-util-visit: 5.0.0 + unist-util-visit: 5.1.0 vfile: 6.0.3 mdast-util-to-markdown@2.1.2: @@ -10144,38 +11489,49 @@ snapshots: mdast-util-to-string: 4.0.0 micromark-util-classify-character: 2.0.1 micromark-util-decode-string: 2.0.1 - unist-util-visit: 5.0.0 + unist-util-visit: 5.1.0 zwitch: 2.0.4 - mdast-util-to-string@2.0.0: {} - mdast-util-to-string@4.0.0: dependencies: '@types/mdast': 4.0.4 mdbox@0.1.1: dependencies: - md4w: 0.2.6 + md4w: 0.2.7 - mdn-data@2.0.28: {} + mdream@0.17.0: + dependencies: + cac: 7.0.0 + pathe: 2.0.3 + tinyglobby: 0.2.15 - mdn-data@2.0.30: {} + mdzilla@0.0.6: + dependencies: + '@speed-highlight/core': 1.2.14 + giget: 3.1.2 + md4x: 0.0.25 + mdream: 0.17.0 + srvx: 0.11.9 + std-env: 4.0.0 - media-typer@0.3.0: {} + media-typer@1.1.0: {} - merge-descriptors@1.0.3: {} + memoirist@0.4.0: {} - merge-stream@2.0.0: {} + merge-anything@5.1.7: + dependencies: + is-what: 4.1.16 - merge2@1.4.1: {} + merge-descriptors@2.0.0: {} - methods@1.1.2: {} + merge-stream@2.0.0: {} microdiff@1.5.0: {} micromark-core-commonmark@2.0.3: dependencies: - decode-named-character-reference: 1.1.0 + decode-named-character-reference: 1.3.0 devlop: 1.1.0 micromark-factory-destination: 2.0.1 micromark-factory-label: 2.0.1 @@ -10308,7 +11664,7 @@ snapshots: micromark-util-decode-string@2.0.1: dependencies: - decode-named-character-reference: 1.1.0 + decode-named-character-reference: 1.3.0 micromark-util-character: 2.1.1 micromark-util-decode-numeric-character-reference: 2.0.2 micromark-util-symbol: 2.0.1 @@ -10342,18 +11698,11 @@ snapshots: micromark-util-types@2.0.2: {} - micromark@2.11.4: - dependencies: - debug: 4.4.0(supports-color@9.4.0) - parse-entities: 2.0.0 - transitivePeerDependencies: - - supports-color - micromark@4.0.2: dependencies: '@types/debug': 4.1.12 - debug: 4.4.0(supports-color@9.4.0) - decode-named-character-reference: 1.1.0 + debug: 4.4.3 + decode-named-character-reference: 1.3.0 devlop: 1.1.0 micromark-core-commonmark: 2.0.3 micromark-factory-space: 2.0.1 @@ -10371,68 +11720,53 @@ snapshots: transitivePeerDependencies: - supports-color - micromatch@4.0.8: - dependencies: - braces: 3.0.3 - picomatch: 2.3.1 - mime-db@1.52.0: {} + mime-db@1.54.0: {} + mime-types@2.1.35: dependencies: mime-db: 1.52.0 - mime@1.6.0: {} + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 - mime@3.0.0: {} + mime@1.6.0: {} - mime@4.0.6: {} + mime@4.1.0: {} mimic-fn@2.1.0: {} - mimic-fn@4.0.0: {} - mimic-response@3.1.0: {} - min-indent@1.0.1: {} - - miniflare@3.20250224.0: + miniflare@4.20260312.0: dependencies: '@cspotcode/source-map-support': 0.8.1 - acorn: 8.14.0 - acorn-walk: 8.3.2 - exit-hook: 2.2.1 - glob-to-regexp: 0.4.1 - stoppable: 1.1.0 - undici: 5.28.5 - workerd: 1.20250224.0 + sharp: 0.34.5 + undici: 7.18.2 + workerd: 1.20260312.1 ws: 8.18.0 - youch: 3.2.3 - zod: 3.22.3 + youch: 4.1.0-beta.10 transitivePeerDependencies: - bufferutil - utf-8-validate - minimatch@3.1.2: + minimatch@10.2.4: dependencies: - brace-expansion: 1.1.11 + brace-expansion: 5.0.4 - minimatch@5.1.6: + minimatch@3.1.5: dependencies: - brace-expansion: 2.0.1 + brace-expansion: 1.1.12 - minimatch@9.0.5: + minimatch@9.0.9: dependencies: - brace-expansion: 2.0.1 + brace-expansion: 2.0.2 minimist@1.2.8: {} - minipass@7.1.2: {} - - minizlib@3.0.1: - dependencies: - minipass: 7.1.2 - rimraf: 5.0.10 + minipass@7.1.3: {} mkdirp-classic@0.5.3: {} @@ -10440,35 +11774,56 @@ snapshots: dependencies: minimist: 1.2.8 - mkdirp@3.0.1: {} - - mkdist@2.2.0(typescript@5.8.2)(vue@3.5.13(typescript@5.8.2)): + mlly@1.8.1: dependencies: - autoprefixer: 10.4.20(postcss@8.5.3) - citty: 0.1.6 - cssnano: 7.0.6(postcss@8.5.3) - defu: 6.1.4 - esbuild: 0.24.2 - jiti: 1.21.7 - mlly: 1.7.4 - pathe: 1.1.2 + acorn: 8.16.0 + pathe: 2.0.3 pkg-types: 1.3.1 - postcss: 8.5.3 - postcss-nested: 7.0.2(postcss@8.5.3) - semver: 7.7.1 - tinyglobby: 0.2.12 - optionalDependencies: - typescript: 5.8.2 - vue: 3.5.13(typescript@5.8.2) + ufo: 1.6.3 + + moment@2.30.1: {} - mlly@1.7.4: + monaco-editor@0.54.0: dependencies: - acorn: 8.14.1 - pathe: 2.0.3 - pkg-types: 1.3.1 - ufo: 1.5.4 + dompurify: 3.1.7 + marked: 14.0.0 + + monaco-languageserver-types@0.4.0: + dependencies: + monaco-types: 0.1.2 + vscode-languageserver-protocol: 3.17.5 + vscode-uri: 3.1.0 + + monaco-marker-data-provider@1.2.5: + dependencies: + monaco-types: 0.1.2 + + monaco-types@0.1.2: {} + + monaco-worker-manager@2.0.1(monaco-editor@0.54.0): + dependencies: + monaco-editor: 0.54.0 + + monaco-yaml@5.2.3(monaco-editor@0.54.0): + dependencies: + jsonc-parser: 3.3.1 + monaco-editor: 0.54.0 + monaco-languageserver-types: 0.4.0 + monaco-marker-data-provider: 1.2.5 + monaco-types: 0.1.2 + monaco-worker-manager: 2.0.1(monaco-editor@0.54.0) + path-browserify: 1.0.1 + prettier: 2.8.8 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-uri: 3.1.0 + yaml: 2.8.2 + + mono-jsx@0.8.2: {} - moo@0.5.2: {} + mono-jsx@0.9.10: {} + + moo@0.5.3: {} mri@1.2.0: {} @@ -10476,72 +11831,62 @@ snapshots: ms@2.1.3: {} - mustache@4.2.0: {} - - nano-jsx@0.0.37: {} + nano-jsx@0.2.1: {} - nanoid@3.3.9: {} + nanoid@3.3.11: {} - nanoid@5.1.3: {} + nanoid@5.1.6: {} napi-build-utils@2.0.0: {} - natural-compare@1.4.0: {} - nearley@2.20.1: dependencies: commander: 2.20.3 - moo: 0.5.2 + moo: 0.5.3 railroad-diagrams: 1.0.0 randexp: 0.4.6 - negotiator@0.6.3: {} + negotiator@1.0.0: {} + + neverpanic@0.0.5(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + + nf3@0.3.11: {} - node-abi@3.74.0: + node-abi@3.88.0: dependencies: - semver: 7.7.1 + semver: 7.7.4 node-addon-api@4.3.0: {} node-addon-api@7.1.1: {} - node-fetch-native@1.6.6: {} + node-fetch-native@1.6.7: {} node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 - node-forge@1.3.1: {} - - node-gyp-build@4.8.4: {} - - node-mock-http@1.0.0: {} + node-forge@1.3.3: {} - node-releases@2.0.19: {} - - nopt@8.1.0: + node-html-parser@6.1.13: dependencies: - abbrev: 3.0.0 + css-select: 5.2.2 + he: 1.2.0 - normalize-package-data@2.5.0: + node-persist@4.0.4: dependencies: - hosted-git-info: 2.8.9 - resolve: 1.22.10 - semver: 5.7.2 - validate-npm-package-license: 3.0.4 + p-limit: 3.1.0 - normalize-path@3.0.0: {} + node-releases@2.0.36: {} - normalize-range@0.1.2: {} + normalize-path@3.0.0: {} npm-run-path@4.0.1: dependencies: path-key: 3.1.1 - npm-run-path@5.3.0: - dependencies: - path-key: 4.0.0 - npm-run-path@6.0.0: dependencies: path-key: 4.0.0 @@ -10551,31 +11896,61 @@ snapshots: dependencies: boolbase: 1.0.0 - nypm@0.6.0: + nypm@0.6.5: dependencies: - citty: 0.1.6 - consola: 3.4.0 + citty: 0.2.1 pathe: 2.0.3 - pkg-types: 2.1.0 - tinyexec: 0.3.2 + tinyexec: 1.0.4 - object-assign@4.1.1: {} - - object-hash@3.0.0: - optional: true + oauth4webapi@3.8.5: {} object-inspect@1.13.4: {} - ofetch@1.4.1: + obug@2.1.1: {} + + obuild@0.4.32(@typescript/native-preview@7.0.0-dev.20260314.1)(chokidar@5.0.0)(dotenv@17.3.1)(giget@3.1.2)(jiti@2.6.1)(magicast@0.5.2)(picomatch@4.0.3)(rollup@4.59.0)(typescript@5.9.3): + dependencies: + c12: 4.0.0-beta.3(chokidar@5.0.0)(dotenv@17.3.1)(giget@3.1.2)(jiti@2.6.1)(magicast@0.5.2) + consola: 3.4.2 + defu: 6.1.4 + exsolve: 1.0.8 + magic-string: 0.30.21 + pathe: 2.0.3 + pretty-bytes: 7.1.0 + rolldown: 1.0.0-rc.9 + rolldown-plugin-dts: 0.22.5(@typescript/native-preview@7.0.0-dev.20260314.1)(rolldown@1.0.0-rc.9)(typescript@5.9.3) + rollup-plugin-license: 3.7.0(picomatch@4.0.3)(rollup@4.59.0) + tinyglobby: 0.2.15 + transitivePeerDependencies: + - '@ts-macro/tsc' + - '@typescript/native-preview' + - chokidar + - dotenv + - giget + - jiti + - magicast + - oxc-resolver + - picomatch + - rollup + - typescript + - vue-tsc + + ocache@0.1.2: + dependencies: + ohash: 2.0.11 + + ofetch@1.5.1: dependencies: - destr: 2.0.3 - node-fetch-native: 1.6.6 - ufo: 1.5.4 + destr: 2.0.5 + node-fetch-native: 1.6.7 + ufo: 1.6.3 - ohash@1.1.6: {} + ofetch@2.0.0-alpha.3: {} ohash@2.0.11: {} + on-exit-leak-free@2.1.2: {} + on-finished@2.4.1: dependencies: ee-first: 1.1.1 @@ -10588,16 +11963,20 @@ snapshots: dependencies: mimic-fn: 2.1.0 - onetime@6.0.0: + oniguruma-parser@0.12.1: {} + + oniguruma-to-es@4.3.4: dependencies: - mimic-fn: 4.0.0 + oniguruma-parser: 0.12.1 + regex: 6.1.0 + regex-recursion: 6.0.2 - open@10.1.0: + open@10.2.0: dependencies: - default-browser: 5.2.1 + default-browser: 5.5.0 define-lazy-prop: 3.0.0 is-inside-container: 1.0.0 - is-wsl: 3.1.0 + wsl-utils: 0.1.0 open@8.4.2: dependencies: @@ -10605,24 +11984,12 @@ snapshots: is-docker: 2.2.1 is-wsl: 2.2.0 - openapi-typescript@7.6.1(typescript@5.8.2): - dependencies: - '@redocly/openapi-core': 1.33.0(supports-color@9.4.0) - ansi-colors: 4.1.3 - change-case: 5.4.4 - parse-json: 8.1.0 - supports-color: 9.4.0 - typescript: 5.8.2 - yargs-parser: 21.1.1 + openapi-types@12.1.3: {} - optionator@0.9.4: + openid-client@6.8.2: dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.5 + jose: 6.2.1 + oauth4webapi: 3.8.5 ora@5.4.1: dependencies: @@ -10638,80 +12005,107 @@ snapshots: os-tmpdir@1.0.2: {} + oxfmt@0.40.0: + dependencies: + tinypool: 2.1.0 + optionalDependencies: + '@oxfmt/binding-android-arm-eabi': 0.40.0 + '@oxfmt/binding-android-arm64': 0.40.0 + '@oxfmt/binding-darwin-arm64': 0.40.0 + '@oxfmt/binding-darwin-x64': 0.40.0 + '@oxfmt/binding-freebsd-x64': 0.40.0 + '@oxfmt/binding-linux-arm-gnueabihf': 0.40.0 + '@oxfmt/binding-linux-arm-musleabihf': 0.40.0 + '@oxfmt/binding-linux-arm64-gnu': 0.40.0 + '@oxfmt/binding-linux-arm64-musl': 0.40.0 + '@oxfmt/binding-linux-ppc64-gnu': 0.40.0 + '@oxfmt/binding-linux-riscv64-gnu': 0.40.0 + '@oxfmt/binding-linux-riscv64-musl': 0.40.0 + '@oxfmt/binding-linux-s390x-gnu': 0.40.0 + '@oxfmt/binding-linux-x64-gnu': 0.40.0 + '@oxfmt/binding-linux-x64-musl': 0.40.0 + '@oxfmt/binding-openharmony-arm64': 0.40.0 + '@oxfmt/binding-win32-arm64-msvc': 0.40.0 + '@oxfmt/binding-win32-ia32-msvc': 0.40.0 + '@oxfmt/binding-win32-x64-msvc': 0.40.0 + + oxlint@1.55.0: + optionalDependencies: + '@oxlint/binding-android-arm-eabi': 1.55.0 + '@oxlint/binding-android-arm64': 1.55.0 + '@oxlint/binding-darwin-arm64': 1.55.0 + '@oxlint/binding-darwin-x64': 1.55.0 + '@oxlint/binding-freebsd-x64': 1.55.0 + '@oxlint/binding-linux-arm-gnueabihf': 1.55.0 + '@oxlint/binding-linux-arm-musleabihf': 1.55.0 + '@oxlint/binding-linux-arm64-gnu': 1.55.0 + '@oxlint/binding-linux-arm64-musl': 1.55.0 + '@oxlint/binding-linux-ppc64-gnu': 1.55.0 + '@oxlint/binding-linux-riscv64-gnu': 1.55.0 + '@oxlint/binding-linux-riscv64-musl': 1.55.0 + '@oxlint/binding-linux-s390x-gnu': 1.55.0 + '@oxlint/binding-linux-x64-gnu': 1.55.0 + '@oxlint/binding-linux-x64-musl': 1.55.0 + '@oxlint/binding-openharmony-arm64': 1.55.0 + '@oxlint/binding-win32-arm64-msvc': 1.55.0 + '@oxlint/binding-win32-ia32-msvc': 1.55.0 + '@oxlint/binding-win32-x64-msvc': 1.55.0 + p-event@4.2.0: dependencies: p-timeout: 3.2.0 - p-finally@1.0.0: {} - - p-limit@2.3.0: + p-event@6.0.1: dependencies: - p-try: 2.2.0 + p-timeout: 6.1.4 + + p-finally@1.0.0: {} p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 - p-locate@4.1.0: - dependencies: - p-limit: 2.3.0 - - p-locate@5.0.0: - dependencies: - p-limit: 3.1.0 - p-timeout@3.2.0: dependencies: p-finally: 1.0.0 - p-try@2.2.0: {} + p-timeout@6.1.4: {} package-json-from-dist@1.0.1: {} package-json@10.0.1: dependencies: - ky: 1.7.5 - registry-auth-token: 5.1.0 + ky: 1.14.3 + registry-auth-token: 5.1.1 registry-url: 6.0.1 - semver: 7.7.1 + semver: 7.7.4 - packrup@0.1.2: {} + package-name-regex@2.0.6: {} - parent-module@1.0.1: - dependencies: - callsites: 3.1.0 + parse-ms@2.1.0: {} - parse-entities@2.0.0: - dependencies: - character-entities: 1.2.4 - character-entities-legacy: 1.1.4 - character-reference-invalid: 1.1.4 - is-alphanumerical: 1.0.4 - is-decimal: 1.0.4 - is-hexadecimal: 1.0.4 + parse-ms@4.0.0: {} - parse-json@5.2.0: + parse-path@7.1.0: dependencies: - '@babel/code-frame': 7.26.2 - error-ex: 1.3.2 - json-parse-even-better-errors: 2.3.1 - lines-and-columns: 1.2.4 + protocols: 2.0.2 - parse-json@8.1.0: + parse-url@8.1.0: dependencies: - '@babel/code-frame': 7.26.2 - index-to-position: 0.1.2 - type-fest: 4.37.0 - - parse-ms@2.1.0: {} + parse-path: 7.1.0 - parse-ms@3.0.0: {} + parse5-htmlparser2-tree-adapter@7.1.0: + dependencies: + domhandler: 5.0.3 + parse5: 7.3.0 - parse-ms@4.0.0: {} + parse5-parser-stream@7.1.2: + dependencies: + parse5: 7.3.0 - parse5@7.2.1: + parse5@7.3.0: dependencies: - entities: 4.5.0 + entities: 6.0.1 parseurl@1.3.3: {} @@ -10720,7 +12114,7 @@ snapshots: ansi-escapes: 4.3.2 cross-spawn: 7.0.6 - path-exists@4.0.0: {} + path-browserify@1.0.1: {} path-is-absolute@1.0.1: {} @@ -10733,18 +12127,14 @@ snapshots: path-scurry@1.11.1: dependencies: lru-cache: 10.4.3 - minipass: 7.1.2 + minipass: 7.1.3 - path-to-regexp@0.1.12: {} + path-to-regexp@6.3.0: {} - path-type@6.0.0: {} - - pathe@1.1.2: {} + path-to-regexp@8.3.0: {} pathe@2.0.3: {} - pathval@2.0.0: {} - pem@1.14.8: dependencies: es6-promisify: 7.0.0 @@ -10752,269 +12142,113 @@ snapshots: os-tmpdir: 1.0.2 which: 2.0.2 - perfect-debounce@1.0.0: {} - - picocolors@1.1.1: {} - - picomatch@2.3.1: {} - - picomatch@4.0.2: {} - - pkg-types@1.3.1: - dependencies: - confbox: 0.1.8 - mlly: 1.7.4 - pathe: 2.0.3 - - pkg-types@2.1.0: - dependencies: - confbox: 0.2.1 - exsolve: 1.0.4 - pathe: 2.0.3 - - pluralize@8.0.0: {} - - postcss-calc@10.1.1(postcss@8.5.3): - dependencies: - postcss: 8.5.3 - postcss-selector-parser: 7.1.0 - postcss-value-parser: 4.2.0 - - postcss-colormin@7.0.2(postcss@8.5.3): - dependencies: - browserslist: 4.24.4 - caniuse-api: 3.0.0 - colord: 2.9.3 - postcss: 8.5.3 - postcss-value-parser: 4.2.0 - - postcss-convert-values@7.0.4(postcss@8.5.3): - dependencies: - browserslist: 4.24.4 - postcss: 8.5.3 - postcss-value-parser: 4.2.0 - - postcss-discard-comments@7.0.3(postcss@8.5.3): - dependencies: - postcss: 8.5.3 - postcss-selector-parser: 6.1.2 - - postcss-discard-duplicates@7.0.1(postcss@8.5.3): - dependencies: - postcss: 8.5.3 - - postcss-discard-empty@7.0.0(postcss@8.5.3): - dependencies: - postcss: 8.5.3 - - postcss-discard-overridden@7.0.0(postcss@8.5.3): - dependencies: - postcss: 8.5.3 - - postcss-merge-longhand@7.0.4(postcss@8.5.3): - dependencies: - postcss: 8.5.3 - postcss-value-parser: 4.2.0 - stylehacks: 7.0.4(postcss@8.5.3) - - postcss-merge-rules@7.0.4(postcss@8.5.3): - dependencies: - browserslist: 4.24.4 - caniuse-api: 3.0.0 - cssnano-utils: 5.0.0(postcss@8.5.3) - postcss: 8.5.3 - postcss-selector-parser: 6.1.2 - - postcss-minify-font-values@7.0.0(postcss@8.5.3): - dependencies: - postcss: 8.5.3 - postcss-value-parser: 4.2.0 - - postcss-minify-gradients@7.0.0(postcss@8.5.3): - dependencies: - colord: 2.9.3 - cssnano-utils: 5.0.0(postcss@8.5.3) - postcss: 8.5.3 - postcss-value-parser: 4.2.0 - - postcss-minify-params@7.0.2(postcss@8.5.3): - dependencies: - browserslist: 4.24.4 - cssnano-utils: 5.0.0(postcss@8.5.3) - postcss: 8.5.3 - postcss-value-parser: 4.2.0 + perfect-debounce@2.1.0: {} - postcss-minify-selectors@7.0.4(postcss@8.5.3): + periscopic@4.0.2: dependencies: - cssesc: 3.0.0 - postcss: 8.5.3 - postcss-selector-parser: 6.1.2 + '@types/estree': 1.0.8 + is-reference: 3.0.3 + zimmerframe: 1.1.4 - postcss-nested@7.0.2(postcss@8.5.3): - dependencies: - postcss: 8.5.3 - postcss-selector-parser: 7.1.0 - - postcss-normalize-charset@7.0.0(postcss@8.5.3): - dependencies: - postcss: 8.5.3 - - postcss-normalize-display-values@7.0.0(postcss@8.5.3): - dependencies: - postcss: 8.5.3 - postcss-value-parser: 4.2.0 - - postcss-normalize-positions@7.0.0(postcss@8.5.3): - dependencies: - postcss: 8.5.3 - postcss-value-parser: 4.2.0 - - postcss-normalize-repeat-style@7.0.0(postcss@8.5.3): - dependencies: - postcss: 8.5.3 - postcss-value-parser: 4.2.0 - - postcss-normalize-string@7.0.0(postcss@8.5.3): - dependencies: - postcss: 8.5.3 - postcss-value-parser: 4.2.0 - - postcss-normalize-timing-functions@7.0.0(postcss@8.5.3): - dependencies: - postcss: 8.5.3 - postcss-value-parser: 4.2.0 - - postcss-normalize-unicode@7.0.2(postcss@8.5.3): - dependencies: - browserslist: 4.24.4 - postcss: 8.5.3 - postcss-value-parser: 4.2.0 - - postcss-normalize-url@7.0.0(postcss@8.5.3): - dependencies: - postcss: 8.5.3 - postcss-value-parser: 4.2.0 - - postcss-normalize-whitespace@7.0.0(postcss@8.5.3): - dependencies: - postcss: 8.5.3 - postcss-value-parser: 4.2.0 + picocolors@1.1.1: {} - postcss-ordered-values@7.0.1(postcss@8.5.3): - dependencies: - cssnano-utils: 5.0.0(postcss@8.5.3) - postcss: 8.5.3 - postcss-value-parser: 4.2.0 + picomatch@2.3.1: {} - postcss-reduce-initial@7.0.2(postcss@8.5.3): - dependencies: - browserslist: 4.24.4 - caniuse-api: 3.0.0 - postcss: 8.5.3 + picomatch@4.0.3: {} - postcss-reduce-transforms@7.0.0(postcss@8.5.3): + pino-abstract-transport@3.0.0: dependencies: - postcss: 8.5.3 - postcss-value-parser: 4.2.0 + split2: 4.2.0 - postcss-selector-parser@6.1.2: - dependencies: - cssesc: 3.0.0 - util-deprecate: 1.0.2 + pino-std-serializers@7.1.0: {} - postcss-selector-parser@7.1.0: + pino@10.3.1: dependencies: - cssesc: 3.0.0 - util-deprecate: 1.0.2 + '@pinojs/redact': 0.4.0 + atomic-sleep: 1.0.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 3.0.0 + pino-std-serializers: 7.1.0 + process-warning: 5.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 4.2.1 + thread-stream: 4.0.0 - postcss-svgo@7.0.1(postcss@8.5.3): + pkg-types@1.3.1: dependencies: - postcss: 8.5.3 - postcss-value-parser: 4.2.0 - svgo: 3.3.2 + confbox: 0.1.8 + mlly: 1.8.1 + pathe: 2.0.3 - postcss-unique-selectors@7.0.3(postcss@8.5.3): + pkg-types@2.3.0: dependencies: - postcss: 8.5.3 - postcss-selector-parser: 6.1.2 - - postcss-value-parser@4.2.0: {} + confbox: 0.2.4 + exsolve: 1.0.8 + pathe: 2.0.3 - postcss@8.5.3: + postcss@8.5.8: dependencies: - nanoid: 3.3.9 + nanoid: 3.3.11 picocolors: 1.1.1 source-map-js: 1.2.1 + preact-render-to-string@6.6.6(preact@10.29.0): + dependencies: + preact: 10.29.0 + + preact@10.29.0: {} + prebuild-install@7.1.3: dependencies: - detect-libc: 2.0.3 + detect-libc: 2.1.2 expand-template: 2.0.3 github-from-package: 0.0.0 minimist: 1.2.8 mkdirp-classic: 0.5.3 napi-build-utils: 2.0.0 - node-abi: 3.74.0 - pump: 3.0.2 + node-abi: 3.88.0 + pump: 3.0.4 rc: 1.2.8 simple-get: 4.0.1 - tar-fs: 2.1.2 + tar-fs: 2.1.4 tunnel-agent: 0.6.0 - prelude-ls@1.2.1: {} + prettier@2.8.8: {} - prettier@3.5.3: {} + prettier@3.8.1: {} - pretty-bytes@6.1.1: {} + pretty-bytes@7.1.0: {} pretty-ms@7.0.1: dependencies: parse-ms: 2.1.0 - pretty-ms@8.0.0: - dependencies: - parse-ms: 3.0.0 - - pretty-ms@9.2.0: + pretty-ms@9.3.0: dependencies: parse-ms: 4.0.0 - printable-characters@1.0.42: {} + process-warning@4.0.1: {} - process-nextick-args@2.0.1: {} - - process@0.11.10: {} + process-warning@5.0.0: {} prompts@2.4.2: dependencies: kleur: 3.0.3 sisteransi: 1.0.5 - property-information@6.5.0: {} + proper-lockfile@4.1.2: + dependencies: + graceful-fs: 4.2.11 + retry: 0.12.0 + signal-exit: 3.0.7 - property-information@7.0.0: {} + property-information@7.1.0: {} proto-list@1.2.4: {} - proto3-json-serializer@2.0.2: - dependencies: - protobufjs: 7.4.0 - optional: true - - protobufjs@7.4.0: - dependencies: - '@protobufjs/aspromise': 1.1.2 - '@protobufjs/base64': 1.1.2 - '@protobufjs/codegen': 2.0.4 - '@protobufjs/eventemitter': 1.1.0 - '@protobufjs/fetch': 1.1.0 - '@protobufjs/float': 1.0.2 - '@protobufjs/inquire': 1.1.0 - '@protobufjs/path': 1.1.2 - '@protobufjs/pool': 1.1.0 - '@protobufjs/utf8': 1.1.0 - '@types/node': 22.13.10 - long: 5.3.1 + protocols@2.0.2: {} proxy-addr@2.0.7: dependencies: @@ -11023,44 +12257,42 @@ snapshots: proxy-from-env@1.1.0: {} - pump@3.0.2: + pump@3.0.4: dependencies: - end-of-stream: 1.4.4 + end-of-stream: 1.4.5 once: 1.4.0 punycode@2.3.1: {} - pupa@3.1.0: + pupa@3.3.0: dependencies: escape-goat: 4.0.0 - qs@6.13.0: + qs@6.15.0: dependencies: side-channel: 1.1.0 - quansync@0.2.8: {} + quansync@0.2.11: {} - queue-microtask@1.2.3: {} + quick-format-unescaped@4.0.4: {} - radix-vue@1.9.17(vue@3.5.13(typescript@5.8.2)): + radix-vue@1.9.17(vue@3.5.30(typescript@5.9.3)): dependencies: - '@floating-ui/dom': 1.6.13 - '@floating-ui/vue': 1.1.6(vue@3.5.13(typescript@5.8.2)) - '@internationalized/date': 3.7.0 - '@internationalized/number': 3.6.0 - '@tanstack/vue-virtual': 3.13.2(vue@3.5.13(typescript@5.8.2)) - '@vueuse/core': 10.11.1(vue@3.5.13(typescript@5.8.2)) - '@vueuse/shared': 10.11.1(vue@3.5.13(typescript@5.8.2)) - aria-hidden: 1.2.4 + '@floating-ui/dom': 1.7.6 + '@floating-ui/vue': 1.1.9(vue@3.5.30(typescript@5.9.3)) + '@internationalized/date': 3.12.0 + '@internationalized/number': 3.6.5 + '@tanstack/vue-virtual': 3.13.22(vue@3.5.30(typescript@5.9.3)) + '@vueuse/core': 10.11.1(vue@3.5.30(typescript@5.9.3)) + '@vueuse/shared': 10.11.1(vue@3.5.30(typescript@5.9.3)) + aria-hidden: 1.2.6 defu: 6.1.4 fast-deep-equal: 3.1.3 - nanoid: 5.1.3 - vue: 3.5.13(typescript@5.8.2) + nanoid: 5.1.6 + vue: 3.5.30(typescript@5.9.3) transitivePeerDependencies: - '@vue/composition-api' - radix3@1.1.2: {} - railroad-diagrams@1.0.0: {} randexp@0.4.6: @@ -11068,23 +12300,24 @@ snapshots: discontinuous-range: 1.0.0 ret: 0.1.15 - randombytes@2.1.0: - dependencies: - safe-buffer: 5.2.1 - range-parser@1.2.1: {} - raw-body@2.5.2: + raw-body@3.0.2: dependencies: bytes: 3.1.2 - http-errors: 2.0.0 - iconv-lite: 0.4.24 + http-errors: 2.0.1 + iconv-lite: 0.7.2 unpipe: 1.0.0 rc9@2.1.2: dependencies: defu: 6.1.4 - destr: 2.0.3 + destr: 2.0.5 + + rc9@3.0.0: + dependencies: + defu: 6.1.4 + destr: 2.0.5 rc@1.2.8: dependencies: @@ -11093,28 +12326,14 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - read-pkg-up@7.0.1: + react-dom@19.2.4(react@19.2.4): dependencies: - find-up: 4.1.0 - read-pkg: 5.2.0 - type-fest: 0.8.1 + react: 19.2.4 + scheduler: 0.27.0 - read-pkg@5.2.0: - dependencies: - '@types/normalize-package-data': 2.4.4 - normalize-package-data: 2.5.0 - parse-json: 5.2.0 - type-fest: 0.6.0 + react-refresh@0.18.0: {} - readable-stream@2.3.8: - dependencies: - core-util-is: 1.0.3 - inherits: 2.0.4 - isarray: 1.0.0 - process-nextick-args: 2.0.1 - safe-buffer: 5.1.2 - string_decoder: 1.1.1 - util-deprecate: 1.0.2 + react@19.2.4: {} readable-stream@3.6.2: dependencies: @@ -11122,42 +12341,40 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 - readable-stream@4.7.0: + readdirp@3.6.0: dependencies: - abort-controller: 3.0.0 - buffer: 6.0.3 - events: 3.3.0 - process: 0.11.10 - string_decoder: 1.3.0 + picomatch: 2.3.1 - readdir-glob@1.1.3: - dependencies: - minimatch: 5.1.6 + readdirp@5.0.0: {} - readdirp@4.1.2: {} + real-require@0.2.0: {} - redis-errors@1.2.0: {} + recast@0.23.11: + dependencies: + ast-types: 0.16.1 + esprima: 4.0.1 + source-map: 0.6.1 + tiny-invariant: 1.3.3 + tslib: 2.8.1 - redis-parser@3.0.0: + regex-recursion@6.0.2: dependencies: - redis-errors: 1.2.0 + regex-utilities: 2.3.0 - regenerator-runtime@0.14.1: {} + regex-utilities@2.3.0: {} - regexp-tree@0.1.27: {} + regex@6.1.0: + dependencies: + regex-utilities: 2.3.0 - registry-auth-token@5.1.0: + registry-auth-token@5.1.1: dependencies: - '@pnpm/npm-conf': 2.3.1 + '@pnpm/npm-conf': 3.0.2 registry-url@6.0.1: dependencies: rc: 1.2.8 - regjsparser@0.10.0: - dependencies: - jsesc: 0.5.0 - rehype-external-links@3.0.0: dependencies: '@types/hast': 3.0.4 @@ -11165,7 +12382,7 @@ snapshots: hast-util-is-element: 3.0.0 is-absolute-url: 4.0.1 space-separated-tokens: 2.0.2 - unist-util-visit: 5.0.0 + unist-util-visit: 5.1.0 rehype-format@5.0.1: dependencies: @@ -11209,17 +12426,17 @@ snapshots: remark-parse@11.0.0: dependencies: '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 micromark-util-types: 2.0.2 unified: 11.0.5 transitivePeerDependencies: - supports-color - remark-rehype@11.1.1: + remark-rehype@11.1.2: dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 - mdast-util-to-hast: 13.2.0 + mdast-util-to-hast: 13.2.1 unified: 11.0.5 vfile: 6.0.3 @@ -11229,17 +12446,21 @@ snapshots: mdast-util-to-markdown: 2.1.2 unified: 11.0.5 + rendu@0.0.7: + dependencies: + srvx: 0.9.8 + require-directory@2.1.1: {} require-from-string@2.0.2: {} requires-port@1.0.0: {} - resolve-from@4.0.0: {} + reserved-identifiers@1.2.0: {} - resolve-from@5.0.0: {} + resolve-pkg-maps@1.0.0: {} - resolve@1.22.10: + resolve@1.22.11: dependencies: is-core-module: 2.16.1 path-parse: 1.0.7 @@ -11252,144 +12473,268 @@ snapshots: ret@0.1.15: {} - retry-request@7.0.2: - dependencies: - '@types/request': 2.48.12 - extend: 3.0.2 - teeny-request: 9.0.0 - transitivePeerDependencies: - - encoding - - supports-color - optional: true + ret@0.5.0: {} - retry@0.13.1: - optional: true + retry@0.12.0: {} reusify@1.1.0: {} + rfdc@1.4.1: {} + rimraf@2.7.1: dependencies: glob: 7.2.3 rimraf@5.0.10: dependencies: - glob: 10.4.5 + glob: 10.5.0 - rollup-plugin-dts@6.1.1(rollup@4.35.0)(typescript@5.8.2): + rolldown-plugin-dts@0.22.5(@typescript/native-preview@7.0.0-dev.20260314.1)(rolldown@1.0.0-rc.9)(typescript@5.9.3): dependencies: - magic-string: 0.30.17 - rollup: 4.35.0 - typescript: 5.8.2 + '@babel/generator': 8.0.0-rc.2 + '@babel/helper-validator-identifier': 8.0.0-rc.2 + '@babel/parser': 8.0.0-rc.2 + '@babel/types': 8.0.0-rc.2 + ast-kit: 3.0.0-beta.1 + birpc: 4.0.0 + dts-resolver: 2.1.3 + get-tsconfig: 4.13.6 + obug: 2.1.1 + rolldown: 1.0.0-rc.9 optionalDependencies: - '@babel/code-frame': 7.26.2 + '@typescript/native-preview': 7.0.0-dev.20260314.1 + typescript: 5.9.3 + transitivePeerDependencies: + - oxc-resolver - rollup-plugin-visualizer@5.14.0(rollup@4.35.0): + rolldown@1.0.0-rc.9: dependencies: - open: 8.4.2 - picomatch: 4.0.2 - source-map: 0.7.4 - yargs: 17.7.2 + '@oxc-project/types': 0.115.0 + '@rolldown/pluginutils': 1.0.0-rc.9 optionalDependencies: - rollup: 4.35.0 + '@rolldown/binding-android-arm64': 1.0.0-rc.9 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.9 + '@rolldown/binding-darwin-x64': 1.0.0-rc.9 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.9 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.9 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.9 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.9 + '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.9 + '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.9 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.9 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.9 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.9 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.9 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.9 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.9 + + rollup-plugin-license@3.7.0(picomatch@4.0.3)(rollup@4.59.0): + dependencies: + commenting: 1.1.0 + fdir: 6.5.0(picomatch@4.0.3) + lodash: 4.17.23 + magic-string: 0.30.21 + moment: 2.30.1 + package-name-regex: 2.0.6 + rollup: 4.59.0 + spdx-expression-validate: 2.0.0 + spdx-satisfies: 5.0.1 + transitivePeerDependencies: + - picomatch - rollup@4.35.0: + rollup@4.59.0: dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.35.0 - '@rollup/rollup-android-arm64': 4.35.0 - '@rollup/rollup-darwin-arm64': 4.35.0 - '@rollup/rollup-darwin-x64': 4.35.0 - '@rollup/rollup-freebsd-arm64': 4.35.0 - '@rollup/rollup-freebsd-x64': 4.35.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.35.0 - '@rollup/rollup-linux-arm-musleabihf': 4.35.0 - '@rollup/rollup-linux-arm64-gnu': 4.35.0 - '@rollup/rollup-linux-arm64-musl': 4.35.0 - '@rollup/rollup-linux-loongarch64-gnu': 4.35.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.35.0 - '@rollup/rollup-linux-riscv64-gnu': 4.35.0 - '@rollup/rollup-linux-s390x-gnu': 4.35.0 - '@rollup/rollup-linux-x64-gnu': 4.35.0 - '@rollup/rollup-linux-x64-musl': 4.35.0 - '@rollup/rollup-win32-arm64-msvc': 4.35.0 - '@rollup/rollup-win32-ia32-msvc': 4.35.0 - '@rollup/rollup-win32-x64-msvc': 4.35.0 + '@rollup/rollup-android-arm-eabi': 4.59.0 + '@rollup/rollup-android-arm64': 4.59.0 + '@rollup/rollup-darwin-arm64': 4.59.0 + '@rollup/rollup-darwin-x64': 4.59.0 + '@rollup/rollup-freebsd-arm64': 4.59.0 + '@rollup/rollup-freebsd-x64': 4.59.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.59.0 + '@rollup/rollup-linux-arm-musleabihf': 4.59.0 + '@rollup/rollup-linux-arm64-gnu': 4.59.0 + '@rollup/rollup-linux-arm64-musl': 4.59.0 + '@rollup/rollup-linux-loong64-gnu': 4.59.0 + '@rollup/rollup-linux-loong64-musl': 4.59.0 + '@rollup/rollup-linux-ppc64-gnu': 4.59.0 + '@rollup/rollup-linux-ppc64-musl': 4.59.0 + '@rollup/rollup-linux-riscv64-gnu': 4.59.0 + '@rollup/rollup-linux-riscv64-musl': 4.59.0 + '@rollup/rollup-linux-s390x-gnu': 4.59.0 + '@rollup/rollup-linux-x64-gnu': 4.59.0 + '@rollup/rollup-linux-x64-musl': 4.59.0 + '@rollup/rollup-openbsd-x64': 4.59.0 + '@rollup/rollup-openharmony-arm64': 4.59.0 + '@rollup/rollup-win32-arm64-msvc': 4.59.0 + '@rollup/rollup-win32-ia32-msvc': 4.59.0 + '@rollup/rollup-win32-x64-gnu': 4.59.0 + '@rollup/rollup-win32-x64-msvc': 4.59.0 fsevents: 2.3.3 - run-applescript@7.0.0: {} + rou3@0.8.1: {} - run-parallel@1.2.0: + router@2.2.0: dependencies: - queue-microtask: 1.2.3 + debug: 4.4.3 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.3.0 + transitivePeerDependencies: + - supports-color + + rsc-html-stream@0.0.7: {} + + run-applescript@7.1.0: {} rxjs@7.8.2: dependencies: tslib: 2.8.1 - safe-buffer@5.1.2: {} - safe-buffer@5.2.1: {} + safe-regex2@5.1.0: + dependencies: + ret: 0.5.0 + + safe-stable-stringify@2.5.0: {} + safer-buffer@2.1.2: {} - sax@1.4.1: {} + sax@1.5.0: {} + + scheduler@0.27.0: {} scule@1.3.0: {} + secure-json-parse@4.1.0: {} + selfsigned@2.4.1: dependencies: - '@types/node-forge': 1.3.11 - node-forge: 1.3.1 + '@types/node-forge': 1.3.14 + node-forge: 1.3.3 - semver@5.7.2: {} + semver@6.3.1: {} - semver@7.7.1: {} + semver@7.7.4: {} - send@0.19.0: + send@0.19.2: dependencies: debug: 2.6.9 depd: 2.0.0 destroy: 1.2.0 - encodeurl: 1.0.2 + encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 fresh: 0.5.2 - http-errors: 2.0.0 + http-errors: 2.0.1 mime: 1.6.0 ms: 2.1.3 on-finished: 2.4.1 range-parser: 1.2.1 - statuses: 2.0.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + send@1.2.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 transitivePeerDependencies: - supports-color - serialize-javascript@6.0.2: + seroval-plugins@1.5.1(seroval@1.5.1): dependencies: - randombytes: 2.1.0 + seroval: 1.5.1 + + seroval@1.5.1: {} serve-placeholder@2.0.2: dependencies: defu: 6.1.4 - serve-static@1.16.2: + serve-static@1.16.3: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.19.2 + transitivePeerDependencies: + - supports-color + + serve-static@2.2.1: dependencies: encodeurl: 2.0.0 escape-html: 1.0.3 parseurl: 1.3.3 - send: 0.19.0 + send: 1.2.1 transitivePeerDependencies: - supports-color + set-cookie-parser@2.7.2: {} + setprototypeof@1.2.0: {} + sharp@0.34.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.7.4 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 shebang-regex@3.0.0: {} - shell-quote@1.8.2: {} + shell-quote@1.8.3: {} + + shiki@3.23.0: + dependencies: + '@shikijs/core': 3.23.0 + '@shikijs/engine-javascript': 3.23.0 + '@shikijs/engine-oniguruma': 3.23.0 + '@shikijs/langs': 3.23.0 + '@shikijs/themes': 3.23.0 + '@shikijs/types': 3.23.0 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 side-channel-list@1.0.0: dependencies: @@ -11427,6 +12772,10 @@ snapshots: signal-exit@4.1.0: {} + simple-code-frame@1.3.0: + dependencies: + kolorist: 1.8.0 + simple-concat@1.0.1: {} simple-get@4.0.1: @@ -11437,72 +12786,85 @@ snapshots: sisteransi@1.0.5: {} - slash@5.1.0: {} - - smob@1.5.0: {} - smtp-address-parser@1.0.10: dependencies: nearley: 2.20.1 - source-map-js@1.2.1: {} + solid-js@1.9.11: + dependencies: + csstype: 3.2.3 + seroval: 1.5.1 + seroval-plugins: 1.5.1(seroval@1.5.1) - source-map-support@0.5.21: + solid-refresh@0.6.3(solid-js@1.9.11): dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 + '@babel/generator': 7.29.1 + '@babel/helper-module-imports': 7.28.6 + '@babel/types': 7.29.0 + solid-js: 1.9.11 + transitivePeerDependencies: + - supports-color + + sonic-boom@4.2.1: + dependencies: + atomic-sleep: 1.0.0 + + source-map-js@1.2.1: {} source-map@0.6.1: {} - source-map@0.7.4: {} + source-map@0.7.6: {} space-separated-tokens@2.0.2: {} spawn-command@0.0.2: {} - spdx-correct@3.2.0: + spdx-compare@1.0.0: dependencies: + array-find-index: 1.0.2 spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.21 + spdx-ranges: 2.1.1 spdx-exceptions@2.5.0: {} spdx-expression-parse@3.0.1: dependencies: spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.21 + spdx-license-ids: 3.0.23 - spdx-license-ids@3.0.21: {} + spdx-expression-validate@2.0.0: + dependencies: + spdx-expression-parse: 3.0.1 - stackback@0.0.2: {} + spdx-license-ids@3.0.23: {} - stacktracey@2.1.8: + spdx-ranges@2.1.1: {} + + spdx-satisfies@5.0.1: dependencies: - as-table: 1.0.55 - get-source: 2.0.12 + spdx-compare: 1.0.0 + spdx-expression-parse: 3.0.1 + spdx-ranges: 2.1.1 - standard-as-callback@2.1.0: {} + split2@4.2.0: {} - statuses@2.0.1: {} + srvx@0.11.9: {} - std-env@3.8.1: {} + srvx@0.9.8: {} - stoppable@1.1.0: {} + stack-trace@1.0.0-pre2: {} - stream-events@1.0.5: - dependencies: - stubs: 3.0.0 - optional: true + stackback@0.0.2: {} - stream-shift@1.0.3: - optional: true + statuses@2.0.2: {} - streamx@2.22.0: - dependencies: - fast-fifo: 1.3.2 - text-decoder: 1.2.3 - optionalDependencies: - bare-events: 2.5.4 + std-env@3.10.0: {} + + std-env@4.0.0: {} + + string-byte-length@3.0.1: {} + + string-byte-slice@3.0.1: {} string-width@4.2.3: dependencies: @@ -11514,17 +12876,13 @@ snapshots: dependencies: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 - strip-ansi: 7.1.0 + strip-ansi: 7.2.0 string-width@7.2.0: dependencies: - emoji-regex: 10.4.0 - get-east-asian-width: 1.3.0 - strip-ansi: 7.1.0 - - string_decoder@1.1.1: - dependencies: - safe-buffer: 5.1.2 + emoji-regex: 10.6.0 + get-east-asian-width: 1.5.0 + strip-ansi: 7.2.0 string_decoder@1.3.0: dependencies: @@ -11535,9 +12893,10 @@ snapshots: character-entities-html4: 2.1.0 character-entities-legacy: 3.0.0 - stringify-object@5.0.0: + stringify-object@6.0.0: dependencies: get-own-enumerable-keys: 1.0.0 + is-identifier: 1.0.1 is-obj: 3.0.0 is-regexp: 3.1.0 @@ -11545,47 +12904,41 @@ snapshots: dependencies: ansi-regex: 5.0.1 - strip-ansi@7.1.0: + strip-ansi@7.2.0: dependencies: - ansi-regex: 6.1.0 + ansi-regex: 6.2.2 strip-final-newline@2.0.0: {} - strip-final-newline@3.0.0: {} - strip-final-newline@4.0.0: {} - strip-indent@3.0.0: - dependencies: - min-indent: 1.0.1 - strip-json-comments@2.0.1: {} - strip-json-comments@3.1.1: {} - - strip-literal@3.0.0: + strip-literal@3.1.0: dependencies: js-tokens: 9.0.1 - strnum@1.1.2: - optional: true - - stubborn-fs@1.2.5: {} + strtok3@10.3.4: + dependencies: + '@tokenizer/token': 0.3.0 - stubs@3.0.0: - optional: true + stubborn-fs@2.0.0: + dependencies: + stubborn-utils: 1.0.2 - style-mod@4.1.2: {} + stubborn-utils@1.0.2: {} - stylehacks@7.0.4(postcss@8.5.3): - dependencies: - browserslist: 4.24.4 - postcss: 8.5.3 - postcss-selector-parser: 6.1.2 + style-mod@4.1.3: {} sudo-prompt@8.2.5: {} - supports-color@10.0.0: {} + super-regex@1.1.0: + dependencies: + function-timeout: 1.0.2 + make-asynchronous: 1.1.0 + time-span: 5.1.0 + + supports-color@10.2.2: {} supports-color@7.2.0: dependencies: @@ -11595,109 +12948,67 @@ snapshots: dependencies: has-flag: 4.0.0 - supports-color@9.4.0: {} - supports-preserve-symlinks-flag@1.0.0: {} - svgo@3.3.2: + swrv@1.1.0(vue@3.5.30(typescript@5.9.3)): dependencies: - '@trysound/sax': 0.2.0 - commander: 7.2.0 - css-select: 5.1.0 - css-tree: 2.3.1 - css-what: 6.1.0 - csso: 5.0.5 - picocolors: 1.1.1 + vue: 3.5.30(typescript@5.9.3) + + tabbable@6.4.0: {} - system-architecture@0.1.0: {} + tagged-tag@1.0.0: {} - tabbable@6.2.0: {} + tailwind-merge@3.4.0: {} - tailwind-merge@2.6.0: {} + tailwind-merge@3.5.0: {} - tailwindcss@4.0.12: {} + tailwindcss@4.2.1: {} - tar-fs@2.1.2: + tapable@2.3.0: {} + + tar-fs@2.1.4: dependencies: chownr: 1.1.4 mkdirp-classic: 0.5.3 - pump: 3.0.2 + pump: 3.0.4 tar-stream: 2.2.0 tar-stream@2.2.0: dependencies: bl: 4.1.0 - end-of-stream: 1.4.4 + end-of-stream: 1.4.5 fs-constants: 1.0.0 inherits: 2.0.4 readable-stream: 3.6.2 - tar-stream@3.1.7: - dependencies: - b4a: 1.6.7 - fast-fifo: 1.3.2 - streamx: 2.22.0 - - tar@7.4.3: - dependencies: - '@isaacs/fs-minipass': 4.0.1 - chownr: 3.0.0 - minipass: 7.1.2 - minizlib: 3.0.1 - mkdirp: 3.0.1 - yallist: 5.0.0 - - teeny-request@9.0.0: + thread-stream@4.0.0: dependencies: - http-proxy-agent: 5.0.0 - https-proxy-agent: 5.0.1 - node-fetch: 2.7.0 - stream-events: 1.0.5 - uuid: 9.0.1 - transitivePeerDependencies: - - encoding - - supports-color - optional: true + real-require: 0.2.0 - terser@5.39.0: + time-span@4.0.0: dependencies: - '@jridgewell/source-map': 0.3.6 - acorn: 8.14.1 - commander: 2.20.3 - source-map-support: 0.5.21 + convert-hrtime: 3.0.0 - test-exclude@7.0.1: + time-span@5.1.0: dependencies: - '@istanbuljs/schema': 0.1.3 - glob: 10.4.5 - minimatch: 9.0.5 + convert-hrtime: 5.0.0 - text-decoder@1.2.3: - dependencies: - b4a: 1.6.7 + tiny-invariant@1.3.3: {} - time-span@4.0.0: - dependencies: - convert-hrtime: 3.0.0 + tiny-warning@1.0.3: {} tinybench@2.9.0: {} - tinyexec@0.3.2: {} + tinyexec@1.0.4: {} - tinyglobby@0.2.12: + tinyglobby@0.2.15: dependencies: - fdir: 6.4.3(picomatch@4.0.2) - picomatch: 4.0.2 - - tinypool@1.0.2: {} + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 - tinyrainbow@2.0.0: {} + tinypool@2.1.0: {} - tinyspy@3.0.2: {} - - tippy.js@6.3.7: - dependencies: - '@popperjs/core': 2.11.8 + tinyrainbow@3.1.0: {} tmp@0.0.33: dependencies: @@ -11707,8 +13018,16 @@ snapshots: dependencies: is-number: 7.0.0 + toad-cache@3.7.0: {} + toidentifier@1.0.1: {} + token-types@6.1.2: + dependencies: + '@borewit/text-codec': 0.2.2 + '@tokenizer/token': 0.3.0 + ieee754: 1.2.1 + tr46@0.0.3: {} tree-kill@1.2.2: {} @@ -11717,117 +13036,81 @@ snapshots: trough@2.2.0: {} - ts-api-utils@2.0.1(typescript@5.8.2): + truncate-json@3.0.1: dependencies: - typescript: 5.8.2 + guess-json-indent: 3.0.1 + string-byte-length: 3.0.1 + string-byte-slice: 3.0.1 - ts-deepmerge@7.0.2: {} + ts-deepmerge@7.0.3: {} + + tsconfck@3.1.6(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 tslib@1.14.1: {} tslib@2.8.1: {} + tsx@4.21.0: + dependencies: + esbuild: 0.27.4 + get-tsconfig: 4.13.6 + optionalDependencies: + fsevents: 2.3.3 + tunnel-agent@0.6.0: dependencies: safe-buffer: 5.2.1 - type-check@0.4.0: - dependencies: - prelude-ls: 1.2.1 + turbo-stream@3.2.0: {} type-fest@0.21.3: {} - type-fest@0.6.0: {} - - type-fest@0.8.1: {} + type-fest@4.41.0: {} - type-fest@4.37.0: {} - - type-is@1.6.18: + type-fest@5.4.4: dependencies: - media-typer: 0.3.0 - mime-types: 2.1.35 + tagged-tag: 1.0.0 - typescript-eslint@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2): + type-is@2.0.1: dependencies: - '@typescript-eslint/eslint-plugin': 8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) - '@typescript-eslint/parser': 8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) - '@typescript-eslint/utils': 8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) - eslint: 9.22.0(jiti@2.4.2) - typescript: 5.8.2 - transitivePeerDependencies: - - supports-color + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.2 - typescript@5.8.2: {} + typescript@5.9.3: {} - ufo@1.5.4: {} + ufo@1.6.3: {} - ultrahtml@1.5.3: {} + uint8array-extras@1.5.0: {} - unbuild@3.5.0(typescript@5.8.2)(vue@3.5.13(typescript@5.8.2)): - dependencies: - '@rollup/plugin-alias': 5.1.1(rollup@4.35.0) - '@rollup/plugin-commonjs': 28.0.3(rollup@4.35.0) - '@rollup/plugin-json': 6.1.0(rollup@4.35.0) - '@rollup/plugin-node-resolve': 16.0.0(rollup@4.35.0) - '@rollup/plugin-replace': 6.0.2(rollup@4.35.0) - '@rollup/pluginutils': 5.1.4(rollup@4.35.0) - citty: 0.1.6 - consola: 3.4.0 - defu: 6.1.4 - esbuild: 0.25.0 - fix-dts-default-cjs-exports: 1.0.0 - hookable: 5.5.3 - jiti: 2.4.2 - magic-string: 0.30.17 - mkdist: 2.2.0(typescript@5.8.2)(vue@3.5.13(typescript@5.8.2)) - mlly: 1.7.4 - pathe: 2.0.3 - pkg-types: 2.1.0 - pretty-bytes: 6.1.1 - rollup: 4.35.0 - rollup-plugin-dts: 6.1.1(rollup@4.35.0)(typescript@5.8.2) - scule: 1.3.0 - tinyglobby: 0.2.12 - untyped: 2.0.0 - optionalDependencies: - typescript: 5.8.2 - transitivePeerDependencies: - - sass - - vue - - vue-tsc + ultrahtml@1.6.0: {} uncrypto@0.1.3: {} - unctx@2.4.1: + unctx@2.5.0: dependencies: - acorn: 8.14.1 + acorn: 8.16.0 estree-walker: 3.0.3 - magic-string: 0.30.17 - unplugin: 2.2.0 + magic-string: 0.30.21 + unplugin: 2.3.11 - undici-types@6.20.0: {} + undici-types@7.16.0: {} - undici@5.28.5: - dependencies: - '@fastify/busboy': 2.1.1 + undici-types@7.18.2: {} - undici@7.4.0: {} + undici@7.18.2: {} - unenv@2.0.0-rc.14: + undici@7.24.3: {} + + unenv@2.0.0-rc.24: dependencies: - defu: 6.1.4 - exsolve: 1.0.4 - ohash: 2.0.11 pathe: 2.0.3 - ufo: 1.5.4 - unhead@1.11.20: + unhead@2.1.12: dependencies: - '@unhead/dom': 1.11.20 - '@unhead/schema': 1.11.20 - '@unhead/shared': 1.11.20 - hookable: 5.5.3 + hookable: 6.0.1 unicorn-magic@0.3.0: {} @@ -11841,29 +13124,29 @@ snapshots: trough: 2.2.0 vfile: 6.0.3 - unimport@4.1.2: + unimport@6.0.1: dependencies: - acorn: 8.14.1 + acorn: 8.16.0 escape-string-regexp: 5.0.0 estree-walker: 3.0.3 - local-pkg: 1.1.1 - magic-string: 0.30.17 - mlly: 1.7.4 + local-pkg: 1.1.2 + magic-string: 0.30.21 + mlly: 1.8.1 pathe: 2.0.3 - picomatch: 4.0.2 - pkg-types: 1.3.1 + picomatch: 4.0.3 + pkg-types: 2.3.0 scule: 1.3.0 - strip-literal: 3.0.0 - tinyglobby: 0.2.12 - unplugin: 2.2.0 - unplugin-utils: 0.2.4 + strip-literal: 3.1.0 + tinyglobby: 0.2.15 + unplugin: 3.0.0 + unplugin-utils: 0.3.1 unist-util-find-after@5.0.0: dependencies: '@types/unist': 3.0.3 - unist-util-is: 6.0.0 + unist-util-is: 6.0.1 - unist-util-is@6.0.0: + unist-util-is@6.0.1: dependencies: '@types/unist': 3.0.3 @@ -11871,128 +13154,96 @@ snapshots: dependencies: '@types/unist': 3.0.3 - unist-util-stringify-position@2.0.3: - dependencies: - '@types/unist': 2.0.11 - unist-util-stringify-position@4.0.0: dependencies: '@types/unist': 3.0.3 - unist-util-visit-parents@6.0.1: + unist-util-visit-parents@6.0.2: dependencies: '@types/unist': 3.0.3 - unist-util-is: 6.0.0 + unist-util-is: 6.0.1 - unist-util-visit@5.0.0: + unist-util-visit@5.1.0: dependencies: '@types/unist': 3.0.3 - unist-util-is: 6.0.0 - unist-util-visit-parents: 6.0.1 - - universalify@2.0.1: {} + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 unpipe@1.0.0: {} - unplugin-utils@0.2.4: + unplugin-utils@0.3.1: dependencies: pathe: 2.0.3 - picomatch: 4.0.2 + picomatch: 4.0.3 - unplugin@1.16.1: + unplugin@2.3.11: dependencies: - acorn: 8.14.1 + '@jridgewell/remapping': 2.3.5 + acorn: 8.16.0 + picomatch: 4.0.3 webpack-virtual-modules: 0.6.2 - unplugin@2.2.0: + unplugin@3.0.0: dependencies: - acorn: 8.14.1 + '@jridgewell/remapping': 2.3.5 + picomatch: 4.0.3 webpack-virtual-modules: 0.6.2 - unstorage@1.15.0(@azure/identity@4.7.0)(db0@0.3.1)(ioredis@5.6.0): - dependencies: - anymatch: 3.1.3 - chokidar: 4.0.3 - destr: 2.0.3 - h3: 1.15.1 - lru-cache: 10.4.3 - node-fetch-native: 1.6.6 - ofetch: 1.4.1 - ufo: 1.5.4 + unstorage@2.0.0-alpha.6(@azure/identity@4.13.0)(chokidar@5.0.0)(db0@0.3.4)(ofetch@2.0.0-alpha.3): optionalDependencies: - '@azure/identity': 4.7.0 - db0: 0.3.1 - ioredis: 5.6.0 - - untun@0.1.3: - dependencies: - citty: 0.1.6 - consola: 3.4.0 - pathe: 1.1.2 + '@azure/identity': 4.13.0 + chokidar: 5.0.0 + db0: 0.3.4 + ofetch: 2.0.0-alpha.3 untyped@2.0.0: dependencies: citty: 0.1.6 defu: 6.1.4 - jiti: 2.4.2 - knitwork: 1.2.0 + jiti: 2.6.1 + knitwork: 1.3.0 scule: 1.3.0 - unwasm@0.3.9: + unwasm@0.5.3: dependencies: - knitwork: 1.2.0 - magic-string: 0.30.17 - mlly: 1.7.4 - pathe: 1.1.2 - pkg-types: 1.3.1 - unplugin: 1.16.1 + exsolve: 1.0.8 + knitwork: 1.3.0 + magic-string: 0.30.21 + mlly: 1.8.1 + pathe: 2.0.3 + pkg-types: 2.3.0 - update-browserslist-db@1.1.3(browserslist@4.24.4): + update-browserslist-db@1.2.3(browserslist@4.28.1): dependencies: - browserslist: 4.24.4 + browserslist: 4.28.1 escalade: 3.2.0 picocolors: 1.1.1 update-notifier@7.3.1: dependencies: boxen: 8.0.1 - chalk: 5.4.1 - configstore: 7.0.0 + chalk: 5.6.2 + configstore: 7.1.0 is-in-ci: 1.0.0 is-installed-globally: 1.0.0 - is-npm: 6.0.0 + is-npm: 6.1.0 latest-version: 9.0.0 - pupa: 3.1.0 - semver: 7.7.1 + pupa: 3.3.0 + semver: 7.7.4 xdg-basedir: 5.1.0 - uqr@0.1.2: {} - - uri-js-replace@1.0.1: {} - - uri-js@4.4.1: + use-sync-external-store@1.6.0(react@19.2.4): dependencies: - punycode: 2.3.1 - - urlpattern-polyfill@8.0.2: {} + react: 19.2.4 util-deprecate@1.0.2: {} - utils-merge@1.0.1: {} - - uuid@10.0.0: {} + uuid@11.1.0: {} uuid@8.3.2: {} - uuid@9.0.1: {} - valid-url@1.0.9: {} - validate-npm-package-license@3.0.4: - dependencies: - spdx-correct: 3.2.0 - spdx-expression-parse: 3.0.1 - vary@1.1.2: {} vfile-location@5.0.3: @@ -12000,7 +13251,7 @@ snapshots: '@types/unist': 3.0.3 vfile: 6.0.3 - vfile-message@4.0.2: + vfile-message@4.0.3: dependencies: '@types/unist': 3.0.3 unist-util-stringify-position: 4.0.0 @@ -12008,109 +13259,163 @@ snapshots: vfile@6.0.3: dependencies: '@types/unist': 3.0.3 - vfile-message: 4.0.2 + vfile-message: 4.0.3 - vite-node@3.0.8(@types/node@22.13.10)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.0): + vite-plugin-devtools-json@1.0.0(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)): dependencies: - cac: 6.7.14 - debug: 4.4.0(supports-color@9.4.0) - es-module-lexer: 1.6.0 - pathe: 2.0.3 - vite: 6.2.1(@types/node@22.13.10)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.0) + uuid: 11.1.0 + vite: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + + vite-plugin-monaco-editor@1.1.0(monaco-editor@0.54.0): + dependencies: + monaco-editor: 0.54.0 + + vite-plugin-solid@2.11.11(solid-js@1.9.11)(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)): + dependencies: + '@babel/core': 7.29.0 + '@types/babel__core': 7.20.5 + babel-preset-solid: 1.9.10(@babel/core@7.29.0)(solid-js@1.9.11) + merge-anything: 5.1.7 + solid-js: 1.9.11 + solid-refresh: 0.6.3(solid-js@1.9.11) + vite: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + vitefu: 1.1.2(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) + transitivePeerDependencies: + - supports-color + + vite-prerender-plugin@0.5.12(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)): + dependencies: + kolorist: 1.8.0 + magic-string: 0.30.21 + node-html-parser: 6.1.13 + simple-code-frame: 1.3.0 + source-map: 0.7.6 + stack-trace: 1.0.0-pre2 + vite: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + + vite-tsconfig-paths@6.1.1(typescript@5.9.3)(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)): + dependencies: + debug: 4.4.3 + globrex: 0.1.2 + tsconfck: 3.1.6(typescript@5.9.3) + vite: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - - '@types/node' - - jiti - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - supports-color - - terser - - tsx - - yaml + - typescript - vite@6.2.1(@types/node@22.13.10)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.0): + vite@7.3.1(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.2): dependencies: - esbuild: 0.25.0 - postcss: 8.5.3 - rollup: 4.35.0 + esbuild: 0.27.4 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.8 + rollup: 4.59.0 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 25.5.0 + fsevents: 2.3.3 + jiti: 2.6.1 + lightningcss: 1.32.0 + tsx: 4.21.0 + yaml: 2.8.2 + + vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2): + dependencies: + '@oxc-project/runtime': 0.115.0 + lightningcss: 1.32.0 + picomatch: 4.0.3 + postcss: 8.5.8 + rolldown: 1.0.0-rc.9 + tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 22.13.10 + '@types/node': 25.5.0 + esbuild: 0.27.4 fsevents: 2.3.3 - jiti: 2.4.2 - terser: 5.39.0 - yaml: 2.7.0 - - vitest@3.0.8(@edge-runtime/vm@5.0.0)(@types/debug@4.1.12)(@types/node@22.13.10)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.0): - dependencies: - '@vitest/expect': 3.0.8 - '@vitest/mocker': 3.0.8(vite@6.2.1(@types/node@22.13.10)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.0)) - '@vitest/pretty-format': 3.0.8 - '@vitest/runner': 3.0.8 - '@vitest/snapshot': 3.0.8 - '@vitest/spy': 3.0.8 - '@vitest/utils': 3.0.8 - chai: 5.2.0 - debug: 4.4.0(supports-color@9.4.0) - expect-type: 1.2.0 - magic-string: 0.30.17 + jiti: 2.6.1 + tsx: 4.21.0 + yaml: 2.8.2 + + vitefu@1.1.2(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)): + optionalDependencies: + vite: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + + vitest@4.1.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@25.5.0)(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)): + dependencies: + '@vitest/expect': 4.1.0 + '@vitest/mocker': 4.1.0(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) + '@vitest/pretty-format': 4.1.0 + '@vitest/runner': 4.1.0 + '@vitest/snapshot': 4.1.0 + '@vitest/spy': 4.1.0 + '@vitest/utils': 4.1.0 + es-module-lexer: 2.0.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 pathe: 2.0.3 - std-env: 3.8.1 + picomatch: 4.0.3 + std-env: 4.0.0 tinybench: 2.9.0 - tinyexec: 0.3.2 - tinypool: 1.0.2 - tinyrainbow: 2.0.0 - vite: 6.2.1(@types/node@22.13.10)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.0) - vite-node: 3.0.8(@types/node@22.13.10)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.0) + tinyexec: 1.0.4 + tinyglobby: 0.2.15 + tinyrainbow: 3.1.0 + vite: 8.0.0(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) why-is-node-running: 2.3.0 optionalDependencies: '@edge-runtime/vm': 5.0.0 - '@types/debug': 4.1.12 - '@types/node': 22.13.10 + '@opentelemetry/api': 1.9.0 + '@types/node': 25.5.0 transitivePeerDependencies: - - jiti - - less - - lightningcss - msw - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - vue-demi@0.14.10(vue@3.5.13(typescript@5.8.2)): + vscode-jsonrpc@8.2.0: {} + + vscode-languageserver-protocol@3.17.5: + dependencies: + vscode-jsonrpc: 8.2.0 + vscode-languageserver-types: 3.17.5 + + vscode-languageserver-textdocument@1.0.12: {} + + vscode-languageserver-types@3.17.5: {} + + vscode-uri@3.1.0: {} + + vue-component-type-helpers@3.2.5: {} + + vue-demi@0.14.10(vue@3.5.30(typescript@5.9.3)): + dependencies: + vue: 3.5.30(typescript@5.9.3) + + vue-router@4.6.2(vue@3.5.30(typescript@5.9.3)): dependencies: - vue: 3.5.13(typescript@5.8.2) + '@vue/devtools-api': 6.6.4 + vue: 3.5.30(typescript@5.9.3) - vue-router@4.5.0(vue@3.5.13(typescript@5.8.2)): + vue-router@4.6.4(vue@3.5.30(typescript@5.9.3)): dependencies: '@vue/devtools-api': 6.6.4 - vue: 3.5.13(typescript@5.8.2) + vue: 3.5.30(typescript@5.9.3) - vue-sonner@1.3.0: {} + vue-sonner@1.3.2: {} - vue@3.5.13(typescript@5.8.2): + vue@3.5.30(typescript@5.9.3): dependencies: - '@vue/compiler-dom': 3.5.13 - '@vue/compiler-sfc': 3.5.13 - '@vue/runtime-dom': 3.5.13 - '@vue/server-renderer': 3.5.13(vue@3.5.13(typescript@5.8.2)) - '@vue/shared': 3.5.13 + '@vue/compiler-dom': 3.5.30 + '@vue/compiler-sfc': 3.5.30 + '@vue/runtime-dom': 3.5.30 + '@vue/server-renderer': 3.5.30(vue@3.5.30(typescript@5.9.3)) + '@vue/shared': 3.5.30 optionalDependencies: - typescript: 5.8.2 + typescript: 5.9.3 w3c-keyname@2.2.8: {} wait-on@7.2.0: dependencies: - axios: 1.8.2 + axios: 1.13.6(debug@4.4.3) joi: 17.13.3 - lodash: 4.17.21 + lodash: 4.17.23 minimist: 1.2.8 rxjs: 7.8.2 transitivePeerDependencies: @@ -12122,17 +13427,15 @@ snapshots: web-namespaces@2.0.1: {} + web-worker@1.5.0: {} + webidl-conversions@3.0.1: {} webpack-virtual-modules@0.6.2: {} - websocket-driver@0.7.4: + whatwg-encoding@3.1.1: dependencies: - http-parser-js: 0.5.9 - safe-buffer: 5.2.1 - websocket-extensions: 0.1.4 - - websocket-extensions@0.1.4: {} + iconv-lite: 0.6.3 whatwg-mimetype@4.0.0: {} @@ -12141,7 +13444,7 @@ snapshots: tr46: 0.0.3 webidl-conversions: 3.0.1 - when-exit@2.1.4: {} + when-exit@2.1.5: {} which@2.0.2: dependencies: @@ -12156,15 +13459,30 @@ snapshots: dependencies: string-width: 7.2.0 - word-wrap@1.2.5: {} - - workerd@1.20250224.0: + workerd@1.20260312.1: + optionalDependencies: + '@cloudflare/workerd-darwin-64': 1.20260312.1 + '@cloudflare/workerd-darwin-arm64': 1.20260312.1 + '@cloudflare/workerd-linux-64': 1.20260312.1 + '@cloudflare/workerd-linux-arm64': 1.20260312.1 + '@cloudflare/workerd-windows-64': 1.20260312.1 + + wrangler@4.73.0(@cloudflare/workers-types@4.20260313.1): + dependencies: + '@cloudflare/kv-asset-handler': 0.4.2 + '@cloudflare/unenv-preset': 2.15.0(unenv@2.0.0-rc.24)(workerd@1.20260312.1) + blake3-wasm: 2.1.5 + esbuild: 0.27.3 + miniflare: 4.20260312.0 + path-to-regexp: 6.3.0 + unenv: 2.0.0-rc.24 + workerd: 1.20260312.1 optionalDependencies: - '@cloudflare/workerd-darwin-64': 1.20250224.0 - '@cloudflare/workerd-darwin-arm64': 1.20250224.0 - '@cloudflare/workerd-linux-64': 1.20250224.0 - '@cloudflare/workerd-linux-arm64': 1.20250224.0 - '@cloudflare/workerd-windows-64': 1.20250224.0 + '@cloudflare/workers-types': 4.20260313.1 + fsevents: 2.3.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate wrap-ansi@7.0.0: dependencies: @@ -12174,38 +13492,45 @@ snapshots: wrap-ansi@8.1.0: dependencies: - ansi-styles: 6.2.1 + ansi-styles: 6.2.3 string-width: 5.1.2 - strip-ansi: 7.1.0 + strip-ansi: 7.2.0 - wrap-ansi@9.0.0: + wrap-ansi@9.0.2: dependencies: - ansi-styles: 6.2.1 + ansi-styles: 6.2.3 string-width: 7.2.0 - strip-ansi: 7.1.0 + strip-ansi: 7.2.0 wrappy@1.0.2: {} ws@8.18.0: {} + wsl-utils@0.1.0: + dependencies: + is-wsl: 3.1.1 + xdg-basedir@5.1.0: {} xml2js@0.6.2: dependencies: - sax: 1.4.1 + sax: 1.5.0 xmlbuilder: 11.0.1 + xmlbuilder2@4.0.3: + dependencies: + '@oozcitak/dom': 2.0.2 + '@oozcitak/infra': 2.0.2 + '@oozcitak/util': 10.0.0 + js-yaml: 4.1.1 + xmlbuilder@11.0.1: {} y18n@5.0.8: {} - yallist@4.0.0: {} - - yallist@5.0.0: {} - - yaml-ast-parser@0.0.43: {} + yallist@3.1.1: {} - yaml@2.7.0: {} + yaml@2.8.2: {} yargs-parser@21.1.1: {} @@ -12221,36 +13546,56 @@ snapshots: yocto-queue@0.1.0: {} - yoctocolors@2.1.1: {} + yoctocolors@2.1.2: {} - youch-core@0.3.2: + youch-core@0.3.3: dependencies: - '@poppinss/exception': 1.2.1 + '@poppinss/exception': 1.2.3 error-stack-parser-es: 1.0.5 - youch@3.2.3: - dependencies: - cookie: 0.5.0 - mustache: 4.2.0 - stacktracey: 2.1.8 + youch@4.1.0: + dependencies: + '@poppinss/colors': 4.1.6 + '@poppinss/dumper': 0.7.0 + '@speed-highlight/core': 1.2.14 + cookie-es: 2.0.0 + youch-core: 0.3.3 + + youch@4.1.0-beta.10: + dependencies: + '@poppinss/colors': 4.1.6 + '@poppinss/dumper': 0.6.5 + '@speed-highlight/core': 1.2.14 + cookie: 1.1.1 + youch-core: 0.3.3 + + zephyr-agent@0.1.15(https-proxy-agent@7.0.6): + dependencies: + '@toon-format/toon': 0.9.0 + axios: 1.13.6(debug@4.4.3) + axios-retry: 4.5.0(axios@1.13.6(debug@4.4.3)) + debug: 4.4.3 + eventsource: 4.1.0 + git-url-parse: 15.0.0 + https-proxy-agent: 7.0.6 + is-ci: 4.1.0 + jose: 5.10.0 + node-persist: 4.0.4 + open: 10.2.0 + proper-lockfile: 4.1.2 + tslib: 2.8.1 + zephyr-edge-contract: 0.1.15 + transitivePeerDependencies: + - supports-color - youch@4.1.0-beta.6: + zephyr-edge-contract@0.1.15: dependencies: - '@poppinss/dumper': 0.6.3 - '@speed-highlight/core': 1.2.7 - cookie: 1.0.2 - youch-core: 0.3.2 - - zhead@2.2.4: {} + tslib: 2.8.1 - zip-stream@6.0.1: - dependencies: - archiver-utils: 5.0.2 - compress-commons: 6.0.2 - readable-stream: 4.7.0 + zimmerframe@1.1.4: {} - zod@3.22.3: {} + zod@3.25.76: {} - zod@3.24.2: {} + zod@4.3.6: {} zwitch@2.0.4: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index c8506e68dc..76e0abfc92 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,2 +1,40 @@ packages: - - "examples/**" + - examples/** + - playground + - test/fixture + - test/minimal + +ignoreWorkspaceRootCheck: true + +ignoredBuiltDependencies: + - keytar + - protobufjs + - vue-demi + +onlyBuiltDependencies: + - '@parcel/watcher' + - esbuild + - ocache + - sharp + - workerd + +peerDependencyRules: + ignoreMissing: + - react + - '@types/react' + - react-dom + - '@algolia/client-search' + +shellEmulator: true + +# typescript-eslint is affected by +# https://github.com/pnpm/pnpm/issues/10329 +# trustPolicy: no-downgrade + +trustPolicyExclude: + - chokidar@4.0.3 + - tailwind-merge@2.6.0 + - '@headlessui/vue@1.7.23' + - undici-types@6.21.0 + - rxjs@7.8.2 + - semver@6.3.1 diff --git a/renovate.json b/renovate.json index 57fe916b5c..d89f08b04e 100644 --- a/renovate.json +++ b/renovate.json @@ -1,3 +1,4 @@ { - "extends": ["github>unjs/renovate-config"] + "extends": ["github>unjs/renovate-config"], + "baseBranchPatterns": ["main"] } diff --git a/runtime-meta.d.ts b/runtime-meta.d.ts deleted file mode 100644 index 960d7d4b8d..0000000000 --- a/runtime-meta.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -export declare const pkgDir: string; -export declare const runtimeDir: string; -export declare const subpaths: string[]; -export declare const runtimeDependencies: string[]; diff --git a/runtime-meta.mjs b/runtime-meta.mjs deleted file mode 100644 index 3a29883ab7..0000000000 --- a/runtime-meta.mjs +++ /dev/null @@ -1,33 +0,0 @@ -import { fileURLToPath } from "node:url"; - -export const pkgDir = fileURLToPath(new URL(".", import.meta.url)); - -export const runtimeDir = fileURLToPath( - new URL("dist/runtime/", import.meta.url) -); - -export const runtimeDependencies = [ - "h3", - "cookie-es", - "defu", - "destr", - "hookable", - "iron-webcrypto", - "klona", - "node-fetch-native", - "node-mock-http", - "ofetch", - "ohash", - "pathe", - "radix3", - "scule", - "ufo", - "db0", - "std-env", - "uncrypto", - "unctx", - "unenv", - "unstorage", - "crossws", - "croner", -]; diff --git a/scripts/bump-nightly.ts b/scripts/bump-nightly.ts index 1ed82369b1..233b016f98 100755 --- a/scripts/bump-nightly.ts +++ b/scripts/bump-nightly.ts @@ -1,19 +1,16 @@ import { promises as fsp } from "node:fs"; import { execaCommand } from "execa"; -import { globby } from "globby"; +import { glob } from "tinyglobby"; import { resolve } from "pathe"; const nightlyPackages = { - h3: "h3-nightly", + // h3: "h3-nightly", } as Record; async function loadPackage(dir: string) { const pkgPath = resolve(dir, "package.json"); - const data = JSON.parse( - await fsp.readFile(pkgPath, "utf8").catch(() => "{}") - ); - const save = () => - fsp.writeFile(pkgPath, JSON.stringify(data, null, 2) + "\n"); + const data = JSON.parse(await fsp.readFile(pkgPath, "utf8").catch(() => "{}")); + const save = () => fsp.writeFile(pkgPath, JSON.stringify(data, null, 2) + "\n"); const updateDeps = (reviver: (dep: any) => any) => { for (const type of [ @@ -48,7 +45,7 @@ type Package = ThenArg>; async function loadWorkspace(dir: string) { const workspacePkg = await loadPackage(dir); - const pkgDirs = await globby(workspacePkg.data.workspaces || [], { + const pkgDirs = await glob(workspacePkg.data.workspaces || [], { onlyDirectories: true, }); @@ -119,15 +116,10 @@ function joinNumbers(items: number[]): string { async function main() { const workspace = await loadWorkspace(process.cwd()); - const commit = await execaCommand("git rev-parse --short HEAD").then((r) => - r.stdout.trim() - ); + const commit = await execaCommand("git rev-parse --short HEAD").then((r) => r.stdout.trim()); for (const pkg of workspace.packages.filter((p) => !p.data.private)) { - workspace.setVersion( - pkg.data.name, - `${pkg.data.version}-${fmtDate(new Date())}.${commit}` - ); + workspace.setVersion(pkg.data.name, `${pkg.data.version}-${fmtDate(new Date())}.${commit}`); workspace.rename(pkg.data.name, pkg.data.name + "-nightly"); pkg.updateDeps((dep) => { if (nightlyPackages[dep.name]) { diff --git a/scripts/bump-version.ts b/scripts/bump-version.ts new file mode 100755 index 0000000000..314fc3e82c --- /dev/null +++ b/scripts/bump-version.ts @@ -0,0 +1,94 @@ +#!/bin/env node +import { promises as fsp } from "node:fs"; +import { resolve } from "pathe"; + +const c = { + cyan: (s: string) => `\x1B[36m${s}\x1B[0m`, + green: (s: string) => `\x1B[32m${s}\x1B[0m`, + yellow: (s: string) => `\x1B[33m${s}\x1B[0m`, + gray: (s: string) => `\x1B[90m${s}\x1B[0m`, + red: (s: string) => `\x1B[31m${s}\x1B[0m`, + bold: (s: string) => `\x1B[1m${s}\x1B[0m`, +}; + +export function fmtDate(d: Date): string { + const y = d.getFullYear() % 100; + const m = (d.getMonth() + 1).toString().padStart(2, "0"); + const day = d.getDate().toString().padStart(2, "0"); + return `${y}${m}${day}`; +} + +async function fetchExistingVersions(pkgName: string): Promise { + const url = `https://registry.npmjs.org/${pkgName}`; + console.log(c.gray(`Fetching versions from npm registry for ${c.cyan(pkgName)}...`)); + try { + const res = await fetch(url); + if (!res.ok) { + console.log(c.yellow(` Registry returned ${res.status}, assuming first release`)); + return []; + } + const data = (await res.json()) as { versions?: Record }; + const versions = Object.keys(data.versions || {}); + return versions; + } catch (err) { + console.log(c.yellow(` Failed to fetch registry: ${err}`)); + return []; + } +} + +export async function resolveVersion( + pkgName: string, + dateStr: string, + prerelease = "beta" +): Promise { + const versions = await fetchExistingVersions(pkgName); + const base = `3.0.${dateStr}`; + const prefix = prerelease ? `${base}-${prerelease}` : base; + const matching = versions.filter((v) => v.startsWith(prefix)); + + const sep = prerelease ? "." : "-"; + let max = 0; + for (const v of matching) { + const rest = v.slice(prefix.length); + if (rest === "") { + max = Math.max(max, 1); + } else if (rest.startsWith(sep)) { + const n = Number.parseInt(rest.slice(1), 10); + if (!Number.isNaN(n)) { + max = Math.max(max, n); + } + } + } + + const version = max === 0 ? prefix : `${prefix}${sep}${max + 1}`; + console.log(c.gray(` Resolved version: ${c.cyan(version)}`)); + return version; +} + +async function main() { + console.log(c.bold("\nBump version to beta\n")); + + const pkgPath = resolve(process.cwd(), "package.json"); + const pkg = JSON.parse(await fsp.readFile(pkgPath, "utf8")); + const oldVersion = pkg.version; + + const dateStr = fmtDate(new Date()); + console.log(c.gray(`Date: ${c.cyan(dateStr)}`)); + + const newVersion = await resolveVersion(pkg.name, dateStr); + + console.log(); + console.log(` ${c.cyan(pkg.name)} ${c.gray(oldVersion)} → ${c.green(newVersion)}`); + + pkg.version = newVersion; + await fsp.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n"); + + console.log(c.green(`\nDone!\n`)); +} + +if (process.argv[1] && import.meta.url.endsWith(process.argv[1])) { + main().catch((error) => { + console.error(c.red(`\nError: ${error.message}\n`)); + process.exit(1); + }); +} diff --git a/scripts/gen-mirror.ts b/scripts/gen-mirror.ts deleted file mode 100644 index 683eba4807..0000000000 --- a/scripts/gen-mirror.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { cp, mkdir, rm, writeFile } from "node:fs/promises"; -import { fileURLToPath } from "mlly"; -import { join } from "pathe"; -import { type PackageJson, readPackageJSON } from "pkg-types"; -import { subpaths } from "../build.config"; - -const copyPkgFields = [ - "description", - "keywords", - "repository", - "license", - "type", - "exports", - "main", - "types", - "bin", - "files", -]; - -const copyFiles = ["README.md", "LICENSE"]; - -async function main() { - // Dirs - const mainDir = fileURLToPath(new URL("..", import.meta.url)); - const mirrorDir = fileURLToPath(new URL("../.mirror", import.meta.url)); - await rm(mirrorDir, { recursive: true }).catch(() => {}); - await mkdir(mirrorDir, { recursive: true }); - - // Read main package - const mainPkg = await readPackageJSON(mainDir); - - // Check for nightly - const isNightly = mainPkg.name!.includes("nightly"); - - // Mirror nitro<>nitropack - const mirrrorPkgName = mainPkg.name!.includes("pack") - ? mainPkg.name!.replace("pack", "") - : mainPkg.name!.replace("nitro", "nitropack"); - - // Canonical name for main pkg (without -nightly suffix) - const canonicalName = mainPkg.name!.replace("-nightly", ""); - - // Copy package.json fields - const mirrorPkg: PackageJson = { - name: mirrrorPkgName, - version: `${mainPkg.version}-${mainPkg.name}-mirror`, - dependencies: {}, - }; - - // Add dependency - if (isNightly) { - mirrorPkg.dependencies![canonicalName] = - `npm:${mainPkg.name}@${mainPkg.version}`; - } else { - mirrorPkg.dependencies![canonicalName] = `${mainPkg.version}`; - } - - for (const field of copyPkgFields) { - if (mainPkg[field]) { - mirrorPkg[field] = mainPkg[field]; - } - } - await writeFile( - join(mirrorDir, "package.json"), - JSON.stringify(mirrorPkg, null, 2) - ); - - // Generate subpath re-exports - for (const subpath of subpaths) { - await mkdir(join(mirrorDir, "dist", subpath), { recursive: true }); - await writeFile( - join(mirrorDir, "dist", subpath, "index.mjs"), - `export * from "${canonicalName}/${subpath}";` - ); - await writeFile( - join(mirrorDir, "dist", subpath, "index.d.ts"), - `export * from "${canonicalName}/${subpath}";` - ); - await writeFile( - join(mirrorDir, "dist", subpath, "index.d.mts"), - `export * from "${canonicalName}/${subpath}";` - ); - await writeFile( - join(mirrorDir, `${subpath}.d.ts`), - `export * from "./dist/${subpath}";` - ); - } - - // Runtime Meta - await writeFile( - join(mirrorDir, "runtime-meta.mjs"), - `export * from "${canonicalName}/runtime/meta";` - ); - await writeFile( - join(mirrorDir, "runtime-meta.d.ts"), - `export * from "${canonicalName}/runtime/meta";` - ); - - // Other files - for (const file of copyFiles) { - await cp(join(mainDir, file), join(mirrorDir, file)); - } -} - -// eslint-disable-next-line unicorn/prefer-top-level-await -main(); diff --git a/scripts/gen-node-compat.ts b/scripts/gen-node-compat.ts index 7f4fbae5f3..82dadb5622 100644 --- a/scripts/gen-node-compat.ts +++ b/scripts/gen-node-compat.ts @@ -1,130 +1,18 @@ import { writeFile } from "node:fs/promises"; const platforms = { - cloudflare: { - url: "https://platform-node-compat.pi0.workers.dev/?json", - forceHybrid: ["console"], - forceBuiltin: ["assert", "assert/strict", "events", "net", "stream"], - }, - vercel: { - url: "https://platform-node-compat.vercel.app/?json", - // https://vercel.com/docs/functions/edge-middleware/edge-runtime#compatible-node.js-modules - forceBuiltin: ["async_hooks", "events", "buffer", "assert", "util"], - }, - // Deno deploy and Netlify edge are almost identical - deno: { - url: "https://platform-node-compat.deno.dev/?json", - forceBuiltin: true, - }, - netlify: { - url: "https://platform-node-compat.netlify.app/?json", - forceBuiltin: true, - }, -} as { - [platform: string]: { - url: string; - forceHybrid?: string[]; - forceBuiltin?: true | string[]; - }; + cloudflare: "https://platform-node-compat.pi0.workers.dev/?ts", + deno: "https://platform-node-compat.deno.dev/?ts", }; -type NodeComptatReport = { - _url: string; - version: string; - globals: { - globalKeys: string[]; - missing: string[]; - }; - builtinModules: Record< - string, - | false - | { - exports: string[]; - missingExports: string[]; - } - >; -}; - -for (const [platformName, { url, forceHybrid, forceBuiltin }] of Object.entries( - platforms -)) { - const report = (await fetch(url).then((res) => - res.json() - )) as NodeComptatReport; - - const builtnNodeModules: [string, string[]][] = []; - - const hybridNodeCompatModules: [string, string[]][] = []; - - const notSupported: string[] = []; - - for (const [id, status] of Object.entries(report.builtinModules)) { - if (!status) { - if (forceHybrid?.includes(id)) { - hybridNodeCompatModules.push([id, []]); - } else { - notSupported.push(id); - } - continue; - } - - const missingExports = status.missingExports.filter( - (exp) => !exp.startsWith("_") - ); +for (const platform in platforms) { + const url = platforms[platform as keyof typeof platforms]; + const code = await fetch(url).then((res) => res.text()); - let target = - missingExports.length === 0 ? builtnNodeModules : hybridNodeCompatModules; - if (forceHybrid?.includes(id)) { - target = hybridNodeCompatModules; - } - if (forceBuiltin === true || forceBuiltin?.includes(id)) { - target = builtnNodeModules; - } - - target.push([id, missingExports]); - } - - const code = /* js */ `// Auto generated using gen-node-compat.ts on ${new Date().toISOString().split("T")[0]} -// Source: ${url.replace(/\?json$/, "")} -// Do not edit this file manually - -// prettier-ignore -export const builtnNodeModules = [ -${builtnNodeModules - .sort() - .map(([id, missing]) => - missing.length > 0 - ? ` "${id}", // Missing exports: ${missing.join(", ")}` - : ` "${id}",` - ) - .join("\n")} -]; - -// prettier-ignore -export const hybridNodeModules = [ -${hybridNodeCompatModules - .sort((a, b) => a[0].localeCompare(b[0])) - .map(([id, missing]) => - missing.length > 0 - ? ` "${id}", // Missing exports: ${missing.join(", ")}` - : ` "${id}",` - ) - .join("\n")} -]; - -// prettier-ignore -export const unsupportedNodeModules = [ -${notSupported.map((id) => ` "${id}",`).join("\n")} -]; -`; + console.log(`Fetching Node.js compatibility data for ${platform} from ${url}`); await writeFile( - new URL( - `../src/presets/_unenv/node-compat/${platformName}.ts`, - import.meta.url - ), + new URL(`../src/presets/${platform}/unenv/node-compat.ts`, import.meta.url), code ); } - -export {}; diff --git a/scripts/gen-presets.ts b/scripts/gen-presets.ts index f7ccf9f8e5..6c95332d18 100644 --- a/scripts/gen-presets.ts +++ b/scripts/gen-presets.ts @@ -1,12 +1,10 @@ import { existsSync, readFileSync, readdirSync, writeFileSync } from "node:fs"; import { resolve } from "node:path"; -import { fileURLToPath } from "node:url"; +import { fileURLToPath, pathToFileURL } from "node:url"; import { consola } from "consola"; -import { createJiti } from "jiti"; import { findTypeExports } from "mlly"; -import type { NitroPreset, NitroPresetMeta } from "nitropack/types"; +import type { NitroPreset, NitroPresetMeta } from "nitro/types"; import { camelCase, kebabCase, pascalCase, snakeCase } from "scule"; -import { subpaths } from "../build.config"; const autoGenHeader = /* ts */ `// Auto-generated using gen-presets script\n`; @@ -15,29 +13,22 @@ const presetsDir = fileURLToPath(new URL("../src/presets", import.meta.url)); const presetDirs: string[] = readdirSync(presetsDir, { withFileTypes: true }) .filter( (dir) => + dir.name !== "_utils" && dir.isDirectory() && existsSync(resolve(presetsDir, dir.name, "preset.ts")) ) .map((dir) => dir.name); // --- Load presets --- -const jiti = createJiti(presetsDir, { - alias: { - nitropack: fileURLToPath(new URL("../src/core/index.ts", import.meta.url)), - ...Object.fromEntries( - subpaths.map((pkg) => [ - `nitropack/${pkg}`, - fileURLToPath(new URL(`../src/${pkg}/index.ts`, import.meta.url)), - ]) - ), - }, -}); const allPresets: (NitroPreset & { _meta?: NitroPresetMeta })[] = []; for (const preset of presetDirs) { const presetPath = resolve(presetsDir, preset, "preset.ts"); - const _presets = await jiti - .import(presetPath) - .then((mod) => (mod as any).default || mod); + const _presets = await import(pathToFileURL(presetPath).href).then( + (mod) => (mod as any).default || mod + ); + if (!Array.isArray(_presets)) { + throw new TypeError(`Preset ${preset} does not export an array`); + } allPresets.push(..._presets); } @@ -51,7 +42,7 @@ for (const preset of allPresets) { const names = [preset._meta.name, ...(preset._meta.aliases || [])]; for (const name of names) { if (_names.has(name)) { - if (!preset._meta.compatibilityDate) { + if (!preset._meta.compatibilityDate && !preset._meta.dev) { consola.warn(`Preset ${name} is duplicated`); } continue; @@ -70,7 +61,7 @@ writeFileSync( resolve(presetsDir, "_all.gen.ts"), /* ts */ `${autoGenHeader} ${presetDirs - .map((preset) => `import _${camelCase(preset)} from "./${preset}/preset";`) + .map((preset) => `import _${camelCase(preset)} from "./${preset}/preset.ts";`) .join("\n")} export default [ @@ -91,15 +82,13 @@ writeFileSync( ${presetsWithType .map( (preset) => - `import type { PresetOptions as ${pascalCase( - preset - )}Options } from "./${preset}/preset";` + `import type { PresetOptions as ${pascalCase(preset)}Options } from "./${preset}/preset.ts";` ) .join("\n")} export interface PresetOptions { ${presetsWithType - .map((preset) => ` ${camelCase(preset)}: ${pascalCase(preset)}Options;`) + .map((preset) => ` ${camelCase(preset)}?: ${pascalCase(preset)}Options;`) .join("\n")} } @@ -109,9 +98,7 @@ export type PresetName = ${names.map((name) => `"${name}"`).join(" | ")}; export type PresetNameInput = ${names .flatMap((name) => - [...new Set([kebabCase(name), camelCase(name), snakeCase(name)])].map( - (n) => `"${n}"` - ) + [...new Set([kebabCase(name), camelCase(name), snakeCase(name)])].map((n) => `"${n}"`) ) .join(" | ")} | (string & {}); ` diff --git a/scripts/release-nightly.sh b/scripts/release-nightly.sh deleted file mode 100755 index 84927d8774..0000000000 --- a/scripts/release-nightly.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash - -# Temporary forked from nuxt/nuxt - -set -xe - -# Restore all git changes -git restore -s@ -SW -- . - -# Bump according to changelog -pnpm changelogen --bump - -# Bump versions to nightly -pnpm jiti ./scripts/bump-nightly - -# Build mirror -pnpm gen-mirror - -# Resolve lockfile -# pnpm install - -# Update token -if [[ ! -z ${NODE_AUTH_TOKEN} ]] ; then - echo "//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}" >> ~/.npmrc - echo "registry=https://registry.npmjs.org/" >> ~/.npmrc - echo "always-auth=true" >> ~/.npmrc - echo "npmAuthToken: ${NODE_AUTH_TOKEN}" >> ~/.npmrc.yml - npm whoami -fi - -# Release packages - -echo "Publishing main package..." -npm publish --access public --tolerate-republish - -echo "Publishing mirror package..." -cd .mirror -npm publish --access public --tolerate-republish diff --git a/scripts/release.ts b/scripts/release.ts new file mode 100755 index 0000000000..1bcac7da10 --- /dev/null +++ b/scripts/release.ts @@ -0,0 +1,152 @@ +#!/bin/env node +import { execSync } from "node:child_process"; +import { readFile } from "node:fs/promises"; +import { parseArgs } from "node:util"; +// import { setTimeout as sleep } from "node:timers/promises"; + +const { values: args } = parseArgs({ + allowNegative: true, + options: { + precheck: { type: "boolean", default: true }, + }, +}); + +const c = { + cyan: (s: string) => `\x1B[36m${s}\x1B[0m`, + green: (s: string) => `\x1B[32m${s}\x1B[0m`, + red: (s: string) => `\x1B[31m${s}\x1B[0m`, + bold: (s: string) => `\x1B[1m${s}\x1B[0m`, + gray: (s: string) => `\x1B[90m${s}\x1B[0m`, +}; + +main().catch((error) => { + console.error(c.red(`\nError: ${error.message}\n`)); + process.exit(1); +}); + +async function main() { + console.log(c.bold("\n🚀 Nitro Release\n")); + + // 1. Prechecks + if (!args.precheck) { + console.log(c.gray("→ Skipping prechecks (--no-precheck)\n")); + } else { + await precheck(); + } + + // 2. Bump version + console.log(c.cyan("\n→ Bumping version...\n")); + run("node scripts/bump-version.ts"); + + // 3. Read new version + const pkg = JSON.parse(await readFile("package.json", "utf8")); + const version = `v${pkg.version}`; + console.log(c.cyan(`\n→ Version: ${c.bold(version)}\n`)); + + // 4. Generate release notes + console.log(c.cyan("→ Generating release notes...\n")); + run("pnpx changelogen --output CHANGELOG.md"); + console.log(c.green(" Written to CHANGELOG.md")); + + // 5. Commit and tag + console.log(c.cyan("\n→ Creating release commit and tag...\n")); + run("git add package.json"); + run(`git commit -m "${version}"`); + run(`git tag -a ${version} -m "${version}"`); + + console.log(c.green(c.bold(`\n✅ Release ${version} prepared!\n`))); + + // Prompt to push + process.stdout.write(c.cyan(` Push with ${c.bold("git push --follow-tags")}? (yes/no) `)); + const answer = await new Promise((resolve) => { + process.stdin.setEncoding("utf8"); + process.stdin.once("data", (data) => resolve(data.toString().trim())); + }); + process.stdin.destroy(); + if (answer === "yes") { + run("git push --follow-tags"); + console.log(c.green(c.bold("\n🎉 Released!\n"))); + } else { + console.log(c.cyan(`\n Run ${c.bold("git push --follow-tags")} manually to publish.\n`)); + } +} + +function run(cmd: string, opts?: { silent?: boolean; quiet?: boolean }) { + if (!opts?.quiet) { + console.log(c.gray(`$ ${cmd}`)); + } + return execSync(cmd, { + stdio: opts?.silent ? "pipe" : "inherit", + encoding: "utf8", + }); +} + +async function precheck() { + console.log(c.cyan("→ Running prechecks...\n")); + + // Check we are on main branch + const branch = run("git rev-parse --abbrev-ref HEAD", { silent: true }).trim(); + if (branch !== "main") { + throw new Error(`Must be on "main" branch (currently on "${branch}")`); + } + + // Check no dirty state + const status = run("git status --porcelain", { silent: true }).trim(); + if (status) { + throw new Error(`Working tree is dirty:\n${status}`); + } + + // Check local HEAD matches remote main + run("git fetch origin main", { silent: true }); + const localHead = run("git rev-parse HEAD", { silent: true }).trim(); + const remoteHead = run("git rev-parse origin/main", { silent: true }).trim(); + if (localHead !== remoteHead) { + throw new Error( + `Local HEAD (${localHead.slice(0, 8)}) does not match origin/main (${remoteHead.slice(0, 8)})` + ); + } + + // Check all GitHub Actions completed successfully for HEAD commit + // type CIRun = { status: string; conclusion: string; name: string; databaseId: number }; + // type CIJob = { status: string; conclusion: string; name: string }; + // const pollInterval = 15_000; + // let ciRuns: CIRun[] = []; + // // eslint-disable-next-line no-constant-condition + // while (true) { + // ciRuns = JSON.parse( + // run( + // `gh run list --branch main --commit ${remoteHead} --json status,conclusion,name,databaseId`, + // { silent: true, quiet: true } + // ) + // ) as CIRun[]; + // if (ciRuns.length === 0) { + // throw new Error("No GitHub Actions runs found for HEAD"); + // } + // const pending = ciRuns.filter((r) => r.status !== "completed"); + // if (pending.length === 0) break; + // console.log(c.gray(` Waiting for ${pending.map((r) => r.name).join(", ")}...`)); + // await sleep(pollInterval); + // } + + // // Fetch jobs for each run and print summary + // const allFailed: string[] = []; + // for (const r of ciRuns) { + // const jobs = JSON.parse( + // run(`gh run view ${r.databaseId} --json jobs -q ".jobs"`, { silent: true, quiet: true }) + // ) as CIJob[]; + // const runIcon = r.conclusion === "success" ? c.green("✓") : c.red("✗"); + // console.log(` ${runIcon} ${c.bold(r.name)}`); + // for (const job of jobs) { + // const jobIcon = job.conclusion === "success" ? c.green("✓") : c.red("✗"); + // console.log(` ${jobIcon} ${job.name}`); + // if (job.conclusion !== "success") { + // allFailed.push(`${r.name} > ${job.name} (${job.conclusion})`); + // } + // } + // } + // if (allFailed.length > 0) { + // throw new Error(`GitHub Actions failed:\n ${allFailed.join("\n ")}`); + // } + + console.log(c.green(" All prechecks passed!\n")); +} diff --git a/scripts/vite7.ts b/scripts/vite7.ts new file mode 100644 index 0000000000..ba57ba944e --- /dev/null +++ b/scripts/vite7.ts @@ -0,0 +1,18 @@ +import { execSync } from "node:child_process"; +import { readFileSync, writeFileSync } from "node:fs"; +import { resolve } from "node:path"; + +const pkgPath = resolve(import.meta.dirname, "../package.json"); +const pkg = JSON.parse(readFileSync(pkgPath, "utf8")); + +pkg.resolutions = pkg.resolutions || {}; +pkg.resolutions.vite = "^7"; + +writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n"); + +console.log("Added vite: ^7 to resolutions"); + +execSync("pnpm install --no-frozen-lockfile", { + stdio: "inherit", + cwd: resolve(import.meta.dirname, ".."), +}); diff --git a/skills/nitro/SKILL.md b/skills/nitro/SKILL.md new file mode 100644 index 0000000000..256630437d --- /dev/null +++ b/skills/nitro/SKILL.md @@ -0,0 +1,10 @@ +--- +name: nitro +description: Build and deploy universal JavaScript servers with Nitro +--- + +@docs/TOC.md + +You can use `npx nitro docs [--page ] [...args]` to explore the documentation locally. +For example, `npx nitro docs --page /docs/routing` will open the routing page of the guide section. +If not available, fallback to https://nitro.build/llms.txt diff --git a/src/core/build/assets.ts b/src/build/assets.ts similarity index 60% rename from src/core/build/assets.ts rename to src/build/assets.ts index b55a14d28b..f32274e525 100644 --- a/src/core/build/assets.ts +++ b/src/build/assets.ts @@ -1,9 +1,9 @@ import { existsSync, promises as fsp } from "node:fs"; -import { globby } from "globby"; -import { isDirectory, prettyPath } from "nitropack/kit"; -import type { Nitro } from "nitropack/types"; +import { glob } from "tinyglobby"; +import { isDirectory, prettyPath } from "../utils/fs.ts"; +import type { Nitro } from "nitro/types"; import { join, relative, resolve } from "pathe"; -import { compressPublicAssets } from "../utils/compress"; +import { compressPublicAssets } from "../utils/compress.ts"; const NEGATION_RE = /^(!?)(.*)$/; const PARENT_DIR_GLOB_RE = /!?\.\.\//; @@ -18,15 +18,13 @@ export async function scanUnprefixedPublicAssets(nitro: Nitro) { if (!(await isDirectory(asset.dir))) { continue; } - const includePatterns = getIncludePatterns(nitro, asset.dir); - const publicAssets = await globby(includePatterns, { + const includePatterns = getIncludePatterns(nitro, asset.dir, asset.ignore); + const publicAssets = await glob(includePatterns, { cwd: asset.dir, absolute: false, dot: true, }); - scannedPaths.push( - ...publicAssets.map((file) => join(asset.baseURL || "/", file)) - ); + scannedPaths.push(...publicAssets.map((file) => join(asset.baseURL || "/", file))); } return scannedPaths; } @@ -36,18 +34,18 @@ export async function copyPublicAssets(nitro: Nitro) { return; } for (const asset of nitro.options.publicAssets) { - const srcDir = asset.dir; + const assetDir = asset.dir; const dstDir = join(nitro.options.output.publicDir, asset.baseURL!); - if (await isDirectory(srcDir)) { - const includePatterns = getIncludePatterns(nitro, srcDir); - const publicAssets = await globby(includePatterns, { - cwd: srcDir, + if (await isDirectory(assetDir)) { + const includePatterns = getIncludePatterns(nitro, assetDir, asset.ignore); + const publicAssets = await glob(includePatterns, { + cwd: assetDir, absolute: false, dot: true, }); await Promise.all( publicAssets.map(async (file) => { - const src = join(srcDir, file); + const src = join(assetDir, file); const dst = join(dstDir, file); if (!existsSync(dst)) { await fsp.cp(src, dst); @@ -59,15 +57,17 @@ export async function copyPublicAssets(nitro: Nitro) { if (nitro.options.compressPublicAssets) { await compressPublicAssets(nitro); } - nitro.logger.success( - "Generated public " + prettyPath(nitro.options.output.publicDir) - ); + nitro.logger.success("Generated public " + prettyPath(nitro.options.output.publicDir)); } -function getIncludePatterns(nitro: Nitro, srcDir: string) { +function getIncludePatterns( + nitro: Nitro, + assetDir: string, + ignorePatterns: string[] | false = nitro.options.ignore +) { return [ "**", - ...nitro.options.ignore.map((p) => { + ...(ignorePatterns || []).map((p) => { const [_, negation, pattern] = p.match(NEGATION_RE) || []; return ( // Convert ignore to include patterns @@ -75,7 +75,7 @@ function getIncludePatterns(nitro: Nitro, srcDir: string) { // Make non-glob patterns relative to publicAssetDir (pattern.startsWith("*") ? pattern - : relative(srcDir, resolve(nitro.options.srcDir, pattern))) + : relative(assetDir, resolve(nitro.options.rootDir, pattern))) ); }), ].filter((p) => !PARENT_DIR_GLOB_RE.test(p)); diff --git a/src/build/build.ts b/src/build/build.ts new file mode 100644 index 0000000000..5fc53a58eb --- /dev/null +++ b/src/build/build.ts @@ -0,0 +1,21 @@ +import type { Nitro } from "nitro/types"; + +export async function build(nitro: Nitro) { + switch (nitro.options.builder) { + case "rollup": { + const { rollupBuild } = await import("./rollup/build.ts"); + return rollupBuild(nitro); + } + case "rolldown": { + const { rolldownBuild } = await import("./rolldown/build.ts"); + return rolldownBuild(nitro); + } + case "vite": { + const { viteBuild } = await import("./vite/build.ts"); + return viteBuild(nitro); + } + default: { + throw new Error(`Unknown builder: ${nitro.options.builder}`); + } + } +} diff --git a/src/build/chunks.ts b/src/build/chunks.ts new file mode 100644 index 0000000000..237c07db58 --- /dev/null +++ b/src/build/chunks.ts @@ -0,0 +1,120 @@ +import type { Nitro } from "nitro/types"; + +// Tests in @test/unit/chunks.test.ts + +const virtualRe = /^(?:\0|#|virtual:)/; + +export const NODE_MODULES_RE = /node_modules[/\\](?!(?:nitro|nitro-nightly)[/\\])[^.]/; + +export function libChunkName(id: string) { + const pkgName = pathToPkgName(id); + return pkgName ? `_libs/${pkgName}` : undefined; +} + +export function pathToPkgName(path: string): string | undefined { + let pkgName = path.match( + /.*(?:[/\\])node_modules(?:[/\\])(?@[^/\\]+[/\\][^/\\]+|[^/\\.][^/\\]*)/ + )?.groups?.name; + if (pkgName?.endsWith("-nightly")) { + pkgName = pkgName.slice(0, -8); + } + return pkgName; +} + +export function getChunkName(chunk: { name: string; moduleIds: string[] }, nitro: Nitro) { + // Known groups + if (chunk.name === "rolldown-runtime") { + return "_runtime.mjs"; + } + + // Library chunks + if (chunk.moduleIds.every((id) => NODE_MODULES_RE.test(id))) { + const chunkName = joinPkgNames(chunk.moduleIds); + if (chunkName.length > 30) { + return `${chunk.name}+[...].mjs`; + } + return `_libs/${chunkName || "_"}.mjs`; + } + + // _ chunks are preserved (should be after library normalization) + if (chunk.name.startsWith("_")) { + return `${chunk.name}.mjs`; + } + + // No moduleIds + if (chunk.moduleIds.length === 0) { + return `_chunks/${chunk.name}.mjs`; + } + + const ids = chunk.moduleIds.filter((id) => !virtualRe.test(id)); + + // All virtual + if (ids.length === 0) { + if (chunk.moduleIds.every((id) => id.includes("virtual:raw"))) { + return `_raw/[name].mjs`; + } + return `_virtual/[name].mjs`; + } + + // WASM chunk + if (ids.every((id) => id.endsWith(".wasm"))) { + return `_wasm/[name].mjs`; + } + + // Chunks generate by other vite environments (we assume SSR for simplicity) + if (ids.every((id) => id.includes("vite/services"))) { + return `_ssr/[name].mjs`; + } + + // Chunks from generated code + if (ids.every((id) => id.startsWith(nitro.options.buildDir))) { + return `_build/[name].mjs`; + } + + // Try to match user defined routes or tasks + const mainId = ids.at(-1); + if (mainId) { + const routeHandler = nitro.routing.routes.routes + .flatMap((h) => h.data) + .find((h) => h.handler === mainId); + if (routeHandler?.route) { + return `_routes/${routeToFsPath(routeHandler.route)}.mjs`; + } + + const taskHandler = Object.entries(nitro.options.tasks).find( + ([_, task]) => task.handler === mainId + ); + if (taskHandler) { + return `_tasks/[name].mjs`; + } + } + + return `_chunks/[name].mjs`; +} + +function joinPkgNames(moduleIds: string[]): string { + const names = [ + ...new Set( + moduleIds + .map((id) => pathToPkgName(id)) + .filter(Boolean) + .map((name) => name!.replace(/^@/, "").replace(/[/\\]/g, "__")) + ), + ].sort(); + return names.join("+"); +} + +export function routeToFsPath(route: string) { + return ( + route + .split("/") + .slice(1) + .map((s) => + s + .replace(/:(\w+)/g, "[$1]") + .replace(/\*+/g, "[...]") + .replace(/[^a-zA-Z0-9_.[\]]/g, "_") + ) + .join("/") || "index" + ); +} diff --git a/src/build/config.ts b/src/build/config.ts new file mode 100644 index 0000000000..495b580260 --- /dev/null +++ b/src/build/config.ts @@ -0,0 +1,119 @@ +import type { Nitro, NitroImportMeta } from "nitro/types"; +import { defineEnv } from "unenv"; +import { pkgDir } from "nitro/meta"; +import { pathRegExp, toPathRegExp } from "../utils/regex.ts"; + +export type BaseBuildConfig = ReturnType; + +export function baseBuildConfig(nitro: Nitro) { + // prettier-ignore + const extensions: string[] = [".ts", ".mjs", ".js", ".json", ".node", ".tsx", ".jsx" ]; + + const isNodeless = nitro.options.node === false; + + const importMetaInjections: NitroImportMeta = { + dev: nitro.options.dev, + preset: nitro.options.preset, + prerender: nitro.options.preset === "nitro-prerender", + nitro: true, + server: true, + client: false, + baseURL: nitro.options.baseURL, + _asyncContext: nitro.options.experimental.asyncContext, + _tasks: nitro.options.experimental.tasks, + _websocket: nitro.options.features.websocket ?? nitro.options.experimental.websocket, + }; + + const replacements = { + ...Object.fromEntries( + Object.entries(importMetaInjections).map(([key, val]) => [ + `import.meta.${key}`, + JSON.stringify(val), + ]) + ), + ...nitro.options.replace, + }; + + const { env } = defineEnv({ + nodeCompat: isNodeless, + resolve: true, + presets: nitro.options.unenv, + overrides: { + alias: nitro.options.alias, + }, + }); + + const aliases = resolveAliases({ ...env.alias }); + + const noExternal: RegExp[] = getNoExternals(nitro); + + const ignoreWarningCodes = new Set([ + "EVAL", + "CIRCULAR_DEPENDENCY", + "THIS_IS_UNDEFINED", + "EMPTY_BUNDLE", + ]); + + return { + extensions, + isNodeless, + replacements, + env, + aliases, + noExternal, + ignoreWarningCodes, + }; +} + +function getNoExternals(nitro: Nitro): RegExp[] { + const noExternal: RegExp[] = [ + /\.[mc]?tsx?$/, + /^(?:[\0#~.]|virtual:)/, + new RegExp("^" + pathRegExp(pkgDir) + "(?!.*node_modules)"), + ...[ + nitro.options.rootDir, + ...nitro.options.scanDirs.filter( + (dir) => dir.includes("node_modules") || !dir.startsWith(nitro.options.rootDir) + ), + ].map((dir) => new RegExp("^" + pathRegExp(dir) + "(?!.*node_modules)")), + ]; + + if (nitro.options.wasm !== false) { + noExternal.push(/\.wasm$/); + } + + if (Array.isArray(nitro.options.noExternals)) { + noExternal.push( + ...nitro.options.noExternals + .filter(Boolean) + .map((item) => toPathRegExp(item as string | RegExp)) + ); + } + + return noExternal.sort((a, b) => a.source.length - b.source.length); +} + +export function resolveAliases(_aliases: Record) { + // Sort aliases from specific to general (ie. fs/promises before fs) + const aliases = Object.fromEntries( + Object.entries(_aliases).sort( + ([a], [b]) => b.split("/").length - a.split("/").length || b.length - a.length + ) + ); + // Resolve alias values in relation to each other + for (const key in aliases) { + for (const alias in aliases) { + if (!["~", "@", "#"].includes(alias[0])) { + continue; + } + if (alias === "@" && !aliases[key].startsWith("@/")) { + continue; + } // Don't resolve @foo/bar + + if (aliases[key].startsWith(alias)) { + aliases[key] = aliases[alias] + aliases[key].slice(alias.length); + } + } + } + return aliases; +} diff --git a/src/build/info.ts b/src/build/info.ts new file mode 100644 index 0000000000..31f1a8131e --- /dev/null +++ b/src/build/info.ts @@ -0,0 +1,105 @@ +import type { Nitro, NitroBuildInfo, WorkerAddress } from "nitro/types"; +import { join, relative, resolve } from "pathe"; +import { version as nitroVersion } from "nitro/meta"; +import { presetsWithConfig } from "../presets/_types.gen.ts"; +import { writeFile } from "../utils/fs.ts"; +import { mkdir, readFile, stat } from "node:fs/promises"; +import { dirname } from "node:path"; +import type { RolldownOutput } from "rolldown"; +import type { RollupOutput } from "rollup"; + +const NITRO_WELLKNOWN_DIR = "node_modules/.nitro"; + +export async function getBuildInfo( + root: string +): Promise< + | { outputDir?: undefined; buildInfo?: undefined } + | { outputDir: string; buildInfo?: NitroBuildInfo } +> { + const outputDir = await findLastBuildDir(root); + + const isDir = await stat(outputDir) + .then((s) => s.isDirectory()) + .catch(() => false); + if (!isDir) { + return {}; + } + + const buildInfo = (await readFile(resolve(outputDir, "nitro.json"), "utf8") + .then(JSON.parse) + .catch(() => undefined)) as NitroBuildInfo | undefined; + + return { + outputDir, + buildInfo, + }; +} + +export async function findLastBuildDir(root: string): Promise { + const lastBuildLink = join(root, NITRO_WELLKNOWN_DIR, "last-build.json"); + const outputDir = await readFile(lastBuildLink, "utf8") + .then(JSON.parse) + .then((data) => resolve(lastBuildLink, data.outputDir || "../../../.output")) + .catch(() => resolve(root, ".output")); + return outputDir; +} + +export async function writeBuildInfo( + nitro: Nitro, + output: RolldownOutput | RollupOutput | undefined +): Promise { + const serverEntryName = output?.output?.find((o) => o.type === "chunk" && o.isEntry)?.fileName; + + const buildInfoPath = resolve(nitro.options.output.dir, "nitro.json"); + const buildInfo: NitroBuildInfo = { + date: new Date().toJSON(), + preset: nitro.options.preset, + framework: nitro.options.framework, + versions: { + nitro: nitroVersion, + }, + serverEntry: serverEntryName + ? relative(nitro.options.output.dir, join(nitro.options.output.serverDir, serverEntryName)) + : undefined, + publicDir: relative( + nitro.options.output.dir, + resolve(nitro.options.output.dir, nitro.options.output.publicDir) + ), + commands: { + preview: nitro.options.commands.preview, + deploy: nitro.options.commands.deploy, + }, + config: { + ...Object.fromEntries(presetsWithConfig.map((key) => [key, nitro.options[key]])), + }, + }; + + await writeFile(buildInfoPath, JSON.stringify(buildInfo, null, 2), true); + + const lastBuild = join(nitro.options.rootDir, NITRO_WELLKNOWN_DIR, "last-build.json"); + await mkdir(dirname(lastBuild), { recursive: true }); + await writeFile( + lastBuild, + JSON.stringify({ + outputDir: relative(lastBuild, nitro.options.output.dir), + }) + ); + return buildInfo; +} + +export async function writeDevBuildInfo(nitro: Nitro, addr?: WorkerAddress): Promise { + const buildInfoPath = join(nitro.options.rootDir, NITRO_WELLKNOWN_DIR, "nitro.dev.json"); + const buildInfo: NitroBuildInfo = { + date: new Date().toJSON(), + preset: nitro.options.preset, + framework: nitro.options.framework, + versions: { + nitro: nitroVersion, + }, + dev: { + pid: process.pid, + workerAddress: addr, + }, + }; + await writeFile(buildInfoPath, JSON.stringify(buildInfo, null, 2)); +} diff --git a/src/build/plugins.ts b/src/build/plugins.ts new file mode 100644 index 0000000000..9b11849cb6 --- /dev/null +++ b/src/build/plugins.ts @@ -0,0 +1,91 @@ +import type { Nitro } from "nitro/types"; +import type { Plugin } from "rollup"; +import type { BaseBuildConfig } from "./config.ts"; + +import { virtualTemplates } from "./virtual/_all.ts"; +import replace from "@rollup/plugin-replace"; +import { unwasm } from "unwasm/plugin"; +import { routeMeta } from "./plugins/route-meta.ts"; +import { serverMain } from "./plugins/server-main.ts"; +import { virtual, virtualDeps } from "./plugins/virtual.ts"; +import { sourcemapMinify } from "./plugins/sourcemap-min.ts"; +import { raw } from "./plugins/raw.ts"; +import { externals } from "./plugins/externals.ts"; + +export async function baseBuildPlugins(nitro: Nitro, base: BaseBuildConfig) { + const plugins: Plugin[] = []; + + // Virtual + const virtualPlugin = virtual(virtualTemplates(nitro, [...base.env.polyfill])); + nitro.vfs = virtualPlugin.api.modules; + plugins.push(virtualPlugin, virtualDeps()); + + // Auto imports + if (nitro.options.imports) { + const unimportPlugin = await import("unimport/unplugin"); + plugins.push(unimportPlugin.default.rollup(nitro.options.imports) as Plugin); + } + + // WASM loader + if (nitro.options.wasm !== false) { + plugins.push(unwasm(nitro.options.wasm || {})); + } + + // Inject globalThis.__server_main__ + plugins.push(serverMain(nitro)); + + // Raw Imports + plugins.push(raw()); + + // Route meta + if (nitro.options.experimental.openAPI) { + plugins.push(await routeMeta(nitro)); + } + + // Replace + plugins.push( + (replace as unknown as typeof replace.default)({ + preventAssignment: true, + values: base.replacements, + }) + ); + + // Externals (require Node.js compatible resolution) + if (nitro.options.node && nitro.options.noExternals !== true) { + const isDevOrPrerender = nitro.options.dev || nitro.options.preset === "nitro-prerender"; + const { NodeNativePackages, NonBundleablePackages } = await import("nf3/db"); + const traceDeps = [ + ...new Set([ + ...NodeNativePackages, + ...NonBundleablePackages, + ...(nitro.options.traceDeps || []), + ]), + ]; + plugins.push( + externals({ + rootDir: nitro.options.rootDir, + conditions: nitro.options.exportConditions!, + exclude: [...base.noExternal], + include: isDevOrPrerender + ? undefined + : [ + new RegExp( + `^(?:${traceDeps.join("|")})|[/\\\\]node_modules[/\\\\](?:${traceDeps.join("|")})(?:[/\\\\])` + ), + ], + trace: isDevOrPrerender ? false : { outDir: nitro.options.output.serverDir }, + }) + ); + } + + // Sourcemap minify + if ( + nitro.options.sourcemap && + !nitro.options.dev && + nitro.options.experimental.sourcemapMinify !== false + ) { + plugins.push(sourcemapMinify()); + } + + return plugins; +} diff --git a/src/build/plugins/externals.ts b/src/build/plugins/externals.ts new file mode 100644 index 0000000000..e1d571d30e --- /dev/null +++ b/src/build/plugins/externals.ts @@ -0,0 +1,254 @@ +import type { Plugin } from "rollup"; +import type { PackageJson } from "pkg-types"; +import type { ExternalsTraceOptions } from "nf3"; + +import { pathToFileURL } from "node:url"; +import { builtinModules, createRequire } from "node:module"; +import { isAbsolute, join } from "pathe"; +import { resolveModulePath } from "exsolve"; +import { escapeRegExp, toPathRegExp } from "../../utils/regex.ts"; +import consola from "consola"; + +export type ExternalsOptions = { + rootDir: string; + conditions: string[]; + exclude?: (string | RegExp)[]; + include?: (string | RegExp)[]; + trace?: false | Omit; +}; + +const PLUGIN_NAME = "nitro:externals"; + +export function externals(opts: ExternalsOptions): Plugin { + const include: RegExp[] | undefined = opts?.include + ? opts.include.map((p) => toPathRegExp(p)) + : undefined; + + const exclude: RegExp[] = [ + /^(?:[\0#~.]|[a-z0-9]{2,}:)|\?/, + ...(opts?.exclude || []).map((p) => toPathRegExp(p)), + ]; + + const filter = (id: string) => { + // Most match at least one include (if specified) + if (include && !include.some((r) => r.test(id))) { + return false; + } + // Most not match any exclude + if (exclude.some((r) => r.test(id))) { + return false; + } + return true; + }; + + const tryResolve = (id: string, from: string | undefined) => + resolveModulePath(id, { + try: true, + from: from && isAbsolute(from) ? from : opts.rootDir, + conditions: opts.conditions, + }); + + const tracedPaths = new Set(); + + if (include && include.length === 0) { + return { + name: PLUGIN_NAME, + }; + } + + return { + name: PLUGIN_NAME, + resolveId: { + order: "pre", + filter: { id: { exclude, include } }, + async handler(id, importer, rOpts) { + // Externalize built-in modules with normalized prefix + if (builtinModules.includes(id)) { + return { + resolvedBy: PLUGIN_NAME, + external: true, + id: id.includes(":") ? id : `node:${id}`, + }; + } + + // Skip nested rollup-node resolutions + if (rOpts.custom?.["node-resolve"]) { + return null; + } + + // Resolve by other resolvers + let resolved = await this.resolve(id, importer, rOpts); + + // Skip rolldown-plugin-commonjs resolver for externals + const cjsResolved = resolved?.meta?.commonjs?.resolved; + if (cjsResolved) { + if (!filter(cjsResolved.id)) { + return resolved; // Bundled and wrapped by CJS plugin + } + resolved = cjsResolved /* non-wrapped */; + } + + // Check if not resolved or explicitly marked as excluded + if (!resolved?.id || !filter(resolved!.id)) { + return resolved; + } + + // Normalize to absolute path + let resolvedPath = resolved.id; + if (!isAbsolute(resolvedPath)) { + resolvedPath = tryResolve(resolvedPath, importer) || resolvedPath; + } + + // Tracing mode + if (opts.trace) { + let importId = toImport(id) || toImport(resolvedPath); + if (!importId) { + return resolved; + } + if (!tryResolve(importId, importer)) { + const guessed = await guessSubpath(resolvedPath, opts.conditions); + if (!guessed) { + return resolved; + } + importId = guessed; + } + tracedPaths.add(resolvedPath); + return { + ...resolved, + resolvedBy: PLUGIN_NAME, + external: true, + id: importId, + }; + } + + // Resolve as absolute path external + return { + ...resolved, + resolvedBy: PLUGIN_NAME, + external: true, + id: isAbsolute(resolvedPath) + ? pathToFileURL(resolvedPath).href // windows compat + : resolvedPath, + }; + }, + }, + buildEnd: { + order: "post", + async handler() { + if (!opts.trace || tracedPaths.size === 0) { + return; + } + const { traceNodeModules } = await import("nf3"); + const traceTime = Date.now(); + let traceFilesCount = 0; + let tracedPkgsCount = 0; + await traceNodeModules([...tracedPaths], { + ...opts.trace, + conditions: opts.conditions, + rootDir: opts.rootDir, + writePackageJson: true, // deno compat + hooks: { + tracedFiles(result) { + traceFilesCount = Object.keys(result).length; + }, + tracedPackages: (pkgs) => { + tracedPkgsCount = Object.keys(pkgs).length; + consola.info( + `Tracing dependencies:\n${Object.entries(pkgs) + .map( + ([name, versions]) => + `- \`${name}\` (${Object.keys(versions.versions).join(", ")})` + ) + .join("\n")}` + ); + }, + }, + }); + consola.success( + `Traced ${tracedPkgsCount} dependencies (${traceFilesCount} files) in ${Date.now() - traceTime}ms.` + ); + consola.info( + `Ensure your production environment matches the builder OS and architecture (\`${process.platform}-${process.arch}\`) to avoid native module issues.` + ); + }, + }, + }; +} + +// ---- Internal utils ---- + +const NODE_MODULES_RE = + /^(?.+[\\/]node_modules[\\/])(?[^@\\/]+|@[^\\/]+[\\/][^\\/]+)(?:[\\/](?.+))?$/; + +const IMPORT_RE = /^(?!\.)(?[^@/\\]+|@[^/\\]+[/\\][^/\\]+)(?:[/\\](?.+))?$/; + +function toImport(id: string): string | undefined { + if (isAbsolute(id)) { + const { name, subpath } = NODE_MODULES_RE.exec(id)?.groups || ({} as Record); + if (name && subpath) { + return join(name, subpath); + } + } else if (IMPORT_RE.test(id)) { + return id; + } +} + +function guessSubpath(path: string, conditions: string[]): string | undefined { + const { dir, name, subpath } = NODE_MODULES_RE.exec(path)?.groups || {}; + if (!dir || !name || !subpath) { + return; + } + const pkgDir = join(dir, name) + "/"; + const exports = getPkgJSON(pkgDir)?.exports; + if (!exports || typeof exports !== "object") { + return; + } + for (const e of flattenExports(exports)) { + if (!conditions.includes(e.condition || "default")) { + continue; + } + if (e.fsPath === subpath) { + return join(name, e.subpath); + } + if (e.fsPath.includes("*")) { + const fsPathRe = new RegExp( + "^" + escapeRegExp(e.fsPath).replace(String.raw`\*`, "(.+?)") + "$" + ); + if (fsPathRe.test(subpath)) { + const matched = fsPathRe.exec(subpath)?.[1]; + if (matched) { + return join(name, e.subpath.replace("*", matched)); + } + } + } + } +} + +function getPkgJSON(dir: string): PackageJson | undefined { + const cache = ((getPkgJSON as any)._cache ||= new Map()); + if (cache.has(dir)) { + return cache.get(dir); + } + try { + const pkg = createRequire(dir)("./package.json"); + cache.set(dir, pkg); + return pkg; + } catch { + /* ignore */ + } +} + +// Based on mlly +function flattenExports( + exports: Exclude = {}, + parentSubpath = "./" +): { subpath: string; fsPath: string; condition?: string }[] { + return Object.entries(exports).flatMap(([key, value]) => { + const [subpath, condition] = key.startsWith(".") ? [key.slice(1)] : [undefined, key]; + const _subPath = join(parentSubpath, subpath || ""); + if (typeof value === "string") { + return [{ subpath: _subPath, fsPath: value.replace(/^\.\//, ""), condition }]; + } + return typeof value === "object" ? flattenExports(value, _subPath) : []; + }); +} diff --git a/src/build/plugins/oxc.ts b/src/build/plugins/oxc.ts new file mode 100644 index 0000000000..15093b1236 --- /dev/null +++ b/src/build/plugins/oxc.ts @@ -0,0 +1,36 @@ +import type { MinifyOptions } from "rolldown/experimental"; +import type { OXCOptions } from "nitro/types"; +import type { Plugin } from "rollup"; + +export async function oxc( + options: OXCOptions & { sourcemap: boolean; minify: boolean | MinifyOptions } +): Promise { + const { minifySync, transformSync } = await import("rolldown/utils"); + return { + name: "nitro:oxc", + transform: { + filter: { + id: /^(?!.*\/node_modules\/).*\.m?[jt]sx?$/, + }, + handler(code, id) { + const res = transformSync(id, code, { + sourcemap: options.sourcemap, + tsconfig: false, + ...options.transform, + }); + if (res.errors?.length > 0) { + this.error(res.errors.join("\n")); + } + return res; + }, + }, + renderChunk(code, chunk) { + if (options.minify) { + return minifySync(chunk.fileName, code, { + sourcemap: options.sourcemap, + ...(typeof options.minify === "object" ? options.minify : {}), + }); + } + }, + }; +} diff --git a/src/build/plugins/raw.ts b/src/build/plugins/raw.ts new file mode 100644 index 0000000000..54adfe54b8 --- /dev/null +++ b/src/build/plugins/raw.ts @@ -0,0 +1,104 @@ +import { promises as fsp } from "node:fs"; +import mime from "mime"; +import type { Plugin } from "rollup"; + +const HELPER_ID = "virtual:nitro-raw-helpers"; +const RESOLVED_PREFIX = "virtual:nitro:raw:"; +const PREFIX = "raw:"; + +export function raw(): Plugin { + return { + name: "nitro:raw", + resolveId: { + order: "pre", + filter: { + id: [new RegExp(`^${HELPER_ID}$`), new RegExp(`^${PREFIX}`)], + }, + async handler(id, importer, resolveOpts) { + if (id === HELPER_ID) { + return id; + } + if (id.startsWith(PREFIX)) { + const resolvedId = (await this.resolve(id.slice(PREFIX.length), importer, resolveOpts)) + ?.id; + if (!resolvedId) { + return null; + } + return { id: RESOLVED_PREFIX + resolvedId }; + } + }, + }, + load: { + order: "pre", + filter: { + id: [new RegExp(`^${HELPER_ID}$`), new RegExp(`^${RESOLVED_PREFIX}`)], + }, + handler(id) { + if (id === HELPER_ID) { + return getHelpers(); + } + if (id.startsWith(RESOLVED_PREFIX)) { + // this.addWatchFile(id.substring(RESOLVED_PREFIX.length)); + return fsp.readFile(id.slice(RESOLVED_PREFIX.length), isBinary(id) ? "binary" : "utf8"); + } + }, + }, + transform: { + order: "pre", + filter: { + id: new RegExp(`^${RESOLVED_PREFIX}`), + }, + handler(code, id) { + const path = id.slice(RESOLVED_PREFIX.length); + if (isBinary(id)) { + const serialized = Buffer.from(code, "binary").toString("base64"); + return { + code: `import {base64ToUint8Array } from "${HELPER_ID}" \n export default base64ToUint8Array("${serialized}")`, + map: rawAssetMap(path), + }; + } + return { + code: `export default ${JSON.stringify(code)}`, + map: rawAssetMap(path), + moduleType: "js", + }; + }, + }, + }; +} + +function isBinary(id: string) { + const idMime = mime.getType(id) || ""; + if (idMime.startsWith("text/")) { + return false; + } + if (/application\/(json|sql|xml|yaml)/.test(idMime)) { + return false; + } + return true; +} + +function getHelpers() { + return /* js */ ` +export function base64ToUint8Array(str) { + const data = atob(str); + const size = data.length; + const bytes = new Uint8Array(size); + for (let i = 0; i < size; i++) { + bytes[i] = data.charCodeAt(i); + } + return bytes; +} + `; +} + +function rawAssetMap(id: string) { + return { + version: 3, + file: id, + sources: [id], + sourcesContent: [], + names: [], + mappings: "", + }; +} diff --git a/src/build/plugins/route-meta.ts b/src/build/plugins/route-meta.ts new file mode 100644 index 0000000000..bf31ff43ff --- /dev/null +++ b/src/build/plugins/route-meta.ts @@ -0,0 +1,107 @@ +import { readFile } from "node:fs/promises"; +import { isAbsolute } from "pathe"; +import type { Expression, Literal } from "estree"; +import type { Nitro, NitroEventHandler } from "nitro/types"; +import type { Plugin } from "rollup"; +import { escapeRegExp } from "../../utils/regex.ts"; + +const PREFIX = "\0nitro:route-meta:"; + +export async function routeMeta(nitro: Nitro) { + const { transformSync } = await import("rolldown/utils"); + return { + name: "nitro:route-meta", + resolveId: { + // eslint-disable-next-line no-control-regex + filter: { id: /^(?!\u0000)(.+)\?meta$/ }, + async handler(id, importer, resolveOpts) { + if (id.endsWith("?meta")) { + const resolved = await this.resolve(id.replace("?meta", ""), importer, resolveOpts); + if (!resolved) { + return; + } + return PREFIX + resolved.id; + } + }, + }, + load: { + filter: { + id: new RegExp(`^${escapeRegExp(PREFIX)}`), + }, + handler(id) { + if (id.startsWith(PREFIX)) { + const fullPath = id.slice(PREFIX.length); + if (isAbsolute(fullPath)) { + return readFile(fullPath, { encoding: "utf8" }); + } else { + return "export default undefined;"; + } + } + }, + }, + transform: { + filter: { + id: new RegExp(`^${escapeRegExp(PREFIX)}`), + }, + async handler(code, id) { + let meta: NitroEventHandler["meta"] | null = null; + + try { + const transformRes = transformSync(id, code, { tsconfig: false }); + if (transformRes.errors?.length > 0) { + for (const error of transformRes.errors) { + this.warn(error); + } + return { + code: `export default {};`, + map: null, + }; + } + + const ast = this.parse(transformRes.code); + for (const node of ast.body) { + if ( + node.type === "ExpressionStatement" && + node.expression.type === "CallExpression" && + node.expression.callee.type === "Identifier" && + node.expression.callee.name === "defineRouteMeta" && + node.expression.arguments.length === 1 + ) { + meta = astToObject(node.expression.arguments[0] as any); + break; + } + } + } catch (error) { + nitro.logger.warn(`[handlers-meta] Cannot extra route meta for: ${id}: ${error}`); + } + + return { + code: `export default ${JSON.stringify(meta)};`, + map: null, + }; + }, + }, + } satisfies Plugin; +} + +function astToObject(node: Expression | Literal): any { + switch (node.type) { + case "ObjectExpression": { + const obj: Record = {}; + for (const prop of node.properties) { + if (prop.type === "Property") { + const key = (prop.key as any).name ?? (prop.key as any).value; + obj[key] = astToObject(prop.value as any); + } + } + return obj; + } + case "ArrayExpression": { + return node.elements.map((el) => astToObject(el as any)).filter((obj) => obj !== undefined); + } + case "Literal": { + return node.value; + } + // No default + } +} diff --git a/src/build/plugins/server-main.ts b/src/build/plugins/server-main.ts new file mode 100644 index 0000000000..4b0104c67f --- /dev/null +++ b/src/build/plugins/server-main.ts @@ -0,0 +1,16 @@ +import type { Nitro } from "nitro/types"; +import type { Plugin } from "rollup"; + +export function serverMain(nitro: Nitro): Plugin { + return { + name: "nitro:server-main", + renderChunk(code, chunk) { + if (chunk.isEntry) { + return { + code: `globalThis.__nitro_main__ = import.meta.url; ${code}`, + map: null, + }; + } + }, + }; +} diff --git a/src/rollup/plugins/sourcemap-min.ts b/src/build/plugins/sourcemap-min.ts similarity index 51% rename from src/rollup/plugins/sourcemap-min.ts rename to src/build/plugins/sourcemap-min.ts index cf22ae88a8..91934e6939 100644 --- a/src/rollup/plugins/sourcemap-min.ts +++ b/src/build/plugins/sourcemap-min.ts @@ -1,28 +1,28 @@ import type { ExistingRawSourceMap, Plugin } from "rollup"; -export function sourcemapMininify() { +export function sourcemapMinify() { return { name: "nitro:sourcemap-minify", generateBundle(_options, bundle) { for (const [key, asset] of Object.entries(bundle)) { // Only process sourcemaps - if ( - !key.endsWith(".map") || - !("source" in asset) || - typeof asset.source !== "string" - ) { + if (!key.endsWith(".map") || !("source" in asset) || typeof asset.source !== "string") { continue; } + // Parse sourcemap const sourcemap: ExistingRawSourceMap = JSON.parse(asset.source); - // Only process sourcemaps with node_module sources - if ( - !(sourcemap.sources || []).some((s) => s.includes("node_modules")) - ) { - continue; + + // Remove sourcesContent + delete sourcemap.sourcesContent; + + // Remove x_google_ignoreList + delete sourcemap.x_google_ignoreList; + + if ((sourcemap.sources || []).every((s) => s.includes("node_modules"))) { + sourcemap.mappings = ""; // required key } - // TODO: Try to treeshake mappings instead - sourcemap.mappings = ""; + asset.source = JSON.stringify(sourcemap); } }, diff --git a/src/build/plugins/virtual.ts b/src/build/plugins/virtual.ts new file mode 100644 index 0000000000..1d327100ea --- /dev/null +++ b/src/build/plugins/virtual.ts @@ -0,0 +1,94 @@ +import type { Plugin, ResolvedId } from "rollup"; +import { pathRegExp } from "../../utils/regex.ts"; +import { runtimeDependencies, runtimeDir } from "nitro/meta"; + +export type VirtualModule = { + id: string; + moduleSideEffects?: boolean; + template: string | (() => string | Promise); +}; + +export function virtual(input: VirtualModule[]): Plugin { + const modules = new Map< + string, + { module: VirtualModule; render: () => string | Promise } + >(); + for (const mod of input) { + const render = () => (typeof mod.template === "function" ? mod.template() : mod.template); + modules.set(mod.id, { module: mod, render }); + } + + const include: RegExp[] = [/^#nitro\/virtual/]; + + const extraIds = [...modules.keys()].filter((key) => !key.startsWith("#nitro/virtual")); + if (extraIds.length > 0) { + include.push(new RegExp(`^(${extraIds.map((id) => pathRegExp(id)).join("|")})$`)); + } + + return { + name: "nitro:virtual", + api: { + modules, + }, + resolveId: { + order: "pre", + filter: { id: include }, + handler: (id) => { + const mod = modules.get(id); + if (mod) { + return { + id, + moduleSideEffects: mod.module.moduleSideEffects ?? false, + }; + } + }, + }, + load: { + order: "pre", + filter: { id: include }, + handler: async (id) => { + const mod = modules.get(id); + if (!mod) { + throw new Error(`Virtual module ${id} not found.`); + } + return { + code: await mod.render(), + map: null, + }; + }, + }, + }; +} + +export function virtualDeps(): Plugin { + const cache = new Map>(); + + return { + name: "nitro:virtual-deps", + resolveId: { + order: "pre", + filter: { + id: new RegExp(`^(#nitro|${runtimeDependencies.map((dep) => pathRegExp(dep)).join("|")})`), + }, + handler(id, importer) { + // https://github.com/rolldown/rolldown/issues/7529 + if (!importer || !importer.startsWith("#nitro/virtual")) { + return; + } + let resolved = cache.get(id); + if (!resolved) { + resolved = this.resolve(id, runtimeDir) + .then((_resolved) => { + cache.set(id, _resolved); + return _resolved; + }) + .catch((error) => { + cache.delete(id); + throw error; + }); + } + return resolved; + }, + }, + }; +} diff --git a/src/core/build/prepare.ts b/src/build/prepare.ts similarity index 91% rename from src/core/build/prepare.ts rename to src/build/prepare.ts index d6248bff0b..d1e25ed29c 100644 --- a/src/core/build/prepare.ts +++ b/src/build/prepare.ts @@ -1,5 +1,5 @@ import fsp from "node:fs/promises"; -import type { Nitro } from "nitropack"; +import type { Nitro } from "nitro/types"; export async function prepare(nitro: Nitro) { await prepareDir(nitro.options.output.dir); diff --git a/src/build/rolldown/build.ts b/src/build/rolldown/build.ts new file mode 100644 index 0000000000..e00c4631cc --- /dev/null +++ b/src/build/rolldown/build.ts @@ -0,0 +1,11 @@ +import { getRolldownConfig } from "./config.ts"; +import type { Nitro } from "nitro/types"; +import { watchDev } from "./dev.ts"; +import { buildProduction } from "./prod.ts"; + +export async function rolldownBuild(nitro: Nitro) { + await nitro.hooks.callHook("build:before", nitro); + const config = await getRolldownConfig(nitro); + await nitro.hooks.callHook("rollup:before", nitro, config as any); + return nitro.options.dev ? watchDev(nitro, config) : buildProduction(nitro, config); +} diff --git a/src/build/rolldown/config.ts b/src/build/rolldown/config.ts new file mode 100644 index 0000000000..c10df2d8ed --- /dev/null +++ b/src/build/rolldown/config.ts @@ -0,0 +1,80 @@ +import type { Nitro } from "nitro/types"; +import type { OutputOptions, RolldownOptions, RolldownPlugin } from "rolldown"; +import { baseBuildConfig } from "../config.ts"; +import { baseBuildPlugins } from "../plugins.ts"; +import { builtinModules } from "node:module"; +import { defu } from "defu"; +import { getChunkName, libChunkName, NODE_MODULES_RE } from "../chunks.ts"; + +export const getRolldownConfig = async (nitro: Nitro): Promise => { + const base = baseBuildConfig(nitro); + + const tsc = nitro.options.typescript.tsConfig?.compilerOptions; + + let config: RolldownOptions = { + platform: nitro.options.node ? "node" : "neutral", + cwd: nitro.options.rootDir, + input: nitro.options.entry, + external: [...base.env.external, ...builtinModules, ...builtinModules.map((m) => `node:${m}`)], + plugins: [...((await baseBuildPlugins(nitro, base)) as RolldownPlugin[])], + resolve: { + alias: base.aliases, + extensions: base.extensions, + conditionNames: nitro.options.exportConditions, + }, + transform: { + inject: base.env.inject as Record, + jsx: { + runtime: tsc?.jsx === "react" ? "classic" : "automatic", + pragma: tsc?.jsxFactory, + pragmaFrag: tsc?.jsxFragmentFactory, + importSource: tsc?.jsxImportSource, + development: nitro.options.dev, + }, + }, + onwarn(warning, warn) { + if (!base.ignoreWarningCodes.has(warning.code || "")) { + console.log(warning.code); + warn(warning); + } + }, + treeshake: { + moduleSideEffects(id) { + return nitro.options.moduleSideEffects.some((p) => id.startsWith(p)); + }, + }, + optimization: { + inlineConst: true, + }, + output: { + format: "esm", + entryFileNames: "index.mjs", + chunkFileNames: (chunk) => getChunkName(chunk, nitro), + codeSplitting: { + groups: [{ test: NODE_MODULES_RE, name: (id) => libChunkName(id) }], + }, + dir: nitro.options.output.serverDir, + inlineDynamicImports: nitro.options.inlineDynamicImports, + // https://github.com/rolldown/rolldown/issues/7235 + minify: nitro.options.minify ? true : "dce-only", + sourcemap: nitro.options.sourcemap, + sourcemapIgnoreList(relativePath) { + return relativePath.includes("node_modules"); + }, + }, + } satisfies RolldownOptions; + + config = defu( + nitro.options.rolldownConfig, + nitro.options.rollupConfig as RolldownOptions, + config + ); + + const outputConfig = config.output as OutputOptions; + if (outputConfig.inlineDynamicImports || outputConfig.format === "iife") { + delete outputConfig.inlineDynamicImports; + outputConfig.codeSplitting = false; + } + + return config as RolldownOptions; +}; diff --git a/src/build/rolldown/dev.ts b/src/build/rolldown/dev.ts new file mode 100644 index 0000000000..4b41eac4d7 --- /dev/null +++ b/src/build/rolldown/dev.ts @@ -0,0 +1,98 @@ +import type { Nitro } from "nitro/types"; +import type { RolldownWatcher, RolldownOptions } from "rolldown"; +import { watch as chokidarWatch } from "chokidar"; +import { basename, join } from "pathe"; +import { debounce } from "perfect-debounce"; +import { scanHandlers } from "../../scan.ts"; +import { writeTypes } from "../types.ts"; +import { formatCompatibilityDate } from "compatx"; + +export async function watchDev(nitro: Nitro, config: RolldownOptions) { + const rolldown = await import("rolldown"); + + let watcher: RolldownWatcher; + + async function load() { + if (watcher) { + await watcher.close(); + } + await scanHandlers(nitro); + nitro.routing.sync(); + watcher = startWatcher(nitro, config); + await writeTypes(nitro); + } + const reload = debounce(load); + + const scanDirs = nitro.options.scanDirs.flatMap((dir) => [ + join(dir, nitro.options.apiDir || "api"), + join(dir, nitro.options.routesDir || "routes"), + join(dir, "middleware"), + join(dir, "plugins"), + join(dir, "modules"), + ]); + + const watchReloadEvents = new Set(["add", "addDir", "unlink", "unlinkDir"]); + const scanDirsWatcher = chokidarWatch(scanDirs, { + ignoreInitial: true, + }).on("all", (event) => { + if (watchReloadEvents.has(event)) { + reload(); + } + }); + + const serverEntryRe = /^server\.[mc]?[jt]sx?$/; + const rootDirWatcher = chokidarWatch(nitro.options.rootDir, { + ignoreInitial: true, + depth: 0, + }).on("all", (event, path) => { + if (watchReloadEvents.has(event) && serverEntryRe.test(basename(path))) { + reload(); + } + }); + + nitro.hooks.hook("close", () => { + watcher.close(); + scanDirsWatcher.close(); + rootDirWatcher.close(); + }); + + nitro.hooks.hook("rollup:reload", () => reload()); + + nitro.logger.info( + `Starting dev watcher (builder: \`rolldown\`, preset: \`${nitro.options.preset}\`, compatibility date: \`${formatCompatibilityDate(nitro.options.compatibilityDate)}\`)` + ); + + await load(); + + function startWatcher(nitro: Nitro, config: RolldownOptions) { + const watcher = rolldown.watch(config); + + let start: number; + + watcher.on("event", (event) => { + // START > BUNDLE_START > BUNDLE_END > END + // START > BUNDLE_START > ERROR > END + switch (event.code) { + case "START": { + start = Date.now(); + nitro.hooks.callHook("dev:start"); + break; + } + case "BUNDLE_END": { + nitro.hooks.callHook("compiled", nitro); + if (nitro.options.logging.buildSuccess) { + nitro.logger.success(`Server built`, start ? `in ${Date.now() - start}ms` : ""); + } + nitro.hooks.callHook("dev:reload"); + break; + } + case "ERROR": { + nitro.logger.error(event.error); + nitro.hooks.callHook("dev:error", event.error); + } + } + }); + + return watcher; + } +} diff --git a/src/build/rolldown/prod.ts b/src/build/rolldown/prod.ts new file mode 100644 index 0000000000..b241f8bbec --- /dev/null +++ b/src/build/rolldown/prod.ts @@ -0,0 +1,57 @@ +import type { Nitro } from "nitro/types"; +import type { OutputOptions, RolldownOptions } from "rolldown"; +import { formatCompatibilityDate } from "compatx"; + +import { relative } from "pathe"; +import { scanHandlers } from "../../scan.ts"; +import { generateFSTree } from "../../utils/fs-tree.ts"; +import { writeTypes } from "../types.ts"; +import { writeBuildInfo } from "../info.ts"; +import type { RolldownOutput } from "rolldown"; + +export async function buildProduction(nitro: Nitro, config: RolldownOptions) { + const rolldown = await import("rolldown"); + + const buildStartTime = Date.now(); + + await scanHandlers(nitro); + await writeTypes(nitro); + + let output: RolldownOutput | undefined; + if (!nitro.options.static) { + nitro.logger.info( + `Building server (builder: \`rolldown\`, preset: \`${nitro.options.preset}\`, compatibility date: \`${formatCompatibilityDate(nitro.options.compatibilityDate)}\`)` + ); + const build = await rolldown.rolldown(config); + output = (await build.write(config.output as OutputOptions)) as RolldownOutput; + } + + const buildInfo = await writeBuildInfo(nitro, output); + + if (!nitro.options.static) { + if (nitro.options.logging.buildSuccess) { + nitro.logger.success(`Server built in ${Date.now() - buildStartTime}ms`); + } + if (nitro.options.logLevel > 1) { + process.stdout.write( + (await generateFSTree(nitro.options.output.serverDir, { + compressedSizes: nitro.options.logging.compressedSizes, + })) || "" + ); + } + } + + await nitro.hooks.callHook("compiled", nitro); + + // Show deploy and preview hints + const rOutput = relative(process.cwd(), nitro.options.output.dir); + const rewriteRelativePaths = (input: string) => { + return input.replace(/([\s:])\.\/(\S*)/g, `$1${rOutput}/$2`); + }; + nitro.logger.success("You can preview this build using `npx nitro preview`"); + if (buildInfo.commands!.deploy) { + nitro.logger.success( + rewriteRelativePaths("You can deploy this build using `npx nitro deploy --prebuilt`") + ); + } +} diff --git a/src/build/rollup/build.ts b/src/build/rollup/build.ts new file mode 100644 index 0000000000..72e0e984ec --- /dev/null +++ b/src/build/rollup/build.ts @@ -0,0 +1,11 @@ +import { getRollupConfig } from "./config.ts"; +import type { Nitro } from "nitro/types"; +import { watchDev } from "./dev.ts"; +import { buildProduction } from "./prod.ts"; + +export async function rollupBuild(nitro: Nitro) { + await nitro.hooks.callHook("build:before", nitro); + const config = await getRollupConfig(nitro); + await nitro.hooks.callHook("rollup:before", nitro, config); + return nitro.options.dev ? watchDev(nitro, config) : buildProduction(nitro, config); +} diff --git a/src/build/rollup/config.ts b/src/build/rollup/config.ts new file mode 100644 index 0000000000..49925ac284 --- /dev/null +++ b/src/build/rollup/config.ts @@ -0,0 +1,90 @@ +import type { Nitro, RollupConfig } from "nitro/types"; +import { defu } from "defu"; +import alias from "@rollup/plugin-alias"; +import commonjs from "@rollup/plugin-commonjs"; +import inject from "@rollup/plugin-inject"; +import json from "@rollup/plugin-json"; +import { nodeResolve } from "@rollup/plugin-node-resolve"; +import { oxc } from "../plugins/oxc.ts"; +import { baseBuildConfig } from "../config.ts"; +import { baseBuildPlugins } from "../plugins.ts"; +import { getChunkName, libChunkName, NODE_MODULES_RE } from "../chunks.ts"; + +export const getRollupConfig = async (nitro: Nitro): Promise => { + const base = baseBuildConfig(nitro); + + const tsc = nitro.options.typescript.tsConfig?.compilerOptions; + + let config: RollupConfig = { + input: nitro.options.entry, + external: [...base.env.external], + plugins: [ + ...(await baseBuildPlugins(nitro, base)), + await oxc({ + sourcemap: !!nitro.options.sourcemap, + minify: nitro.options.minify ? { ...nitro.options.oxc?.minify } : false, + transform: { + target: "esnext", + // @ts-expect-error TODO: does option exists? + cwd: nitro.options.rootDir, + ...nitro.options.oxc?.transform, + jsx: { + runtime: tsc?.jsx === "react" ? "classic" : "automatic", + pragma: tsc?.jsxFactory, + pragmaFrag: tsc?.jsxFragmentFactory, + importSource: tsc?.jsxImportSource, + development: nitro.options.dev, + ...nitro.options.oxc?.transform?.jsx, + }, + }, + }), + alias({ entries: base.aliases }), + nodeResolve({ + extensions: base.extensions, + preferBuiltins: !!nitro.options.node, + rootDir: nitro.options.rootDir, + exportConditions: nitro.options.exportConditions, + }), + (commonjs as unknown as typeof commonjs.default)({ + ...nitro.options.commonJS, + }), + (json as unknown as typeof json.default)(), + (inject as unknown as typeof inject.default)(base.env.inject), + ], + onwarn(warning, rollupWarn) { + if (!base.ignoreWarningCodes.has(warning.code || "")) { + rollupWarn(warning); + } + }, + treeshake: { + moduleSideEffects(id) { + return nitro.options.moduleSideEffects.some((p) => id.startsWith(p)); + }, + }, + output: { + format: "esm", + entryFileNames: "index.mjs", + chunkFileNames: (chunk) => getChunkName(chunk, nitro), + dir: nitro.options.output.serverDir, + inlineDynamicImports: nitro.options.inlineDynamicImports, + generatedCode: { constBindings: true }, + sourcemap: nitro.options.sourcemap, + sourcemapExcludeSources: true, + sourcemapIgnoreList: (id) => id.includes("node_modules"), + manualChunks(id: string) { + if (NODE_MODULES_RE.test(id)) { + return libChunkName(id); + } + }, + }, + } satisfies RollupConfig; + + config = defu(nitro.options.rollupConfig as any, config); + + const outputConfig = config.output as NonNullable; + if (outputConfig.inlineDynamicImports || outputConfig.format === "iife") { + delete outputConfig.manualChunks; + } + + return config; +}; diff --git a/src/build/rollup/dev.ts b/src/build/rollup/dev.ts new file mode 100644 index 0000000000..20f1fb5eb3 --- /dev/null +++ b/src/build/rollup/dev.ts @@ -0,0 +1,105 @@ +import type { Nitro, RollupConfig } from "nitro/types"; +import type { RollupWatcher } from "rollup"; +import { watch as chokidarWatch } from "chokidar"; +import { defu } from "defu"; +import { basename, join } from "pathe"; +import { debounce } from "perfect-debounce"; +import { scanHandlers } from "../../scan.ts"; +import { formatRollupError } from "./error.ts"; +import { writeTypes } from "../types.ts"; +import { formatCompatibilityDate } from "compatx"; + +export async function watchDev(nitro: Nitro, rollupConfig: RollupConfig) { + const rollup = await import("rollup"); + + let rollupWatcher: RollupWatcher; + + async function load() { + if (rollupWatcher) { + await rollupWatcher.close(); + } + await scanHandlers(nitro); + nitro.routing.sync(); + rollupWatcher = startRollupWatcher(nitro, rollupConfig); + await writeTypes(nitro); + } + const reload = debounce(load); + + const scanDirs = nitro.options.scanDirs.flatMap((dir) => [ + join(dir, nitro.options.apiDir || "api"), + join(dir, nitro.options.routesDir || "routes"), + join(dir, "middleware"), + join(dir, "plugins"), + join(dir, "modules"), + ]); + + const watchReloadEvents = new Set(["add", "addDir", "unlink", "unlinkDir"]); + const scanDirsWatcher = chokidarWatch(scanDirs, { + ignoreInitial: true, + }).on("all", (event, path, stat) => { + if (watchReloadEvents.has(event)) { + reload(); + } + }); + + const serverEntryRe = /^server\.[mc]?[jt]sx?$/; + const rootDirWatcher = chokidarWatch(nitro.options.rootDir, { + ignoreInitial: true, + depth: 0, + }).on("all", (event, path) => { + if (watchReloadEvents.has(event) && serverEntryRe.test(basename(path))) { + reload(); + } + }); + + nitro.hooks.hook("close", () => { + rollupWatcher.close(); + scanDirsWatcher.close(); + rootDirWatcher.close(); + }); + + nitro.hooks.hook("rollup:reload", () => reload()); + + nitro.logger.info( + `Starting dev watcher (builder: \`rollup\`, preset: \`${nitro.options.preset}\`, compatibility date: \`${formatCompatibilityDate(nitro.options.compatibilityDate)}\`)` + ); + + await load(); + + function startRollupWatcher(nitro: Nitro, rollupConfig: RollupConfig) { + const watcher = rollup.watch( + defu(rollupConfig, { + watch: { + chokidar: nitro.options.watchOptions, + }, + }) + ); + let start: number; + + watcher.on("event", (event) => { + // START > BUNDLE_START > BUNDLE_END > END + // START > BUNDLE_START > ERROR > END + switch (event.code) { + case "START": { + start = Date.now(); + nitro.hooks.callHook("dev:start"); + break; + } + case "BUNDLE_END": { + nitro.hooks.callHook("compiled", nitro); + if (nitro.options.logging.buildSuccess) { + nitro.logger.success(`Server built`, start ? `in ${Date.now() - start}ms` : ""); + } + nitro.hooks.callHook("dev:reload"); + break; + } + case "ERROR": { + nitro.logger.error(formatRollupError(event.error)); + nitro.hooks.callHook("dev:error", event.error); + } + } + }); + + return watcher; + } +} diff --git a/src/build/rollup/error.ts b/src/build/rollup/error.ts new file mode 100644 index 0000000000..4f92cbb632 --- /dev/null +++ b/src/build/rollup/error.ts @@ -0,0 +1,22 @@ +import { isAbsolute, relative } from "pathe"; +import type rollup from "rollup"; + +export function formatRollupError(_error: rollup.RollupError) { + try { + const logs: string[] = [_error.toString()]; + const errors = (_error as any)?.errors || [_error as rollup.RollupError]; + for (const error of errors) { + const id = (error as any).path || error.id || (_error as rollup.RollupError).id; + let path = isAbsolute(id) ? relative(process.cwd(), id) : id; + const location = (error as rollup.RollupError).loc; + if (location) { + path += `:${location.line}:${location.column}`; + } + const text = (error as rollup.RollupError).frame; + logs.push(`Rollup error while processing \`${path}\`` + text ? "\n\n" + text : ""); + } + return logs.join("\n"); + } catch { + return _error?.toString(); + } +} diff --git a/src/build/rollup/prod.ts b/src/build/rollup/prod.ts new file mode 100644 index 0000000000..defbceeb50 --- /dev/null +++ b/src/build/rollup/prod.ts @@ -0,0 +1,53 @@ +import type { Nitro, RollupConfig } from "nitro/types"; +import { formatCompatibilityDate } from "compatx"; +import { scanHandlers } from "../../scan.ts"; +import { generateFSTree } from "../../utils/fs-tree.ts"; +import { writeTypes } from "../types.ts"; +import { writeBuildInfo } from "../info.ts"; +import { formatRollupError } from "./error.ts"; +import type { RollupOutput } from "rollup"; + +export async function buildProduction(nitro: Nitro, rollupConfig: RollupConfig) { + const rollup = await import("rollup"); + + const buildStartTime = Date.now(); + + await scanHandlers(nitro); + await writeTypes(nitro); + + let output: RollupOutput | undefined; + if (!nitro.options.static) { + nitro.logger.info( + `Building server (builder: \`rollup\`, preset: \`${nitro.options.preset}\`, compatibility date: \`${formatCompatibilityDate(nitro.options.compatibilityDate)}\`)` + ); + const build = await rollup.rollup(rollupConfig).catch((error) => { + nitro.logger.error(formatRollupError(error)); + throw error; + }); + + output = await build.write(rollupConfig.output!); + } + + const buildInfo = await writeBuildInfo(nitro, output); + + if (!nitro.options.static) { + if (nitro.options.logging.buildSuccess) { + nitro.logger.success(`Server built in ${Date.now() - buildStartTime}ms`); + } + if (nitro.options.logLevel > 1) { + process.stdout.write( + (await generateFSTree(nitro.options.output.serverDir, { + compressedSizes: nitro.options.logging.compressedSizes, + })) || "" + ); + } + } + + await nitro.hooks.callHook("compiled", nitro); + + // Show deploy and preview hints + nitro.logger.success("You can preview this build using `npx nitro preview`"); + if (buildInfo.commands!.deploy) { + nitro.logger.success("You can deploy this build using `npx nitro deploy --prebuilt`"); + } +} diff --git a/src/core/build/types.ts b/src/build/types.ts similarity index 57% rename from src/core/build/types.ts rename to src/build/types.ts index b0be180773..0f8d163c1a 100644 --- a/src/core/build/types.ts +++ b/src/build/types.ts @@ -1,16 +1,16 @@ import { existsSync, promises as fsp } from "node:fs"; import { defu } from "defu"; -import { genTypeImport } from "knitwork"; import { lookupNodeModuleSubpath, parseNodeModulePath } from "mlly"; import { resolveModulePath } from "exsolve"; -import { isDirectory, resolveNitroPath, writeFile } from "nitropack/kit"; -import { runtimeDir } from "nitropack/runtime/meta"; -import type { Nitro, NitroTypes } from "nitropack/types"; +import { isDirectory, resolveNitroPath, writeFile } from "../utils/fs.ts"; +import { runtimeDir } from "nitro/meta"; +import type { Nitro, NitroTypes } from "nitro/types"; import { dirname, isAbsolute, join, resolve } from "pathe"; import { relative } from "pathe"; import { resolveAlias } from "pathe/utils"; import type { TSConfig } from "pkg-types"; -import { type JSValue, generateTypes, resolveSchema } from "untyped"; +import type { JSValue } from "untyped"; +import { generateTypes, resolveSchema } from "untyped"; import { toExports } from "unimport"; export async function writeTypes(nitro: Nitro) { @@ -18,7 +18,10 @@ export async function writeTypes(nitro: Nitro) { routes: {}, }; - const typesDir = resolve(nitro.options.buildDir, "types"); + const generatedTypesDir = resolve( + nitro.options.rootDir, + nitro.options.typescript.generatedTypesDir || "node_modules/.nitro/types" + ); const middleware = [...nitro.scannedHandlers, ...nitro.options.handlers]; @@ -27,7 +30,7 @@ export async function writeTypes(nitro: Nitro) { continue; } const relativePath = relative( - typesDir, + generatedTypesDir, resolveNitroPath(mw.handler, nitro.options) ).replace(/\.(js|mjs|cjs|ts|mts|cts|tsx|jsx)$/, ""); @@ -52,20 +55,21 @@ export async function writeTypes(nitro: Nitro) { autoImportExports = toExports(allImports).replace( /#internal\/nitro/g, - relative(typesDir, runtimeDir) + relative(generatedTypesDir, runtimeDir) ); const resolvedImportPathMap = new Map(); - for (const i of allImports.filter((i) => !i.type)) { - if (resolvedImportPathMap.has(i.from)) { + for (const i of allImports) { + const from = i.typeFrom || i.from; + if (resolvedImportPathMap.has(from)) { continue; } - let path = resolveAlias(i.from, nitro.options.alias); + let path = resolveAlias(from, nitro.options.alias); if (!isAbsolute(path)) { - const resolvedPath = resolveModulePath(i.from, { + const resolvedPath = resolveModulePath(from, { try: true, - from: nitro.options.nodeModulesDirs, + from: nitro.options.rootDir, conditions: ["type", "node", "import"], suffixes: ["", "/index"], extensions: [".mjs", ".cjs", ".js", ".mts", ".cts", ".ts"], @@ -84,9 +88,9 @@ export async function writeTypes(nitro: Nitro) { path = path.replace(/\.[a-z]+$/, ""); } if (isAbsolute(path)) { - path = relative(typesDir, path); + path = relative(generatedTypesDir, path); } - resolvedImportPathMap.set(i.from, path); + resolvedImportPathMap.set(from, path); } autoImportedTypes = [ @@ -94,19 +98,20 @@ export async function writeTypes(nitro: Nitro) { ? ( await nitro.unimport.generateTypeDeclarations({ exportHelper: false, - resolvePath: (i) => resolvedImportPathMap.get(i.from) ?? i.from, + resolvePath: (i) => { + const from = i.typeFrom || i.from; + return resolvedImportPathMap.get(from) ?? from; + }, }) ).trim() : "", ]; } - await nitro.hooks.callHook("types:extend", types); - - const routes = [ + const generateRoutes = () => [ "// Generated by nitro", - 'import type { Serialize, Simplify } from "nitropack/types";', - 'declare module "nitropack/types" {', + 'import type { Serialize, Simplify } from "nitro/types";', + 'declare module "nitro/types" {', " type Awaited = T extends PromiseLike ? Awaited : T", " interface InternalApi {", ...Object.entries(types.routes).map(([path, methods]) => @@ -126,24 +131,7 @@ export async function writeTypes(nitro: Nitro) { const config = [ "// Generated by nitro", - ` -// App Config -import type { Defu } from 'defu' - -${nitro.options.appConfigFiles - .map((file, index) => - genTypeImport(relative(typesDir, file).replace(/\.\w+$/, ""), [ - { name: "default", as: `appConfig${index}` }, - ]) - ) - .join("\n")} - -type UserAppConfig = Defu<{}, [${nitro.options.appConfigFiles - .map((_, index: number) => `typeof appConfig${index}`) - .join(", ")}]> - -declare module "nitropack/types" { - interface AppConfig extends UserAppConfig {}`, + /* ts */ `declare module "nitro/types" {`, nitro.options.typescript.generateRuntimeConfigTypes ? generateTypes( await resolveSchema( @@ -168,115 +156,77 @@ declare module "nitropack/types" { ]; const declarations = [ - // local nitropack augmentations + // local nitro augmentations '/// ', '/// ', // global server auto-imports '/// ', ]; - const buildFiles: { path: string; contents: string }[] = []; + const buildFiles: { path: string; contents: string | (() => string) }[] = []; buildFiles.push({ - path: join(typesDir, "nitro-routes.d.ts"), - contents: routes.join("\n"), + path: join(generatedTypesDir, "nitro-routes.d.ts"), + contents: () => generateRoutes().join("\n"), }); buildFiles.push({ - path: join(typesDir, "nitro-config.d.ts"), + path: join(generatedTypesDir, "nitro-config.d.ts"), contents: config.join("\n"), }); buildFiles.push({ - path: join(typesDir, "nitro-imports.d.ts"), - contents: [...autoImportedTypes, autoImportExports || "export {}"].join( - "\n" - ), + path: join(generatedTypesDir, "nitro-imports.d.ts"), + contents: [...autoImportedTypes, autoImportExports || "export {}"].join("\n"), }); buildFiles.push({ - path: join(typesDir, "nitro.d.ts"), + path: join(generatedTypesDir, "nitro.d.ts"), contents: declarations.join("\n"), }); if (nitro.options.typescript.generateTsConfig) { const tsConfigPath = resolve( - nitro.options.buildDir, - nitro.options.typescript.tsconfigPath + generatedTypesDir, + nitro.options.typescript.tsconfigPath || "tsconfig.json" ); const tsconfigDir = dirname(tsConfigPath); const tsConfig: TSConfig = defu(nitro.options.typescript.tsConfig, { compilerOptions: { - forceConsistentCasingInFileNames: true, - strict: nitro.options.typescript.strict, - noEmit: true, + /* Base options: */ + esModuleInterop: true, + allowSyntheticDefaultImports: true, + skipLibCheck: true, target: "ESNext", - module: "ESNext", - moduleResolution: - nitro.options.experimental.typescriptBundlerResolution === false - ? "Node" - : "Bundler", allowJs: true, resolveJsonModule: true, + moduleDetection: "force", + isolatedModules: true, + verbatimModuleSyntax: true, + allowImportingTsExtensions: true, + /* Strictness */ + strict: nitro.options.typescript.strict, + noUncheckedIndexedAccess: true, + noImplicitOverride: true, + forceConsistentCasingInFileNames: true, + /* If NOT transpiling with TypeScript: */ + module: "Preserve", jsx: "preserve", - allowSyntheticDefaultImports: true, jsxFactory: "h", jsxFragmentFactory: "Fragment", paths: { - "#imports": [ - relativeWithDot(tsconfigDir, join(typesDir, "nitro-imports")), - ], - "~/*": [ - relativeWithDot( - tsconfigDir, - join(nitro.options.alias["~"] || nitro.options.srcDir, "*") - ), - ], - "@/*": [ - relativeWithDot( - tsconfigDir, - join(nitro.options.alias["@"] || nitro.options.srcDir, "*") - ), - ], - "~~/*": [ - relativeWithDot( - tsconfigDir, - join(nitro.options.alias["~~"] || nitro.options.rootDir, "*") - ), - ], - "@@/*": [ - relativeWithDot( - tsconfigDir, - join(nitro.options.alias["@@"] || nitro.options.rootDir, "*") - ), - ], - ...(nitro.options.typescript.internalPaths - ? { - "nitropack/runtime": [ - relativeWithDot(tsconfigDir, join(runtimeDir, "index")), - ], - "#internal/nitro": [ - relativeWithDot(tsconfigDir, join(runtimeDir, "index")), - ], - "nitropack/runtime/*": [ - relativeWithDot(tsconfigDir, join(runtimeDir, "*")), - ], - "#internal/nitro/*": [ - relativeWithDot(tsconfigDir, join(runtimeDir, "*")), - ], - } - : {}), + "#imports": [relativeWithDot(tsconfigDir, join(generatedTypesDir, "nitro-imports"))], }, }, include: [ - relativeWithDot(tsconfigDir, join(typesDir, "nitro.d.ts")).replace( + relativeWithDot(tsconfigDir, join(generatedTypesDir, "nitro.d.ts")).replace( /^(?=[^.])/, "./" ), join(relativeWithDot(tsconfigDir, nitro.options.rootDir), "**/*"), - ...(nitro.options.srcDir === nitro.options.rootDir + ...(!nitro.options.serverDir || nitro.options.serverDir === nitro.options.rootDir ? [] - : [join(relativeWithDot(tsconfigDir, nitro.options.srcDir), "**/*")]), + : [join(relativeWithDot(tsconfigDir, nitro.options.serverDir), "**/*")]), ], }); @@ -286,14 +236,10 @@ declare module "nitropack/types" { if (!isAbsolute(path)) { return path; } - const stats = await fsp - .stat(path) - .catch(() => null /* file does not exist */); + const stats = await fsp.stat(path).catch(() => null /* file does not exist */); return relativeWithDot( tsconfigDir, - stats?.isFile() - ? path.replace(/(?<=\w)\.\w+$/g, "") /* remove extension */ - : path + stats?.isFile() ? path.replace(/(?<=\w)\.\w+$/g, "") /* remove extension */ : path ); }) ); @@ -302,32 +248,32 @@ declare module "nitropack/types" { tsConfig.include = [ ...new Set( - tsConfig.include!.map((p) => - isAbsolute(p) ? relativeWithDot(tsconfigDir, p) : p - ) + tsConfig.include!.map((p) => (isAbsolute(p) ? relativeWithDot(tsconfigDir, p) : p)) ), ]; if (tsConfig.exclude) { tsConfig.exclude = [ ...new Set( - tsConfig.exclude!.map((p) => - isAbsolute(p) ? relativeWithDot(tsconfigDir, p) : p - ) + tsConfig.exclude!.map((p) => (isAbsolute(p) ? relativeWithDot(tsconfigDir, p) : p)) ), ]; } + types.tsConfig = tsConfig; + buildFiles.push({ path: tsConfigPath, - contents: JSON.stringify(tsConfig, null, 2), + contents: () => JSON.stringify(tsConfig, null, 2), }); } + await nitro.hooks.callHook("types:extend", types); + await Promise.all( buildFiles.map(async (file) => { await writeFile( - resolve(nitro.options.buildDir, file.path), - file.contents + resolve(generatedTypesDir, file.path), + typeof file.contents === "string" ? file.contents : file.contents() ); }) ); diff --git a/src/build/virtual/_all.ts b/src/build/virtual/_all.ts new file mode 100644 index 0000000000..11f76f1fb0 --- /dev/null +++ b/src/build/virtual/_all.ts @@ -0,0 +1,45 @@ +import type { Nitro } from "nitro/types"; + +import database from "./database.ts"; +import errorHandler from "./error-handler.ts"; +import featureFlags from "./feature-flags.ts"; +import plugins from "./plugins.ts"; +import polyfills from "./polyfills.ts"; +import publicAssets from "./public-assets.ts"; +import rendererTemplate from "./renderer-template.ts"; +import routingMeta from "./routing-meta.ts"; +import routing from "./routing.ts"; +import runtimeConfig from "./runtime-config.ts"; +import serverAssets from "./server-assets.ts"; +import storage from "./storage.ts"; +import tasks from "./tasks.ts"; + +type VirtualTemplate = { + id: string; + template: string | (() => string | Promise); +}; + +export function virtualTemplates(nitro: Nitro, _polyfills: string[]): VirtualTemplate[] { + const nitroTemplates = [ + database, + errorHandler, + featureFlags, + plugins, + polyfills, + publicAssets, + rendererTemplate, + routingMeta, + routing, + runtimeConfig, + serverAssets, + storage, + tasks, + ].flatMap((t) => t(nitro, _polyfills)); + + const customTemplates = Object.entries(nitro.options.virtual).map(([id, template]) => ({ + id, + template, + })); + + return [...nitroTemplates, ...customTemplates]; +} diff --git a/src/build/virtual/database.ts b/src/build/virtual/database.ts new file mode 100644 index 0000000000..0c4c0c952a --- /dev/null +++ b/src/build/virtual/database.ts @@ -0,0 +1,44 @@ +import { connectors } from "db0"; +import type { Nitro } from "nitro/types"; +import { camelCase } from "scule"; + +export default function database(nitro: Nitro) { + return { + id: "#nitro/virtual/database", + template: () => { + if (!nitro.options.experimental.database) { + return /* js */ `export const connectionConfigs = {};`; + } + + const dbConfigs = (nitro.options.dev && nitro.options.devDatabase) || nitro.options.database; + + const connectorsNames = [ + ...new Set(Object.values(dbConfigs || {}).map((config) => config?.connector)), + ].filter(Boolean); + + for (const name of connectorsNames) { + if (!connectors[name]) { + throw new Error(`Database connector "${name}" is invalid.`); + } + } + + return /* js */ ` +${connectorsNames + .map((name) => /* js */ `import ${camelCase(name)}Connector from "${connectors[name]}";`) + .join("\n")} + +export const connectionConfigs = { + ${Object.entries(dbConfigs || {}) + .filter(([, config]) => !!config?.connector) + .map( + ([name, { connector, options }]) => /* js */ `${name}: { + connector: ${camelCase(connector)}Connector, + options: ${JSON.stringify(options)} + }` + ) + .join(",\n")} +}; + `; + }, + }; +} diff --git a/src/build/virtual/error-handler.ts b/src/build/virtual/error-handler.ts new file mode 100644 index 0000000000..02edc1e63b --- /dev/null +++ b/src/build/virtual/error-handler.ts @@ -0,0 +1,42 @@ +import type { Nitro } from "nitro/types"; +import { runtimeDir } from "nitro/meta"; +import { join } from "pathe"; + +export default function errorHandler(nitro: Nitro) { + return { + id: "#nitro/virtual/error-handler", + template: () => { + const errorHandlers = Array.isArray(nitro.options.errorHandler) + ? nitro.options.errorHandler + : [nitro.options.errorHandler]; + + const builtinHandler = join( + runtimeDir, + `internal/error/${nitro.options.dev ? "dev" : "prod"}` + ); + + return /* js */ ` +${errorHandlers.map((h, i) => `import errorHandler$${i} from "${h}";`).join("\n")} + +const errorHandlers = [${errorHandlers.map((_, i) => `errorHandler$${i}`).join(", ")}]; + +import { defaultHandler } from "${builtinHandler}"; + +export default async function(error, event) { + for (const handler of errorHandlers) { + try { + const response = await handler(error, event, { defaultHandler }); + if (response) { + return response; + } + } catch(error) { + // Handler itself thrown, log and continue + console.error(error); + } + } + // H3 will handle fallback +} +`; + }, + }; +} diff --git a/src/build/virtual/feature-flags.ts b/src/build/virtual/feature-flags.ts new file mode 100644 index 0000000000..54dbf9b13f --- /dev/null +++ b/src/build/virtual/feature-flags.ts @@ -0,0 +1,22 @@ +import type { Nitro } from "nitro/types"; + +export default function featureFlags(nitro: Nitro) { + return { + id: "#nitro/virtual/feature-flags", + template: () => { + const featureFlags: Record = { + // Routing + hasRoutes: nitro.routing.routes.hasRoutes(), + hasRouteRules: nitro.routing.routeRules.hasRoutes(), + hasRoutedMiddleware: nitro.routing.routedMiddleware.hasRoutes(), + hasGlobalMiddleware: nitro.routing.globalMiddleware.length > 0, + // Plugins + hasPlugins: nitro.options.plugins.length > 0, + hasHooks: nitro.options.features?.runtimeHooks ?? nitro.options.plugins.length > 0, + }; + return /* js */ Object.entries(featureFlags) + .map(([key, value]) => /* js */ `export const ${key} = ${Boolean(value)};`) + .join("\n"); + }, + }; +} diff --git a/src/build/virtual/plugins.ts b/src/build/virtual/plugins.ts new file mode 100644 index 0000000000..020f4cc6e7 --- /dev/null +++ b/src/build/virtual/plugins.ts @@ -0,0 +1,21 @@ +import type { Nitro } from "nitro/types"; +import { hash } from "ohash"; + +export default function plugins(nitro: Nitro) { + return { + id: "#nitro/virtual/plugins", + template: () => { + const nitroPlugins = [...new Set(nitro.options.plugins)]; + + return /* js */ ` + ${nitroPlugins + .map((plugin) => /* js */ `import _${hash(plugin).replace(/-/g, "")} from "${plugin}";`) + .join("\n")} + + export const plugins = [ + ${nitroPlugins.map((plugin) => `_${hash(plugin).replace(/-/g, "")}`).join(",\n")} + ] + `; + }, + }; +} diff --git a/src/build/virtual/polyfills.ts b/src/build/virtual/polyfills.ts new file mode 100644 index 0000000000..40854ee032 --- /dev/null +++ b/src/build/virtual/polyfills.ts @@ -0,0 +1,13 @@ +import type { Nitro } from "nitro/types"; + +export default function polyfills(_nitro: Nitro, polyfills: string[]) { + return { + id: "#nitro/virtual/polyfills", + moduleSideEffects: true, + template: () => { + return ( + polyfills.map((p) => /* js */ `import '${p}';`).join("\n") || /* js */ `/* No polyfills */` + ); + }, + }; +} diff --git a/src/build/virtual/public-assets.ts b/src/build/virtual/public-assets.ts new file mode 100644 index 0000000000..6602e8b3f7 --- /dev/null +++ b/src/build/virtual/public-assets.ts @@ -0,0 +1,192 @@ +import { promises as fsp } from "node:fs"; +import createEtag from "etag"; +import { glob } from "tinyglobby"; +import mime from "mime"; +import type { Nitro } from "nitro/types"; +import type { PublicAsset } from "nitro/types"; +import { relative, resolve } from "pathe"; +import { joinURL, withTrailingSlash } from "ufo"; +import { runParallel } from "../../utils/parallel.ts"; + +const readAssetHandler: Record< + Exclude, + "node" | "deno" | "null" | "inline" +> = { + true: "node", + node: "node", + false: "null", + deno: "deno", + inline: "inline", +}; + +export default function publicAssets(nitro: Nitro) { + return [ + // public-assets-data + { + id: "#nitro/virtual/public-assets-data", + template: async () => { + const assets: Record = {}; + const files = await glob("**", { + cwd: nitro.options.output.publicDir, + absolute: false, + dot: true, + }); + + const { errors } = await runParallel( + new Set(files), + async (id) => { + let mimeType = mime.getType(id.replace(/\.(gz|br|zst)$/, "")) || "text/plain"; + if (mimeType.startsWith("text")) { + mimeType += "; charset=utf-8"; + } + const fullPath = resolve(nitro.options.output.publicDir, id); + const [assetData, stat] = await Promise.all([ + fsp.readFile(fullPath), + fsp.stat(fullPath), + ]); + + const etag = createEtag(assetData); + + const assetId = joinURL(nitro.options.baseURL, decodeURIComponent(id)); + + let encoding; + if (id.endsWith(".gz")) { + encoding = "gzip"; + } else if (id.endsWith(".br")) { + encoding = "br"; + } else if (id.endsWith(".zst")) { + encoding = "zstd"; + } + + assets[assetId] = { + type: nitro._prerenderMeta?.[assetId]?.contentType || mimeType, + encoding, + etag, + mtime: stat.mtime.toJSON(), + size: stat.size, + path: relative(nitro.options.output.serverDir, fullPath), + data: + nitro.options.serveStatic === "inline" ? assetData.toString("base64") : undefined, + }; + }, + { concurrency: 25 } + ); + + if (errors.length > 0) { + throw new Error(`Failed to process public assets:\n${errors.join("\n")}`, { + cause: errors, + }); + } + + return `export default ${JSON.stringify(assets, null, 2)};`; + }, + }, + + // public-assets + { + id: "#nitro/virtual/public-assets", + template: () => { + const publicAssetBases = Object.fromEntries( + nitro.options.publicAssets + .filter((dir) => !dir.fallthrough && dir.baseURL !== "/") + .map((dir) => [ + withTrailingSlash(joinURL(nitro.options.baseURL, dir.baseURL || "/")), + { maxAge: dir.maxAge }, + ]) + ); + + // prettier-ignore + type _serveStaticAsKey = Exclude | "true" | "false"; + // prettier-ignore + const handlerName = readAssetHandler[nitro.options.serveStatic as _serveStaticAsKey] || "null"; + const readAssetImport = `#nitro/virtual/public-assets-${handlerName}`; + + return /* js */ ` +import assets from '#nitro/virtual/public-assets-data' +export { readAsset } from "${readAssetImport}" +export const publicAssetBases = ${JSON.stringify(publicAssetBases)} + +export function isPublicAssetURL(id = '') { + if (assets[id]) { + return true + } + for (const base in publicAssetBases) { + if (id.startsWith(base)) { return true } + } + return false +} + +export function getPublicAssetMeta(id = '') { + for (const base in publicAssetBases) { + if (id.startsWith(base)) { return publicAssetBases[base] } + } + return {} +} + +export function getAsset (id) { + return assets[id] +} +`; + }, + }, + + // TODO: Handlers can be static templates! + + // public-assets-node + { + id: "#nitro/virtual/public-assets-node", + template: () => { + return /* js */ ` +import { promises as fsp } from 'node:fs' +import { fileURLToPath } from 'node:url' +import { resolve, dirname } from 'node:path' +import assets from '#nitro/virtual/public-assets-data' +export function readAsset (id) { + const serverDir = dirname(fileURLToPath(globalThis.__nitro_main__)) + return fsp.readFile(resolve(serverDir, assets[id].path)) +}`; + }, + }, + + // public-assets-deno + { + id: "#nitro/virtual/public-assets-deno", + template: () => { + return /* js */ ` +import assets from '#nitro/virtual/public-assets-data' +export function readAsset (id) { + // https://deno.com/deploy/docs/serve-static-assets + const path = '.' + decodeURIComponent(new URL(\`../public\${id}\`, 'file://').pathname) + return Deno.readFile(path); +}`; + }, + }, + + // public-assets-null + { + id: "#nitro/virtual/public-assets-null", + template: () => { + return /* js */ ` + export function readAsset (id) { + return Promise.resolve(null); + }`; + }, + }, + + // public-assets-inline + { + id: "#nitro/virtual/public-assets-inline", + template: () => { + return /* js */ ` + import assets from '#nitro/virtual/public-assets-data' + export function readAsset (id) { + if (!assets[id]) { return undefined } + if (assets[id]._data) { return assets[id]._data } + if (!assets[id].data) { return assets[id].data } + assets[id]._data = Uint8Array.from(atob(assets[id].data), (c) => c.charCodeAt(0)) + return assets[id]._data +}`; + }, + }, + ]; +} diff --git a/src/build/virtual/renderer-template.ts b/src/build/virtual/renderer-template.ts new file mode 100644 index 0000000000..7ccb7af4e2 --- /dev/null +++ b/src/build/virtual/renderer-template.ts @@ -0,0 +1,48 @@ +import type { Nitro } from "nitro/types"; +import { readFile } from "node:fs/promises"; +import { hasTemplateSyntax, compileTemplateToString, RENDER_CONTEXT_KEYS } from "rendu"; + +export default function rendererTemplate(nitro: Nitro) { + return { + id: "#nitro/virtual/renderer-template", + template: async () => { + const template = nitro.options.renderer?.template; + if (typeof template !== "string") { + // No template + return /* js */ ` + export const rendererTemplate = () => ''; + export const rendererTemplateFile = undefined; + export const isStaticTemplate = true;`; + } + if (nitro.options.dev) { + // Development + return /* js */ ` + import { readFile } from 'node:fs/promises'; + export const rendererTemplate = () => readFile(${JSON.stringify(template)}, "utf8"); + export const rendererTemplateFile = ${JSON.stringify(template)}; + export const isStaticTemplate = ${JSON.stringify(nitro.options.renderer?.static)}; + `; + } else { + // Production + const html = await readFile(template, "utf8"); + const isStatic = nitro.options.renderer?.static ?? !hasTemplateSyntax(html); + if (isStatic) { + return /* js */ ` + import { HTTPResponse } from "h3"; + export const rendererTemplate = () => new HTTPResponse(${JSON.stringify(html)}, { headers: { "content-type": "text/html; charset=utf-8" } }); + `; + } else { + const template = compileTemplateToString(html, { + contextKeys: [...RENDER_CONTEXT_KEYS], + }); + return /* js */ ` + import { renderToResponse } from 'rendu' + import { serverFetch } from 'nitro/app' + const template = ${template}; + export const rendererTemplate = (request) => renderToResponse(template, { request, context: { serverFetch } }) + `; + } + } + }, + }; +} diff --git a/src/build/virtual/routing-meta.ts b/src/build/virtual/routing-meta.ts new file mode 100644 index 0000000000..c3828ca460 --- /dev/null +++ b/src/build/virtual/routing-meta.ts @@ -0,0 +1,31 @@ +import type { Nitro } from "nitro/types"; + +export default function routingMeta(nitro: Nitro) { + return { + id: "#nitro/virtual/routing-meta", + template: () => { + const handlers = Object.values(nitro.routing.routes.routes).flatMap((h) => h.data); + const routeHandlers = uniqueBy(handlers, "_importHash"); + + return /* js */ ` + ${routeHandlers + .map((h) => /* js */ `import ${h._importHash}Meta from "${h.handler}?meta";`) + .join("\n")} +export const handlersMeta = [ + ${handlers + .map( + (h) => + /* js */ `{ route: ${JSON.stringify(h.route)}, method: ${JSON.stringify( + h.method?.toLowerCase() + )}, meta: ${h._importHash}Meta }` + ) + .join(",\n")} + ]; + `.trim(); + }, + }; +} + +function uniqueBy(arr: T[], key: keyof T): T[] { + return [...new Map(arr.map((item) => [item[key], item])).values()]; +} diff --git a/src/build/virtual/routing.ts b/src/build/virtual/routing.ts new file mode 100644 index 0000000000..6b0c6d1c6b --- /dev/null +++ b/src/build/virtual/routing.ts @@ -0,0 +1,107 @@ +import type { Nitro, NitroEventHandler, NitroRouteRules } from "nitro/types"; + +export const RuntimeRouteRules = ["headers", "redirect", "proxy", "cache", "basicAuth"] as string[]; + +export default function routing(nitro: Nitro) { + return { + id: "#nitro/virtual/routing", + template: () => { + const allHandlers = uniqueBy( + [ + ...Object.values(nitro.routing.routes.routes).flatMap((h) => h.data), + ...Object.values(nitro.routing.routedMiddleware.routes).map((h) => h.data), + ...nitro.routing.globalMiddleware, + ], + "_importHash" + ); + + return /* js */ ` +import * as __routeRules__ from "#nitro/runtime/route-rules"; +import * as srvxNode from "srvx/node" +import * as h3 from "h3"; + +export const findRouteRules = ${nitro.routing.routeRules.compileToString({ serialize: serializeRouteRule, matchAll: true })} + +const multiHandler = (...handlers) => { + const final = handlers.pop() + const middleware = handlers.filter(Boolean).map(h => h3.toMiddleware(h)); + return (ev) => h3.callMiddleware(ev, middleware, final); +} + +${allHandlers + .filter((h) => !h.lazy) + .map((h) => /* js */ `import ${h._importHash} from "${h.handler}";`) + .join("\n")} + +${allHandlers + .filter((h) => h.lazy) + .map( + (h) => + /* js */ `const ${h._importHash} = h3.defineLazyEventHandler(() => import("${h.handler}")${h.format === "node" ? ".then(m => srvxNode.toFetchHandler(m.default))" : ""});` + ) + .join("\n")} + +export const findRoute = ${nitro.routing.routes.compileToString({ serialize: serializeHandler })} + +export const findRoutedMiddleware = ${nitro.routing.routedMiddleware.compileToString({ serialize: serializeHandler, matchAll: true })}; + +export const globalMiddleware = [ + ${nitro.routing.globalMiddleware.map((h) => (h.lazy ? h._importHash : `h3.toEventHandler(${h._importHash})`)).join(",")} +].filter(Boolean); + `; + }, + }; +} + +function uniqueBy(arr: T[], key: keyof T): T[] { + return [...new Map(arr.map((item) => [item[key], item])).values()]; +} + +// --- Serializing --- + +type MaybeArray = T | T[]; + +function serializeHandler(h: MaybeArray): string { + const meta = Array.isArray(h) ? h[0] : h; + + return `{${[ + `route:${JSON.stringify(meta.route)}`, + meta.method && `method:${JSON.stringify(meta.method)}`, + meta.meta && `meta:${JSON.stringify(meta.meta)}`, + `handler:${ + Array.isArray(h) + ? `multiHandler(${h.map((handler) => serializeHandlerFn(handler)).join(",")})` + : serializeHandlerFn(h) + }`, + ] + .filter(Boolean) + .join(",")}}`; +} + +function serializeHandlerFn(h: NitroEventHandler & { _importHash: string }): string { + let code = h._importHash; + if (!h.lazy) { + if (h.format === "node") { + code = `srvxNode.toFetchHandler(${code})`; + } + code = `h3.toEventHandler(${code})`; + } + return code; +} + +function serializeRouteRule(h: NitroRouteRules & { _route: string }): string { + return `[${Object.entries(h) + .filter(([name, options]) => options !== undefined && name[0] !== "_") + .map(([name, options]) => { + return `{${[ + `name:${JSON.stringify(name)}`, + `route:${JSON.stringify(h._route)}`, + h._method && `method:${JSON.stringify(h._method)}`, + RuntimeRouteRules.includes(name) && `handler:__routeRules__.${name}`, + `options:${JSON.stringify(options)}`, + ] + .filter(Boolean) + .join(",")}}`; + }) + .join(",")}]`; +} diff --git a/src/build/virtual/runtime-config.ts b/src/build/virtual/runtime-config.ts new file mode 100644 index 0000000000..c667c9c669 --- /dev/null +++ b/src/build/virtual/runtime-config.ts @@ -0,0 +1,12 @@ +import type { Nitro } from "nitro/types"; + +export default function runtimeConfig(nitro: Nitro) { + return { + id: "#nitro/virtual/runtime-config", + template: () => { + return /* js */ `export const runtimeConfig = ${JSON.stringify( + nitro.options.runtimeConfig || {} + )};`; + }, + }; +} diff --git a/src/build/virtual/server-assets.ts b/src/build/virtual/server-assets.ts new file mode 100644 index 0000000000..74c291c601 --- /dev/null +++ b/src/build/virtual/server-assets.ts @@ -0,0 +1,87 @@ +import { promises as fsp } from "node:fs"; +import createEtag from "etag"; +import { glob } from "tinyglobby"; +import mime from "mime"; +import type { Nitro } from "nitro/types"; +import { resolve } from "pathe"; +import { normalizeKey } from "unstorage"; + +interface ResolvedAsset { + fsPath: string; + meta: { + type?: string; + etag?: string; + mtime?: string; + }; +} + +export default function serverAssets(nitro: Nitro) { + return { + id: "#nitro/virtual/server-assets", + template: async () => { + if (nitro.options.dev || nitro.options.preset === "nitro-prerender") { + return /* js */ ` + import { createStorage } from 'unstorage' + import fsDriver from 'unstorage/drivers/fs' + const serverAssets = ${JSON.stringify(nitro.options.serverAssets)} + export const assets = createStorage() + for (const asset of serverAssets) { + assets.mount(asset.baseName, fsDriver({ base: asset.dir, ignore: (asset?.ignore || []) })) + }`; + } + + // Scan all assets + const assets: Record = {}; + for (const asset of nitro.options.serverAssets) { + const files = await glob(asset.pattern || "**/*", { + cwd: asset.dir, + absolute: false, + ignore: asset.ignore, + }); + for (const _id of files) { + const fsPath = resolve(asset.dir, _id); + const id = asset.baseName + "/" + _id; + assets[id] = { fsPath, meta: {} }; + // @ts-ignore TODO: Use mime@2 types + let type = mime.getType(id) || "text/plain"; + if (type.startsWith("text")) { + type += "; charset=utf-8"; + } + const etag = createEtag(await fsp.readFile(fsPath)); + const mtime = await fsp.stat(fsPath).then((s) => s.mtime.toJSON()); + assets[id].meta = { type, etag, mtime }; + } + } + return /* js */ ` +const _assets = {\n${Object.entries(assets) + .map( + ([id, asset]) => + ` [${JSON.stringify(normalizeKey(id))}]: {\n import: () => import(${JSON.stringify( + "raw:" + asset.fsPath + )}).then(r => r.default || r),\n meta: ${JSON.stringify(asset.meta)}\n }` + ) + .join(",\n")}\n} + +const normalizeKey = ${normalizeKey.toString()} + +export const assets = { + getKeys() { + return Promise.resolve(Object.keys(_assets)) + }, + hasItem (id) { + id = normalizeKey(id) + return Promise.resolve(id in _assets) + }, + getItem (id) { + id = normalizeKey(id) + return Promise.resolve(_assets[id] ? _assets[id].import() : null) + }, + getMeta (id) { + id = normalizeKey(id) + return Promise.resolve(_assets[id] ? _assets[id].meta : {}) + } +} +`; + }, + }; +} diff --git a/src/build/virtual/storage.ts b/src/build/virtual/storage.ts new file mode 100644 index 0000000000..6111f3bb42 --- /dev/null +++ b/src/build/virtual/storage.ts @@ -0,0 +1,47 @@ +import { genImport, genSafeVariableName } from "knitwork"; +import type { Nitro } from "nitro/types"; +import { builtinDrivers } from "unstorage"; + +export default function storage(nitro: Nitro) { + return { + id: "#nitro/virtual/storage", + template: () => { + const mounts: { path: string; driver: string; opts: object }[] = []; + + const isDevOrPrerender = nitro.options.dev || nitro.options.preset === "nitro-prerender"; + const storageMounts = isDevOrPrerender + ? { ...nitro.options.storage, ...nitro.options.devStorage } + : nitro.options.storage; + + for (const path in storageMounts) { + const { driver: driverName, ...driverOpts } = storageMounts[path]; + mounts.push({ + path, + driver: builtinDrivers[driverName as keyof typeof builtinDrivers] || driverName, + opts: driverOpts, + }); + } + + const driverImports = [...new Set(mounts.map((m) => m.driver))]; + + return /* js */ ` +import { createStorage } from 'unstorage' +import { assets } from '#nitro/virtual/server-assets' + +${driverImports.map((i) => genImport(i, genSafeVariableName(i))).join("\n")} + +export function initStorage() { + const storage = createStorage({}) + storage.mount('/assets', assets) + ${mounts + .map( + (m) => + `storage.mount('${m.path}', ${genSafeVariableName(m.driver)}(${JSON.stringify(m.opts)}))` + ) + .join("\n")} + return storage +} +`; + }, + }; +} diff --git a/src/build/virtual/tasks.ts b/src/build/virtual/tasks.ts new file mode 100644 index 0000000000..da7c1379fa --- /dev/null +++ b/src/build/virtual/tasks.ts @@ -0,0 +1,45 @@ +import type { Nitro } from "nitro/types"; +import { normalize } from "pathe"; + +export default function tasks(nitro: Nitro) { + return { + id: "#nitro/virtual/tasks", + template: () => { + const _scheduledTasks = Object.entries(nitro.options.scheduledTasks || {}) + .map(([cron, _tasks]) => { + const tasks = (Array.isArray(_tasks) ? _tasks : [_tasks]).filter((name) => { + if (!nitro.options.tasks[name]) { + nitro.logger.warn(`Scheduled task \`${name}\` is not defined!`); + return false; + } + return true; + }); + return { cron, tasks }; + }) + .filter((e) => e.tasks.length > 0); + const scheduledTasks: false | { cron: string; tasks: string[] }[] = + _scheduledTasks.length > 0 ? _scheduledTasks : false; + + return /* js */ ` +export const scheduledTasks = ${JSON.stringify(scheduledTasks)}; + +export const tasks = { + ${Object.entries(nitro.options.tasks) + .map( + ([name, task]) => + `"${name}": { + meta: { + description: ${JSON.stringify(task.description)}, + }, + resolve: ${ + task.handler + ? /* js */ `() => import("${normalize(task.handler)}").then(r => r.default || r)` + : "undefined" + }, + }` + ) + .join(",\n")} +};`; + }, + }; +} diff --git a/src/build/vite/build.ts b/src/build/vite/build.ts new file mode 100644 index 0000000000..42b15e231b --- /dev/null +++ b/src/build/vite/build.ts @@ -0,0 +1,19 @@ +import type { Nitro } from "nitro/types"; +import { isTest } from "std-env"; +import { nitro as nitroPlugin } from "nitro/vite"; + +export async function viteBuild(nitro: Nitro) { + if (nitro.options.dev) { + throw new Error("Nitro dev CLI does not supports vite. Please use `vite dev` instead."); + } + const { createBuilder } = await import((nitro.options as any).__vitePkg__ || "vite"); + const pluginInstance = nitroPlugin({ _nitro: nitro }); + (globalThis as any).__nitro_build__ = true; + const builder = await createBuilder({ + base: nitro.options.rootDir, + plugins: [pluginInstance], + logLevel: isTest ? "warn" : undefined, + }); + delete (globalThis as any).__nitro_build__; + await builder.buildApp(); +} diff --git a/src/build/vite/bundler.ts b/src/build/vite/bundler.ts new file mode 100644 index 0000000000..5da44dd5df --- /dev/null +++ b/src/build/vite/bundler.ts @@ -0,0 +1,110 @@ +import { defu } from "defu"; +import { baseBuildConfig, type BaseBuildConfig } from "../config.ts"; +import { getChunkName, libChunkName, NODE_MODULES_RE } from "../chunks.ts"; +import { baseBuildPlugins } from "../plugins.ts"; + +import type { RolldownConfig, RollupConfig } from "nitro/types"; +import type { Plugin as RollupPlugin } from "rollup"; +import type { NitroPluginContext } from "./types.ts"; + +export const getBundlerConfig = async ( + ctx: NitroPluginContext +): Promise<{ + base: BaseBuildConfig; + rollupConfig?: RollupConfig; + rolldownConfig?: RolldownConfig; +}> => { + const nitro = ctx.nitro!; + const base = baseBuildConfig(nitro); + + const commonConfig = { + input: nitro.options.entry, + external: [...base.env.external], + plugins: [...(await baseBuildPlugins(nitro, base))].filter(Boolean) as RollupPlugin[], + treeshake: { + moduleSideEffects(id) { + return nitro.options.moduleSideEffects.some((p) => id.startsWith(p)); + }, + }, + onwarn(warning, warn) { + if (!base.ignoreWarningCodes.has(warning.code || "")) { + warn(warning); + } + }, + output: { + dir: nitro.options.output.serverDir, + format: "esm", + entryFileNames: "index.mjs", + chunkFileNames: (chunk: { name: string; moduleIds: string[] }) => getChunkName(chunk, nitro), + inlineDynamicImports: nitro.options.inlineDynamicImports, + sourcemapIgnoreList: (id) => id.includes("node_modules"), + }, + } satisfies RollupConfig & RolldownConfig; + + if (ctx._isRolldown) { + // Rolldown + const rolldownConfig: RolldownConfig = defu( + { + transform: { + inject: base.env.inject as Record, + }, + output: { + codeSplitting: { + groups: [ + { + test: NODE_MODULES_RE, + name: (id: string) => libChunkName(id), + }, + ], + }, + }, + } satisfies RolldownConfig, + nitro.options.rolldownConfig, + nitro.options.rollupConfig as RolldownConfig, // Added for backward compatibility + commonConfig satisfies RolldownConfig + ); + + const outputConfig = rolldownConfig.output!; + if (outputConfig.inlineDynamicImports || outputConfig.format === ("iife" as string)) { + delete outputConfig.inlineDynamicImports; + outputConfig.codeSplitting = false; + } + + return { base, rolldownConfig }; + } else { + // Rollup + const inject = ( + (await import("@rollup/plugin-inject")) as unknown as typeof import("@rollup/plugin-inject") + ).default; + const alias = ( + (await import("@rollup/plugin-alias")) as unknown as typeof import("@rollup/plugin-alias") + ).default; + + const rollupConfig: RollupConfig = defu( + { + plugins: [inject(base.env.inject), alias({ entries: base.aliases })], + output: { + sourcemapExcludeSources: true, + generatedCode: { + constBindings: true, + }, + manualChunks(id: string) { + if (NODE_MODULES_RE.test(id)) { + return libChunkName(id); + } + }, + }, + } satisfies RollupConfig, + nitro.options.rolldownConfig as RollupConfig, // Added for backward compatibility + nitro.options.rollupConfig, + commonConfig + ); + + const outputConfig = rollupConfig.output!; + if (outputConfig.inlineDynamicImports || outputConfig.format === ("iife" as string)) { + delete outputConfig.manualChunks; + } + + return { base, rollupConfig }; + } +}; diff --git a/src/build/vite/dev.ts b/src/build/vite/dev.ts new file mode 100644 index 0000000000..04d1f0fd89 --- /dev/null +++ b/src/build/vite/dev.ts @@ -0,0 +1,247 @@ +import type { NitroPluginContext } from "./types.ts"; +import type { DevEnvironmentContext, ResolvedConfig, ViteDevServer } from "vite"; +import type { FetchFunctionOptions, FetchResult } from "vite/module-runner"; +import type { RunnerRPCHooks } from "env-runner"; + +import { IncomingMessage, ServerResponse } from "node:http"; +import { NodeRequest, sendNodeResponse } from "srvx/node"; +import { DevEnvironment } from "vite"; +import { createViteHotChannel } from "env-runner/vite"; +import { watch as chokidarWatch } from "chokidar"; +import { watch as fsWatch } from "node:fs"; +import { join } from "pathe"; +import { debounce } from "perfect-debounce"; +import { scanHandlers } from "../../scan.ts"; +import { getEnvRunner } from "./env.ts"; + +// https://vite.dev/guide/api-environment-runtimes.html#modulerunner + +// ---- Types ---- + +export type FetchHandler = (req: Request) => Promise; + +export interface DevServer extends RunnerRPCHooks { + fetch: FetchHandler; + init?: () => void | Promise; +} + +// ---- Fetchable Dev Environment ---- + +export function createFetchableDevEnvironment( + name: string, + config: ResolvedConfig, + devServer: DevServer, + entry: string, + opts?: { preventExternalize?: boolean } +): FetchableDevEnvironment { + const transport = createViteHotChannel(devServer, name); + const context: DevEnvironmentContext = { hot: true, transport }; + return new FetchableDevEnvironment(name, config, context, devServer, entry, opts); +} + +export class FetchableDevEnvironment extends DevEnvironment { + devServer: DevServer; + + #entry: string; + #preventExternalize: boolean; + + constructor( + name: string, + config: ResolvedConfig, + context: DevEnvironmentContext, + devServer: DevServer, + entry: string, + opts?: { preventExternalize?: boolean } + ) { + super(name, config, context); + this.devServer = devServer; + this.#entry = entry; + this.#preventExternalize = opts?.preventExternalize ?? false; + } + + override async fetchModule( + id: string, + importer?: string, + options?: FetchFunctionOptions + ): Promise { + // workerd cannot handle CJS/Node modules loaded via import(). + // Bare imports (like "vue") are normally externalized by Vite's fetchModule, + // resolved using mainFields: ["main"] which often picks CJS entries. + // We intercept bare imports, resolve them through the environment's plugin + // pipeline (which respects resolve.conditions and picks ESM), then route + // the resolved path through transformRequest for proper SSR processing. + if ( + this.#preventExternalize && + !id.startsWith("file://") && + importer && + id[0] !== "." && + id[0] !== "/" + ) { + const resolved = await this.pluginContainer.resolveId(id, importer); + if (resolved && !resolved.external) { + return super.fetchModule(resolved.id, importer, options); + } + } + return super.fetchModule(id, importer, options); + } + + async dispatchFetch(request: Request): Promise { + return this.devServer.fetch(request); + } + + override async init(...args: any[]): Promise { + await this.devServer.init?.(); + await super.init(...args); + this.devServer.sendMessage({ + type: "custom", + event: "nitro:vite-env", + data: { name: this.name, entry: this.#entry }, + }); + } +} + +// ---- Vite Dev Server Integration ---- + +export async function configureViteDevServer(ctx: NitroPluginContext, server: ViteDevServer) { + const nitro = ctx.nitro!; + const nitroEnv = server.environments.nitro as FetchableDevEnvironment; + + // Restart with nitro.config changes + const nitroConfigFile = nitro.options._c12.configFile; + if (nitroConfigFile) { + server.config.configFileDependencies.push(nitroConfigFile); + } + + // Websocket + if (nitro.options.features.websocket ?? nitro.options.experimental.websocket) { + server.httpServer!.on("upgrade", (req, socket, head) => { + const protocol = req.headers["sec-websocket-protocol"]; + if (protocol?.startsWith("vite-")) { + // Vite HMR WebSocket connection + return; + } + getEnvRunner(ctx).upgrade?.({ node: { req, socket, head } }); + }); + } + + // Rebuild on scan dir changes + const reload = debounce(async () => { + await scanHandlers(nitro); + nitro.routing.sync(); + nitroEnv.moduleGraph.invalidateAll(); + nitroEnv.hot.send({ type: "full-reload" }); + }); + + const scanDirs = nitro.options.scanDirs.flatMap((dir) => [ + join(dir, nitro.options.apiDir || "api"), + join(dir, nitro.options.routesDir || "routes"), + join(dir, "middleware"), + join(dir, "plugins"), + join(dir, "modules"), + ]); + + const watchReloadEvents = new Set(["add", "addDir", "unlink", "unlinkDir"]); + const scanDirsWatcher = chokidarWatch(scanDirs, { + ignoreInitial: true, + }).on("all", (event, path, stat) => { + if (watchReloadEvents.has(event)) { + reload(); + } + }); + + const rootDirWatcher = fsWatch( + nitro.options.rootDir, + { persistent: false }, + (_event, filename) => { + if (filename && /^server\.[mc]?[jt]sx?$/.test(filename)) { + reload(); + } + } + ); + nitro.hooks.hook("close", () => { + scanDirsWatcher.close(); + rootDirWatcher.close(); + }); + + // Worker => Host RPC + nitroEnv.devServer.onMessage(async (message: any) => { + if (message?.__rpc === "transformHTML") { + try { + const html = (await server.transformIndexHtml("/", message.data)).replace( + "", + `{{{ globalThis.__nitro_vite_envs__?.["ssr"]?.fetch($REQUEST) || "" }}}` + ); + nitroEnv.devServer.sendMessage({ __rpc_id: message.__rpc_id, data: html }); + } catch (error) { + nitroEnv.devServer.sendMessage({ + __rpc_id: message.__rpc_id, + error: error instanceof Error ? error.message : String(error), + }); + } + } + }); + + const nitroDevMiddleware = async ( + nodeReq: IncomingMessage & { _nitroHandled?: boolean }, + nodeRes: ServerResponse, + next: (error?: unknown) => void + ) => { + // Skip for vite internal requests or if already handled + if ( + !nodeReq.url || + /^\/@(?:vite|fs|id)\//.test(nodeReq.url) || + nodeReq._nitroHandled || + server.middlewares.stack + .map((mw) => mw.route) + .some((base) => base && nodeReq.url!.startsWith(base)) + ) { + return next(); + } + nodeReq._nitroHandled = true; + try { + // Create web API compat request + const req = new NodeRequest({ req: nodeReq, res: nodeRes }); + + // Try dev app + const devAppRes = await ctx.devApp!.fetch(req); + if (nodeRes.writableEnded || nodeRes.headersSent) { + return; + } + if (devAppRes.status !== 404) { + return await sendNodeResponse(nodeRes, devAppRes); + } + + // Dispatch the request to the nitro environment + const envRes = await nitroEnv.dispatchFetch(req); + if (nodeRes.writableEnded || nodeRes.headersSent) { + return; + } + return await sendNodeResponse(nodeRes, envRes); + } catch (error) { + return next(error); + } + }; + + // Handle server routes first to avoid conflicts with static assets served by Vite from the root + // https://github.com/vitejs/vite/pull/20866 + server.middlewares.use(function nitroDevMiddlewarePre(req, res, next) { + const fetchDest = req.headers["sec-fetch-dest"]; + res.setHeader("vary", "sec-fetch-dest"); + if ( + // Originating from browser tab or no fetch dest (curl, fetch, etc) and (not script, style, image, etc) + (!fetchDest || /^(document|iframe|frame|empty)$/.test(fetchDest)) && + // No file extension (not /src/index.ts) + !req.url!.match(/\.([a-z0-9]+)(?:[?#]|$)/i)?.[1] && + // Special prefixes (/__vue-router/auto-routes, /@vite-plugin-layouts/, etc) + !/^\/(?:__|@)/.test(req.url!) + ) { + nitroDevMiddleware(req, res, next); + } else { + next(); + } + }); + + return () => { + server.middlewares.use(nitroDevMiddleware); + }; +} diff --git a/src/build/vite/env.ts b/src/build/vite/env.ts new file mode 100644 index 0000000000..b68c5309a3 --- /dev/null +++ b/src/build/vite/env.ts @@ -0,0 +1,204 @@ +import type { EnvironmentOptions, RollupCommonJSOptions } from "vite"; +import type { NitroPluginContext, ServiceConfig } from "./types.ts"; + +import type { RunnerName } from "env-runner"; +import { RunnerManager, loadRunner } from "env-runner"; +import { join, resolve } from "node:path"; +import { runtimeDependencies, runtimeDir } from "nitro/meta"; +import { resolveModulePath } from "exsolve"; +import { createFetchableDevEnvironment } from "./dev.ts"; +import { isAbsolute } from "pathe"; + +export function createNitroEnvironment(ctx: NitroPluginContext): EnvironmentOptions { + const isWorkerdRunner = _isWorkerdRunner(ctx); + return { + consumer: "server", + build: { + rollupOptions: ctx.bundlerConfig!.rollupConfig as any, + rolldownOptions: ctx.bundlerConfig!.rolldownConfig, + minify: ctx.nitro!.options.minify, + emptyOutDir: false, + sourcemap: ctx.nitro!.options.sourcemap, + commonjsOptions: ctx.nitro!.options.commonJS as RollupCommonJSOptions, + copyPublicDir: false, + }, + resolve: { + noExternal: ctx.nitro!.options.dev + ? isWorkerdRunner + ? true + : [ + /^nitro$/, // i have absolutely no idea why and how it fixes issues! + new RegExp(`^(${runtimeDependencies.join("|")})$`), // virtual resolutions in vite skip plugin hooks + ...ctx.bundlerConfig!.base.noExternal, + ] + : true, // production build is standalone + // workerd cannot handle CJS modules, so we must avoid the "node" export + // condition which often resolves to CJS entries. + conditions: isWorkerdRunner + ? ["workerd", "worker", ...ctx.nitro!.options.exportConditions!.filter((c) => c !== "node")] + : ctx.nitro!.options.exportConditions, + externalConditions: ctx.nitro!.options.exportConditions?.filter( + (c) => !/browser|wasm|module/.test(c) + ), + }, + define: { + // Workaround for tanstack-start (devtools) + "process.env.NODE_ENV": JSON.stringify(ctx.nitro!.options.dev ? "development" : "production"), + }, + dev: { + createEnvironment: (envName, envConfig) => { + const entry = resolve(runtimeDir, "internal/vite/dev-entry.mjs"); + const env = createFetchableDevEnvironment(envName, envConfig, getEnvRunner(ctx), entry, { + preventExternalize: isWorkerdRunner, + }); + ctx._transformRequest = (id) => env.transformRequest(id); + (ctx._viteEnvs ??= new Map()).set(envName, entry); + return env; + }, + }, + }; +} + +export function createServiceEnvironment( + ctx: NitroPluginContext, + name: string, + serviceConfig: ServiceConfig +): EnvironmentOptions { + const isWorkerdRunner = _isWorkerdRunner(ctx); + return { + consumer: "server", + build: { + rollupOptions: { input: { index: serviceConfig.entry } }, + minify: ctx.nitro!.options.minify, + sourcemap: ctx.nitro!.options.sourcemap, + outDir: join(ctx.nitro!.options.buildDir, "vite/services", name), + emptyOutDir: true, + copyPublicDir: false, + }, + resolve: { + ...(isWorkerdRunner ? { noExternal: true } : {}), + conditions: isWorkerdRunner + ? ["workerd", "worker", ...ctx.nitro!.options.exportConditions!.filter((c) => c !== "node")] + : ctx.nitro!.options.exportConditions, + externalConditions: ctx.nitro!.options.exportConditions?.filter( + (c) => !/browser|wasm|module/.test(c) + ), + }, + dev: { + createEnvironment: (envName, envConfig) => { + const entry = tryResolve(serviceConfig.entry); + (ctx._viteEnvs ??= new Map()).set(envName, entry); + return createFetchableDevEnvironment(envName, envConfig, getEnvRunner(ctx), entry, { + preventExternalize: isWorkerdRunner, + }); + }, + }, + }; +} + +export function createServiceEnvironments( + ctx: NitroPluginContext +): Record { + return Object.fromEntries( + Object.entries(ctx.services).map(([name, config]) => [ + name, + createServiceEnvironment(ctx, name, config), + ]) + ); +} + +export async function initEnvRunner(ctx: NitroPluginContext) { + if (ctx._envRunner) { + return ctx._envRunner; + } + if (!ctx._initPromise) { + ctx._initPromise = (async () => { + const manager = new RunnerManager(); + let _retries = 0; + manager.onClose((_runner, cause) => { + if (_retries++ < 3) { + ctx.nitro!.logger.info("Restarting env runner...", cause ? `Cause: ${cause}` : ""); + _loadRunner(ctx, manager); + } else { + ctx.nitro!.logger.error( + "Env runner failed after 3 retries.", + cause ? `Last cause: ${cause}` : "" + ); + } + }); + manager.onReady(() => { + _retries = 0; + if (ctx._viteEnvs) { + for (const [name, entry] of ctx._viteEnvs) { + manager.sendMessage({ + type: "custom", + event: "nitro:vite-env", + data: { name, entry }, + }); + } + } + }); + await _loadRunner(ctx, manager); + ctx._envRunner = manager; + return manager; + })(); + } + return await ctx._initPromise; +} + +export function getEnvRunner(ctx: NitroPluginContext) { + if (!ctx._envRunner) { + throw new Error("Env runner not initialized. Call initEnvRunner() first."); + } + return ctx._envRunner; +} + +export async function reloadEnvRunner(ctx: NitroPluginContext) { + const manager = ctx._envRunner; + if (!manager) { + return initEnvRunner(ctx); + } + await _loadRunner(ctx, manager); + return manager; +} + +async function _loadRunner(ctx: NitroPluginContext, manager: RunnerManager) { + const runnerName = (ctx.nitro!.options.devServer.runner || + process.env.NITRO_DEV_RUNNER || + "node-worker") as RunnerName; + const entry = resolve(runtimeDir, "internal/vite/dev-worker.mjs"); + let runner; + if (runnerName === "miniflare") { + const { MiniflareEnvRunner } = await import("env-runner/runners/miniflare"); + runner = new MiniflareEnvRunner({ + name: "nitro-vite", + data: { entry }, + }); + } else { + runner = await loadRunner(runnerName, { + name: "nitro-vite", + data: { entry }, + }); + } + await manager.reload(runner); +} + +// workerd-based runners (miniflare) cannot handle CJS externals via import(), +// so all dependencies must be processed through Vite's transform pipeline. +function _isWorkerdRunner(ctx: NitroPluginContext): boolean { + const runnerName = + ctx.nitro!.options.devServer.runner || process.env.NITRO_DEV_RUNNER || "node-worker"; + return runnerName === "miniflare"; +} + +function tryResolve(id: string) { + if (/^[~#/\0]/.test(id) || isAbsolute(id)) { + return id; + } + const resolved = resolveModulePath(id, { + suffixes: ["", "/index"], + extensions: ["", ".ts", ".mjs", ".cjs", ".js", ".mts", ".cts"], + try: true, + }); + return resolved || id; +} diff --git a/src/build/vite/plugin.ts b/src/build/vite/plugin.ts new file mode 100644 index 0000000000..528bf8eaaf --- /dev/null +++ b/src/build/vite/plugin.ts @@ -0,0 +1,485 @@ +import type { + ConfigEnv, + EnvironmentModuleNode, + EnvironmentOptions, + PluginOption, + UserConfig, + Plugin as VitePlugin, +} from "vite"; +import type { InputOption } from "rollup"; +import type { NitroPluginConfig, NitroPluginContext } from "./types.ts"; +import { resolve, join } from "pathe"; +import { createNitro, prepare } from "../../builder.ts"; +import { getBundlerConfig } from "./bundler.ts"; +import { buildEnvironments, prodSetup } from "./prod.ts"; +import { + initEnvRunner, + getEnvRunner, + createNitroEnvironment, + createServiceEnvironments, + createServiceEnvironment, +} from "./env.ts"; +import { configureViteDevServer } from "./dev.ts"; +import { runtimeDir } from "nitro/meta"; +import { resolveModulePath } from "exsolve"; +import { defu } from "defu"; +import { prettyPath } from "../../utils/fs.ts"; +import { NitroDevApp } from "../../dev/app.ts"; +import { nitroPreviewPlugin } from "./preview.ts"; +import assetsPlugin from "@hiogawa/vite-plugin-fullstack/assets"; +import type { NitroConfig } from "nitro/types"; + +// https://vite.dev/guide/api-environment-plugins +// https://vite.dev/guide/api-environment-frameworks.html + +const DEFAULT_EXTENSIONS = [".ts", ".js", ".mts", ".mjs", ".tsx", ".jsx"]; + +const debug = process.env.NITRO_DEBUG + ? (...args: any[]) => console.log("[nitro]", ...args) + : () => {}; + +export function nitro(pluginConfig: NitroPluginConfig = {}): VitePlugin[] { + if ((globalThis as any).__nitro_build__) { + // We are in `nitro build` context. Nitro injects vite plugin itself + return []; + } + const ctx: NitroPluginContext = createContext(pluginConfig); + return [ + nitroInit(ctx), + nitroEnv(ctx), + nitroMain(ctx), + nitroPrepare(ctx), + nitroService(ctx), + nitroPreviewPlugin(ctx), + pluginConfig.experimental?.vite?.assetsImport !== false && + assetsPlugin({ + experimental: { + // See https://github.com/hi-ogawa/vite-plugins/pull/1289 + clientBuildFallback: false, + }, + }), + ].filter(Boolean) as VitePlugin[]; +} + +function nitroInit(ctx: NitroPluginContext): VitePlugin { + return { + name: "nitro:init", + sharedDuringBuild: true, + apply: (_config, configEnv) => !configEnv.isPreview, + + async config(config, configEnv) { + ctx._isRolldown = !!(this.meta as Record).rolldownVersion; + if (!ctx._initialized) { + debug("[init] Initializing nitro"); + ctx._initialized = true; + await setupNitroContext(ctx, configEnv, config); + } + }, + + applyToEnvironment(env) { + if (env.name === "nitro" && ctx.nitro?.options.dev) { + debug("[init] Adding rollup plugins for dev"); + const plugins = + (ctx.bundlerConfig?.rolldownConfig?.plugins as VitePlugin[]) || + (ctx.bundlerConfig?.rollupConfig?.plugins as VitePlugin[]) || + []; + return [...(plugins || [])]; + } + }, + }; +} + +function nitroEnv(ctx: NitroPluginContext): VitePlugin { + return { + name: "nitro:env", + sharedDuringBuild: true, + apply: (_config, configEnv) => !configEnv.isPreview, + + async config(userConfig, _configEnv) { + debug("[env] Extending config (environments)"); + const environments: Record = { + ...createServiceEnvironments(ctx), + nitro: createNitroEnvironment(ctx), + }; + environments.client = { + consumer: userConfig.environments?.client?.consumer ?? "client", + build: { + rollupOptions: { + input: + userConfig.environments?.client?.build?.rollupOptions?.input ?? + useNitro(ctx).options.renderer?.template, + }, + }, + }; + debug("[env] Environments:", Object.keys(environments).join(", ")); + return { + environments, + }; + }, + + configEnvironment(name, config) { + if (config.consumer === "client") { + debug("[env] Configuring client environment", name === "client" ? "" : ` (${name})`); + config.build!.emptyOutDir = false; + config.build!.outDir = useNitro(ctx).options.output.publicDir; + config.build!.copyPublicDir ??= false; + return; + } + + // Skip if already registered as a service + if (name === "nitro" || ctx.services[name]) { + return; + } + + // Auto-register server consumer environments as services + const entry = getEntry( + config.build?.rolldownOptions?.input || config.build?.rollupOptions?.input + ); + if (typeof entry !== "string") { + return; + } + + // Resolve and register as a service + const resolvedEntry = + resolveModulePath(entry, { + from: [ctx.nitro!.options.rootDir, ...ctx.nitro!.options.scanDirs], + extensions: DEFAULT_EXTENSIONS, + suffixes: ["", "/index"], + try: true, + }) || entry; + + ctx.services[name] = { entry: resolvedEntry }; + debug(`[env] Auto-detected service "${name}" with entry: ${resolvedEntry}`); + + // Return service environment configuration to merge + return createServiceEnvironment(ctx, name, { entry: resolvedEntry }); + }, + + configResolved() { + // Setup default SSR renderer after all environments are configured + if ( + !ctx.nitro!.options.renderer?.handler && + !ctx.nitro!.options.renderer?.template && + ctx.services.ssr?.entry + ) { + ctx.nitro!.options.renderer ??= {}; + ctx.nitro!.options.renderer.handler = resolve(runtimeDir, "internal/vite/ssr-renderer"); + ctx.nitro!.routing.sync(); + } + }, + }; +} + +function nitroMain(ctx: NitroPluginContext): VitePlugin { + return { + name: "nitro:main", + sharedDuringBuild: true, + apply: (_config, configEnv) => !configEnv.isPreview, + + async config(userConfig, _configEnv) { + debug("[main] Extending config (appType, resolve, server)"); + if (!ctx.bundlerConfig) { + throw new Error("Bundler config is not initialized yet!"); + } + return { + appType: userConfig.appType || "custom", + resolve: { + // TODO: environment specific aliases not working + // https://github.com/vitejs/vite/pull/17583 (seems not effective) + alias: ctx.bundlerConfig.base.aliases, + }, + builder: { + sharedConfigBuild: true, + }, + server: { + port: + Number.parseInt(process.env.PORT || "") || + userConfig.server?.port || + useNitro(ctx).options.devServer?.port || + 3000, + // #3673, disable Vite's `cors` by default as Nitro handles all requests + cors: false, + }, + }; + }, + + buildApp: { + order: "post", + handler(builder) { + debug("[main] Building environments"); + return buildEnvironments(ctx, builder); + }, + }, + + generateBundle: { + handler(_options, bundle) { + const environment = this.environment; + debug("[main] Generating manifest and entry points for environment:", environment.name); + const serviceNames = Object.keys(ctx.services); + const isRegisteredService = serviceNames.includes(environment.name); + + // Find entry point of this service + let entryFile: string | undefined; + for (const [_name, file] of Object.entries(bundle)) { + if (file.type === "chunk" && isRegisteredService && file.isEntry) { + if (entryFile === undefined) { + entryFile = file.fileName; + } else { + this.warn(`Multiple entry points found for service "${environment.name}"`); + } + } + } + if (isRegisteredService) { + if (entryFile === undefined) { + this.error(`No entry point found for service "${this.environment.name}".`); + } + ctx._entryPoints![this.environment.name] = entryFile!; + } + }, + }, + + configureServer: (server) => { + debug("[main] Configuring dev server"); + return configureViteDevServer(ctx, server); + }, + + // Invalidate server-only modules and optionally reload the browser + // see: https://github.com/vitejs/vite/issues/19114 + async hotUpdate({ server, modules, timestamp }) { + if (ctx.pluginConfig.experimental?.vite?.serverReload === false) { + return; + } + const env = this.environment; + if (env.config.consumer === "client") { + return; + } + const clientEnvs = Object.values(server.environments).filter( + (env) => env.config.consumer === "client" + ); + const serverOnlyModules: EnvironmentModuleNode[] = []; + const sharedModules: EnvironmentModuleNode[] = []; + const invalidated = new Set(); + for (const mod of modules) { + if (mod.id && !clientEnvs.some((env) => env.moduleGraph.getModuleById(mod.id!))) { + serverOnlyModules.push(mod); + env.moduleGraph.invalidateModule(mod, invalidated, timestamp, false); + } else { + sharedModules.push(mod); + } + } + if (serverOnlyModules.length > 0) { + env.hot.send({ type: "full-reload" }); + if (sharedModules.length === 0 && serverOnlyModules.some((m) => m.environment !== "ssr")) { + server.ws.send({ type: "full-reload" }); + } + return sharedModules; + } + }, + }; +} + +function nitroPrepare(ctx: NitroPluginContext): VitePlugin { + return { + name: "nitro:prepare", + sharedDuringBuild: true, + applyToEnvironment: (env) => env.name === "nitro", + + buildApp: { + // Clean the output directory before any environment is built + order: "pre", + async handler() { + debug("[prepare] Preparing output directory"); + const nitro = ctx.nitro!; + await prepare(nitro); + }, + }, + }; +} + +function nitroService(ctx: NitroPluginContext): VitePlugin { + return { + name: "nitro:service", + enforce: "pre", + sharedDuringBuild: true, + applyToEnvironment: (env) => env.name === "nitro", + + resolveId: { + filter: { id: /^#nitro-vite-setup$/ }, + async handler(id) { + // Virtual modules + if (id === "#nitro-vite-setup") { + return { id, moduleSideEffects: true }; + } + }, + }, + + load: { + filter: { id: /^#nitro-vite-setup$/ }, + async handler(id) { + // Virtual modules + if (id === "#nitro-vite-setup") { + return prodSetup(ctx); + } + }, + }, + }; +} + +// --- internal helpers --- + +function createContext(pluginConfig: NitroPluginConfig): NitroPluginContext { + return { + pluginConfig, + services: { ...pluginConfig.experimental?.vite?.services }, + _entryPoints: {}, + }; +} + +function useNitro(ctx: NitroPluginContext) { + if (!ctx.nitro) { + throw new Error("Nitro instance is not initialized yet."); + } + return ctx.nitro; +} + +async function setupNitroContext( + ctx: NitroPluginContext, + configEnv: ConfigEnv, + userConfig: UserConfig +) { + // Nitro config overrides + const nitroConfig: NitroConfig = { + dev: configEnv.command === "serve", + builder: "vite", + rootDir: userConfig.root, + ...defu( + ctx.pluginConfig, + (ctx.pluginConfig as any).config, // TODO: Remove shortly + userConfig.nitro + ), + }; + + // Register Nitro modules from Vite plugins + nitroConfig.modules ??= []; + for (const plugin of flattenPlugins(userConfig.plugins || [])) { + if (plugin.nitro) { + nitroConfig.modules.push(plugin.nitro); + } + } + + // @see https://vite.dev/guide/env-and-mode#env-files + const dotenvFileNames = [".env", ".env.local"]; + if (configEnv.mode) { + dotenvFileNames.push(`.env.${configEnv.mode}`, `.env.${configEnv.mode}.local`); + } + + // Initialize a new Nitro instance + ctx.nitro = + ctx.pluginConfig._nitro || + (await createNitro(nitroConfig, { dotenv: { fileName: dotenvFileNames } })); + + // Config ssr env as a fetchable ssr service + if (!ctx.services?.ssr) { + if (userConfig.environments?.ssr === undefined) { + const ssrEntry = resolveModulePath("./entry-server", { + from: ["app", "src", ""].flatMap((d) => + [ctx.nitro!.options.rootDir, ...ctx.nitro!.options.scanDirs].map((s) => join(s, d) + "/") + ), + extensions: DEFAULT_EXTENSIONS, + try: true, + }); + if (ssrEntry) { + ctx.services.ssr = { entry: ssrEntry }; + ctx.nitro!.logger.info(`Using \`${prettyPath(ssrEntry)}\` as vite ssr entry.`); + } + } else { + let ssrEntry = getEntry(userConfig.environments.ssr.build?.rollupOptions?.input); + if (typeof ssrEntry === "string") { + ssrEntry = + resolveModulePath(ssrEntry, { + from: [ctx.nitro.options.rootDir, ...ctx.nitro.options.scanDirs], + extensions: DEFAULT_EXTENSIONS, + suffixes: ["", "/index"], + try: true, + }) || ssrEntry; + ctx.services.ssr = { entry: ssrEntry }; + } + } + } + if ( + ctx.nitro.options.serverEntry && + ctx.nitro.options.serverEntry.handler === ctx.services.ssr?.entry + ) { + ctx.nitro.logger.warn( + `Nitro server entry and Vite SSR both set to ${prettyPath(ctx.services.ssr.entry)}. Use a separate SSR entry (e.g. \`src/server.ts\`).` + ); + ctx.nitro.options.serverEntry = false; + } + + // Determine default Vite dist directory + const publicDistDir = (ctx._publicDistDir = + userConfig.build?.outDir || resolve(ctx.nitro.options.buildDir, "vite/public")); + ctx.nitro.options.publicAssets.push({ + dir: publicDistDir, + maxAge: 0, + baseURL: "/", + fallthrough: true, + }); + + // Nitro Vite Production Runtime + if (!ctx.nitro.options.dev) { + ctx.nitro.options.unenv.push({ + meta: { name: "nitro-vite" }, + polyfill: ["#nitro-vite-setup"], + }); + } + + // Call build:before hook **before resolving rollup config** for compatibility + await ctx.nitro.hooks.callHook("build:before", ctx.nitro); + + // Resolve common rollup options + ctx.bundlerConfig = await getBundlerConfig(ctx); + + // Call rollup:before hook to allow modifying rollup config + await ctx.nitro.hooks.callHook( + "rollup:before", + ctx.nitro, + ctx.bundlerConfig.rollupConfig || (ctx.bundlerConfig.rolldownConfig as any) + ); + + // Warm up env runner for dev + if (ctx.nitro.options.dev) { + await initEnvRunner(ctx); + } + + // Attach nitro.fetch to env runner + ctx.nitro.fetch = (req) => getEnvRunner(ctx).fetch(req); + + // Create dev app + if (ctx.nitro.options.dev && !ctx.devApp) { + ctx.devApp = new NitroDevApp(ctx.nitro); + } + + // Cleanup resources after close { + ctx.nitro.hooks.hook("close", async () => { + if (ctx._envRunner) { + await ctx._envRunner.close(); + } + }); +} + +function getEntry(input: InputOption | undefined): string | undefined { + if (typeof input === "string") { + return input; + } else if (Array.isArray(input) && input.length > 0) { + return input[0]; + } else if (input && "index" in input) { + return input.index as string; + } +} + +function flattenPlugins(plugins: PluginOption[]): VitePlugin[] { + return plugins + .flatMap((plugin) => (Array.isArray(plugin) ? flattenPlugins(plugin) : [plugin])) + .filter((p) => p && !(p instanceof Promise)) as VitePlugin[]; +} diff --git a/src/build/vite/preview.ts b/src/build/vite/preview.ts new file mode 100644 index 0000000000..f131de4983 --- /dev/null +++ b/src/build/vite/preview.ts @@ -0,0 +1,46 @@ +import type { Plugin as VitePlugin } from "vite"; +import type { NitroPluginContext } from "./types.ts"; +import { startPreview } from "../../preview.ts"; + +export function nitroPreviewPlugin(ctx: NitroPluginContext): VitePlugin { + return { + name: "nitro:preview", + apply: (_config, configEnv) => !!configEnv.isPreview, + + config(config) { + return { + preview: { + port: config.preview?.port || 3000, + }, + }; + }, + + async configurePreviewServer(server) { + // Init Nitro preview handler + const preview = await startPreview({ + rootDir: server.config.root, + loader: { nodeServer: server.httpServer }, + }); + + // Close preview server when Vite's preview server is closed + server.httpServer.once("close", async () => { + await preview.close(); + }); + + // Handle all requests with Nitro preview handler (also handles production static assets) + const { NodeRequest, sendNodeResponse } = await import("srvx/node"); + server.middlewares.use(async (req, res, next) => { + const nodeReq = new NodeRequest({ req, res }); + const previewRes: Response = await preview.fetch(nodeReq); + await sendNodeResponse(res, previewRes).catch(next); + }); + + // Handle WebSocket upgrade requests with Nitro preview handler if supported + if (preview.upgrade) { + server.httpServer.on("upgrade", (req, socket, head) => { + preview.upgrade!(req, socket, head); + }); + } + }, + } satisfies VitePlugin; +} diff --git a/src/build/vite/prod.ts b/src/build/vite/prod.ts new file mode 100644 index 0000000000..3c20ebc758 --- /dev/null +++ b/src/build/vite/prod.ts @@ -0,0 +1,167 @@ +import type { ViteBuilder } from "vite"; +import type { NitroPluginContext } from "./types.ts"; + +import { basename, dirname, resolve } from "pathe"; +import { formatCompatibilityDate } from "compatx"; +import { colors as C } from "consola/utils"; +import { copyPublicAssets, prerender } from "../../builder.ts"; +import { existsSync } from "node:fs"; +import { writeBuildInfo } from "../info.ts"; +import { mkdir, readFile, rm, writeFile } from "node:fs/promises"; +import { isTest, isCI } from "std-env"; +import type { RolldownOutput } from "rolldown"; + +const BuilderNames = { + nitro: C.magenta("Nitro"), + client: C.green("Client"), + ssr: C.blue("SSR"), +} as Record; + +export async function buildEnvironments(ctx: NitroPluginContext, builder: ViteBuilder) { + const nitro = ctx.nitro!; + + // ---------------------------------------------- + // Stage 1: Build all environments before Nitro + // ---------------------------------------------- + + for (const [envName, env] of Object.entries(builder.environments)) { + // prettier-ignore + const fmtName = BuilderNames[envName] || (envName.length <= 3 ? envName.toUpperCase() : envName[0].toUpperCase() + envName.slice(1)); + if (envName === "nitro" || !env.config.build.rollupOptions.input || env.isBuilt) { + if (!["nitro", "ssr", "client"].includes(envName)) { + nitro.logger.info( + env.isBuilt + ? `Skipping ${fmtName} (already built)` + : `Skipping ${fmtName} (no input defined)` + ); + } + continue; + } + if (!isTest && !isCI) console.log(); + nitro.logger.start(`Building [${fmtName}]`); + await builder.build(env); + } + + // Use transformed client input for renderer template generation + const nitroOptions = ctx.nitro!.options; + const clientInput = builder.environments.client?.config?.build?.rollupOptions?.input; + if (nitroOptions.renderer?.template && nitroOptions.renderer?.template === clientInput) { + const outputPath = resolve(nitroOptions.output.publicDir, basename(clientInput as string)); + if (existsSync(outputPath)) { + const html = await readFile(outputPath, "utf8").then((r) => + r.replace( + "", + `{{{ globalThis.__nitro_vite_envs__?.["ssr"]?.fetch($REQUEST) || "" }}}` + ) + ); + await rm(outputPath); + const tmp = resolve(nitroOptions.buildDir, "vite/index.html"); + await mkdir(dirname(tmp), { recursive: true }); + await writeFile(tmp, html, "utf8"); + nitroOptions.renderer.template = tmp; + } + } + + // Extended builder API by assets plugin + // https://github.com/hi-ogawa/vite-plugins/pull/1288 + await builder.writeAssetsManifest?.(); + + // ---------------------------------------------- + // Stage 2: Build Nitro + // ---------------------------------------------- + + if (!isTest && !isCI) console.log(); + const buildInfo = [ + ["preset", nitro.options.preset], + ["compatibility", formatCompatibilityDate(nitro.options.compatibilityDate)], + ].filter((e) => e[1]); + nitro.logger.start( + `Building [${BuilderNames.nitro}] ${C.dim(`(${buildInfo.map(([k, v]) => `${k}: \`${v}\``).join(", ")})`)}` + ); + + // Copy public assets to the final output directory + await copyPublicAssets(nitro); + + // Add route rule for asset dirs + const assetDirs = new Set( + Object.values(builder.environments) + .filter((env) => env.config.consumer === "client") + .map((env) => env.config.build.assetsDir) + .filter(Boolean) as string[] + ); + for (const assetsDir of assetDirs) { + if (!existsSync(resolve(nitro.options.output.publicDir, assetsDir))) { + continue; + } + const rule = (ctx.nitro!.options.routeRules[`/${assetsDir}/**`] ??= {}); + if (!rule.headers?.["cache-control"]) { + rule.headers = { + ...rule.headers, + "cache-control": `public, max-age=31536000, immutable`, + }; + } + } + ctx.nitro!.routing.sync(); + + // Prerender routes if configured + await prerender(nitro); + + // Build the Nitro server bundle + const output = (await builder.build(builder.environments.nitro)) as RolldownOutput; + + // Close the Nitro instance + await nitro.close(); + + // Call compiled hook + await nitro.hooks.callHook("compiled", nitro); + + // Write build info + await writeBuildInfo(nitro, output); + + // Show deploy and preview commands + if (!isTest && !isCI) console.log(); + nitro.logger.success("You can preview this build using `npx vite preview`"); + if (nitro.options.commands.deploy) { + nitro.logger.success("You can deploy this build using `npx nitro deploy --prebuilt`"); + } +} + +export function prodSetup(ctx: NitroPluginContext): string { + const serviceNames = Object.keys(ctx.services); + + const serviceEntries = serviceNames.map((name) => { + const entry = resolve( + ctx.nitro!.options.buildDir, + "vite/services", + name, + ctx._entryPoints[name] + ); + return [name, entry]; + }); + + return /* js */ ` +function lazyService(loader) { + let promise, mod + return { + fetch(req) { + if (mod) { return mod.fetch(req) } + if (!promise) { + promise = loader().then(_mod => (mod = _mod.default || _mod)) + } + return promise.then(mod => mod.fetch(req)) + } + } +} + +const services = { +${serviceEntries + .map( + ([name, entry]) => + /* js */ `[${JSON.stringify(name)}]: lazyService(() => import(${JSON.stringify(entry)}))` + ) + .join(",\n")} +}; + +globalThis.__nitro_vite_envs__ = services; + `; +} diff --git a/src/build/vite/types.ts b/src/build/vite/types.ts new file mode 100644 index 0000000000..7a471f9aff --- /dev/null +++ b/src/build/vite/types.ts @@ -0,0 +1,69 @@ +import type { TransformResult } from "vite"; +import type { getBundlerConfig } from "./bundler.ts"; +import type { Nitro, NitroConfig, NitroModule } from "nitro/types"; +import type { RunnerManager } from "env-runner"; +import type { NitroDevApp } from "../../dev/app.ts"; + +declare module "vite" { + interface UserConfig { + /** + * Nitro Vite Plugin options. + */ + nitro?: NitroConfig; + } + + interface Plugin { + nitro?: NitroModule; + } +} + +export interface NitroPluginConfig extends NitroConfig { + /** + * @internal Use preinitialized Nitro instance for the plugin. + */ + _nitro?: Nitro; + + experimental?: NitroConfig["experimental"] & { + vite: { + /** + * @experimental Enable `?assets` import proposed by https://github.com/vitejs/vite/discussions/20913 + * @default true + */ + assetsImport?: boolean; + + /** + * + * Invalidate server-only modules and optionally reload the browser when a server-only module is updated. + * + * @default true + */ + serverReload?: boolean; + + /** + * Additional Vite environment services to register. + */ + services?: Record; + }; + }; +} + +export interface ServiceConfig { + entry: string; +} + +export interface NitroPluginContext { + nitro?: Nitro; + pluginConfig: NitroPluginConfig; + bundlerConfig?: Awaited>; + devApp?: NitroDevApp; + services: Record; + + _isRolldown?: boolean; + _initialized?: boolean; + _envRunner?: RunnerManager; + _initPromise?: Promise; + _viteEnvs?: Map; + _transformRequest?: (id: string) => Promise; + _publicDistDir?: string; + _entryPoints: Record; +} diff --git a/src/builder.ts b/src/builder.ts new file mode 100644 index 0000000000..c146f788c0 --- /dev/null +++ b/src/builder.ts @@ -0,0 +1,21 @@ +// Core +export { createNitro } from "./nitro.ts"; + +// Config loader +export { loadOptions } from "./config/loader.ts"; + +// Build +export { build } from "./build/build.ts"; +export { copyPublicAssets } from "./build/assets.ts"; +export { prepare } from "./build/prepare.ts"; +export { writeTypes } from "./build/types.ts"; +export { getBuildInfo } from "./build/info.ts"; + +// Dev server +export { createDevServer } from "./dev/server.ts"; + +// Prerender +export { prerender } from "./prerender/prerender.ts"; + +// Tasks API +export { runTask, listTasks } from "./task.ts"; diff --git a/src/cli/commands/build.ts b/src/cli/commands/build.ts index c6853ffd10..c22dfa2648 100644 --- a/src/cli/commands/build.ts +++ b/src/cli/commands/build.ts @@ -1,44 +1,37 @@ -import nodeCrypto from "node:crypto"; import { defineCommand } from "citty"; import type { DateString } from "compatx"; -import { - build, - copyPublicAssets, - createNitro, - prepare, - prerender, -} from "nitropack/core"; +import { build, copyPublicAssets, createNitro, prepare, prerender } from "nitro/builder"; import { resolve } from "pathe"; -import { commonArgs } from "../common"; +import { commonArgs } from "../common.ts"; -// globalThis.crypto support for Node.js 18 -if (!globalThis.crypto) { - globalThis.crypto = nodeCrypto as unknown as Crypto; -} +export const buildArgs = { + ...commonArgs, + minify: { + type: "boolean", + description: + "Minify the output (overrides preset defaults you can also use `--no-minify` to disable).", + }, + preset: { + type: "string", + description: "The build preset to use (you can also use `NITRO_PRESET` environment variable).", + }, + builder: { + type: "string", + description: "The builder to use (you can also use `NITRO_BUILDER` environment variable).", + }, + compatibilityDate: { + type: "string", + description: + "The date to use for preset compatibility (you can also use `NITRO_COMPATIBILITY_DATE` environment variable).", + }, +} as const; export default defineCommand({ meta: { name: "build", description: "Build nitro project for production", }, - args: { - ...commonArgs, - minify: { - type: "boolean", - description: - "Minify the output (overrides preset defaults you can also use `--no-minify` to disable).", - }, - preset: { - type: "string", - description: - "The build preset to use (you can also use `NITRO_PRESET` environment variable).", - }, - compatibilityDate: { - type: "string", - description: - "The date to use for preset compatibility (you can also use `NITRO_COMPATIBILITY_DATE` environment variable).", - }, - }, + args: buildArgs, async run({ args }) { const rootDir = resolve((args.dir || args._dir || ".") as string); const nitro = await createNitro( @@ -47,6 +40,7 @@ export default defineCommand({ dev: false, minify: args.minify, preset: args.preset, + builder: args.builder as "rollup" | "rolldown" | "vite", }, { compatibilityDate: args.compatibilityDate as DateString, diff --git a/src/cli/commands/deploy.ts b/src/cli/commands/deploy.ts new file mode 100644 index 0000000000..0ea41fa893 --- /dev/null +++ b/src/cli/commands/deploy.ts @@ -0,0 +1,56 @@ +import { defineCommand } from "citty"; +import { relative, resolve } from "pathe"; +import consola from "consola"; +import { execSync } from "node:child_process"; +import { getBuildInfo } from "../../build/info.ts"; +import buildCmd, { buildArgs } from "./build.ts"; + +export default defineCommand({ + meta: { + name: "deploy", + description: "Build and deploy nitro project for production", + }, + args: { + ...buildArgs, + prebuilt: { + type: "boolean", + description: "Skip the build step and deploy the existing build", + }, + }, + async run(ctx) { + (globalThis as any).__nitroDeploying__ = true; + if (!ctx.args.prebuilt) { + await buildCmd.run!(ctx as any); + } + if ((globalThis as any).__nitroDeployed__) { + return; + } + const rootDir = resolve((ctx.args.dir || ctx.args._dir || ".") as string); + const { buildInfo, outputDir } = await getBuildInfo(rootDir); + if (!buildInfo) { + // throw new Error("No build info found, cannot deploy."); + consola.error("No build info found, cannot deploy."); + process.exit(1); + } + if (!buildInfo.commands?.deploy) { + consola.error( + `The \`${buildInfo.preset}\` preset does not have a default deploy command.\n\nTry using a different preset with the \`--preset\` option, or configure a deploy command in the Nitro config, or deploy manually.` + ); + process.exit(1); + } + + const extraArgs = + ctx.rawArgs.indexOf("--") !== -1 + ? ctx.rawArgs.slice(ctx.rawArgs.indexOf("--") + 1).join(" ") + : ""; + + const deployCommand = + buildInfo.commands.deploy.replace( + /([\s:])\.\/(\S*)/g, + `$1${relative(process.cwd(), outputDir)}/$2` + ) + (extraArgs ? ` ${extraArgs}` : ""); + + consola.info(`$ ${deployCommand}`); + execSync(deployCommand, { stdio: "inherit" }); + }, +}); diff --git a/src/cli/commands/dev.ts b/src/cli/commands/dev.ts index 0f8e9c93b1..18114cd596 100644 --- a/src/cli/commands/dev.ts +++ b/src/cli/commands/dev.ts @@ -1,19 +1,13 @@ -import nodeCrypto from "node:crypto"; +import type { Nitro } from "nitro/types"; import { defineCommand } from "citty"; import { consola } from "consola"; -import { getArgs, parseArgs } from "listhen/cli"; -import { build, createDevServer, createNitro, prepare } from "nitropack/core"; -import type { Nitro } from "nitropack/types"; +import { build, createNitro, prepare } from "nitro/builder"; import { resolve } from "pathe"; -import { commonArgs } from "../common"; +import { commonArgs } from "../common.ts"; +import { NitroDevServer } from "../../dev/server.ts"; const hmrKeyRe = /^runtimeConfig\.|routeRules\./; -// globalThis.crypto support for Node.js 18 -if (!globalThis.crypto) { - globalThis.crypto = nodeCrypto as unknown as Crypto; -} - export default defineCommand({ meta: { name: "dev", @@ -21,7 +15,8 @@ export default defineCommand({ }, args: { ...commonArgs, - ...getArgs(), + port: { type: "string", description: "specify port" }, + host: { type: "string", description: "specify hostname " }, }, async run({ args }) { const rootDir = resolve((args.dir || args._dir || ".") as string); @@ -38,7 +33,6 @@ export default defineCommand({ { rootDir, dev: true, - preset: "nitro-dev", _cli: { command: "dev" }, }, { @@ -52,8 +46,7 @@ export default defineCommand({ } consola.info( - "Nitro config updated:\n" + - diff.map((entry) => ` ${entry.toString()}`).join("\n") + "Nitro config updated:\n" + diff.map((entry) => ` ${entry.toString()}`).join("\n") ); await (diff.every((e) => hmrKeyRe.test(e.key)) @@ -64,9 +57,12 @@ export default defineCommand({ } ); nitro.hooks.hookOnce("restart", reload); - const server = createDevServer(nitro); - const listhenOptions = parseArgs(args); - await server.listen(listhenOptions.port || 3000, listhenOptions); + const server = new NitroDevServer(nitro); + + await server.listen({ + port: args.port || nitro.options.devServer.port, + hostname: args.host || nitro.options.devServer.hostname, + }); await prepare(nitro); await build(nitro); }; diff --git a/src/cli/commands/docs.ts b/src/cli/commands/docs.ts new file mode 100644 index 0000000000..93f2a119a4 --- /dev/null +++ b/src/cli/commands/docs.ts @@ -0,0 +1,32 @@ +import { execSync } from "node:child_process"; +import { defineCommand } from "citty"; + +export default defineCommand({ + meta: { + name: "docs", + description: "Explore Nitro documentation", + }, + args: { + page: { type: "string", description: "Page path to open" }, + }, + run({ rawArgs }) { + const runner = ( + [ + ["bun", "x"], + ["pnpm", "dlx"], + ["npm", "x"], + ] as const + ).find(([pkg]) => { + try { + execSync(`${pkg} -v`, { stdio: "ignore" }); + return true; + } catch {} + }) || ["npm", "x"]; + const runnerCmd = runner.join(" "); + const docsDir = new URL("../../../skills/nitro/docs", import.meta.url).pathname; + const args = rawArgs?.join(" ") || ""; + execSync(`${runnerCmd} mdzilla ${docsDir}${args ? ` ${args}` : ""}`, { + stdio: "inherit", + }); + }, +}); diff --git a/src/cli/commands/prepare.ts b/src/cli/commands/prepare.ts index a7cb559571..1a953a3603 100644 --- a/src/cli/commands/prepare.ts +++ b/src/cli/commands/prepare.ts @@ -1,7 +1,7 @@ import { defineCommand } from "citty"; -import { createNitro, writeTypes } from "nitropack/core"; +import { createNitro, writeTypes } from "nitro/builder"; import { resolve } from "pathe"; -import { commonArgs } from "../common"; +import { commonArgs } from "../common.ts"; export default defineCommand({ meta: { diff --git a/src/cli/commands/preview.ts b/src/cli/commands/preview.ts new file mode 100644 index 0000000000..d4c0a0f4ac --- /dev/null +++ b/src/cli/commands/preview.ts @@ -0,0 +1,48 @@ +import { defineCommand } from "citty"; +import { resolve } from "pathe"; +import { commonArgs } from "../common.ts"; +import { startPreview } from "../../preview.ts"; +import { serve } from "srvx"; +import { log } from "srvx/log"; + +export default defineCommand({ + meta: { + name: "preview", + description: "Start a local server to preview the built server", + }, + args: { + ...commonArgs, + port: { type: "string", description: "specify port" }, + host: { type: "string", description: "specify hostname" }, + }, + async run({ args }) { + const rootDir = resolve((args.dir || args._dir || ".") as string); + + const server = serve({ + fetch(req) { + return preview.fetch(req); + }, + middleware: [log()], + gracefulShutdown: false, + port: args.port, + hostname: args.host, + }); + + const preview = await startPreview({ + rootDir, + loader: { srvxServer: server }, + }); + + if (preview.upgrade) { + server.node?.server?.on("upgrade", (req, socket, head) => { + preview.upgrade!(req, socket, head); + }); + } + + process.on("SIGINT", async () => { + await server.close(); + await preview.close(); + process.exit(0); + }); + }, +}); diff --git a/src/cli/commands/task/index.ts b/src/cli/commands/task/index.ts index 6758b11342..e4cc2c6af3 100644 --- a/src/cli/commands/task/index.ts +++ b/src/cli/commands/task/index.ts @@ -6,7 +6,7 @@ export default defineCommand({ description: "Operate in nitro tasks (experimental)", }, subCommands: { - list: () => import("./list").then((r) => r.default), - run: () => import("./run").then((r) => r.default), + list: () => import("./list.ts").then((r) => r.default), + run: () => import("./run.ts").then((r) => r.default), }, }); diff --git a/src/cli/commands/task/list.ts b/src/cli/commands/task/list.ts index bbdd2fa7d4..31593897a5 100644 --- a/src/cli/commands/task/list.ts +++ b/src/cli/commands/task/list.ts @@ -1,6 +1,6 @@ import { defineCommand } from "citty"; import { consola } from "consola"; -import { listTasks, loadOptions } from "nitropack/core"; +import { listTasks, loadOptions } from "nitro/builder"; import { resolve } from "pathe"; export default defineCommand({ @@ -23,11 +23,7 @@ export default defineCommand({ buildDir: options?.buildDir || ".nitro", }); for (const [name, task] of Object.entries(tasks)) { - consola.log( - ` - \`${name}\`${ - task.meta?.description ? ` - ${task.meta.description}` : "" - }` - ); + consola.log(` - \`${name}\`${task.meta?.description ? ` - ${task.meta.description}` : ""}`); } }, }); diff --git a/src/cli/commands/task/run.ts b/src/cli/commands/task/run.ts index 0c15162d5a..f947b4619a 100644 --- a/src/cli/commands/task/run.ts +++ b/src/cli/commands/task/run.ts @@ -1,14 +1,13 @@ import { defineCommand } from "citty"; import { consola } from "consola"; import destr from "destr"; -import { createNitro, loadOptions, runTask } from "nitropack/core"; +import { loadOptions, runTask } from "nitro/builder"; import { resolve } from "pathe"; export default defineCommand({ meta: { name: "run", - description: - "Run a runtime task in the currently running dev server (experimental)", + description: "Run a runtime task in the currently running dev server (experimental)", }, args: { name: { @@ -32,9 +31,7 @@ export default defineCommand({ consola.info(`Running task \`${args.name}\`...`); let payload: any = destr(args.payload || "{}"); if (typeof payload !== "object") { - consola.error( - `Invalid payload: \`${args.payload}\` (it should be a valid JSON object)` - ); + consola.error(`Invalid payload: \`${args.payload}\` (it should be a valid JSON object)`); payload = undefined; } try { diff --git a/src/cli/common.ts b/src/cli/common.ts index 9f9047bd22..c395760209 100644 --- a/src/cli/common.ts +++ b/src/cli/common.ts @@ -1,6 +1,6 @@ import type { ArgsDef } from "citty"; -export const commonArgs = { +export const commonArgs = { dir: { type: "string", description: "project root directory", @@ -10,4 +10,4 @@ export const commonArgs = { default: ".", description: "project root directory (prefer using `--dir`)", }, -}; +} satisfies ArgsDef; diff --git a/src/cli/index.ts b/src/cli/index.ts index 6859e5e960..35789bc966 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -1,6 +1,6 @@ #!/usr/bin/env node import { defineCommand, runMain } from "citty"; -import { version as nitroVersion } from "nitropack/meta"; +import { version as nitroVersion } from "nitro/meta"; const main = defineCommand({ meta: { @@ -9,10 +9,13 @@ const main = defineCommand({ version: nitroVersion, }, subCommands: { - dev: () => import("./commands/dev").then((r) => r.default), - build: () => import("./commands/build").then((r) => r.default), - prepare: () => import("./commands/prepare").then((r) => r.default), - task: () => import("./commands/task").then((r) => r.default), + dev: () => import("./commands/dev.ts").then((r) => r.default), + build: () => import("./commands/build.ts").then((r) => r.default), + deploy: () => import("./commands/deploy.ts").then((r) => r.default), + prepare: () => import("./commands/prepare.ts").then((r) => r.default), + task: () => import("./commands/task/index.ts").then((r) => r.default), + preview: () => import("./commands/preview.ts").then((r) => r.default), + docs: () => import("./commands/docs.ts").then((r) => r.default), }, }); diff --git a/src/core/config/defaults.ts b/src/config/defaults.ts similarity index 59% rename from src/core/config/defaults.ts rename to src/config/defaults.ts index 44c4a71d98..8fc725889b 100644 --- a/src/core/config/defaults.ts +++ b/src/config/defaults.ts @@ -1,20 +1,18 @@ -import { runtimeDir } from "nitropack/runtime/meta"; -import type { NitroConfig } from "nitropack/types"; -import { resolve } from "pathe"; +import type { NitroConfig } from "nitro/types"; import { isDebug, isTest } from "std-env"; +import { version as nitroVersion } from "nitro/meta"; export const NitroDefaults: NitroConfig = { // General + compatibilityDate: "latest", debug: isDebug, - timing: isDebug, logLevel: isTest ? 1 : 3, runtimeConfig: { app: {}, nitro: {} }, - appConfig: {}, - appConfigFiles: [], // Dirs + serverDir: false, scanDirs: [], - buildDir: ".nitro", + buildDir: `node_modules/.nitro`, output: { dir: "{{ rootDir }}/.output", serverDir: "{{ output.dir }}/server", @@ -22,25 +20,21 @@ export const NitroDefaults: NitroConfig = { }, // Features + features: {}, experimental: {}, future: {}, storage: {}, devStorage: {}, - bundledStorage: [], publicAssets: [], serverAssets: [], plugins: [], tasks: {}, scheduledTasks: {}, - imports: { - exclude: [], - dirs: [], - presets: [], - virtualImports: ["#imports"], - }, + imports: false, virtual: {}, compressPublicAssets: false, ignore: [], + wasm: {}, // Dev dev: false, @@ -59,6 +53,7 @@ export const NitroDefaults: NitroConfig = { handlers: [], devHandlers: [], errorHandler: undefined, + routes: {}, routeRules: {}, prerender: { autoSubfolderIndex: true, @@ -72,40 +67,28 @@ export const NitroDefaults: NitroConfig = { routes: [], }, - // Rollup - analyze: false, - moduleSideEffects: [ - "unenv/polyfill/", - "node-fetch-native/polyfill", - "node-fetch-native/dist/polyfill", - resolve(runtimeDir, "polyfill/"), - ], + // Builder + builder: undefined, + moduleSideEffects: ["unenv/polyfill/"], replace: {}, node: true, - sourceMap: true, - esbuild: { - options: { - jsxFactory: "h", - jsxFragment: "Fragment", - }, - }, + sourcemap: false, + traceDeps: [], // Advanced typescript: { - strict: false, - generateTsConfig: true, - generateRuntimeConfigTypes: true, - tsconfigPath: "types/tsconfig.json", - internalPaths: false, - tsConfig: {}, + strict: true, + generateRuntimeConfigTypes: false, + generateTsConfig: false, + tsconfigPath: "tsconfig.json", + tsConfig: undefined, }, - nodeModulesDirs: [], hooks: {}, commands: {}, // Framework framework: { name: "nitro", - version: "", + version: nitroVersion, }, }; diff --git a/src/config/index.ts b/src/config/index.ts deleted file mode 100644 index 4e591e5a59..0000000000 --- a/src/config/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { NitroConfig } from "nitropack/types"; - -export type { NitroConfig } from "nitropack/types"; - -export function defineNitroConfig(config: NitroConfig): NitroConfig { - return config; -} diff --git a/src/config/loader.ts b/src/config/loader.ts new file mode 100644 index 0000000000..ca27a4925a --- /dev/null +++ b/src/config/loader.ts @@ -0,0 +1,176 @@ +import { loadConfig, watchConfig } from "c12"; +import consola from "consola"; +import { resolveCompatibilityDates } from "compatx"; +import type { CompatibilityDateSpec } from "compatx"; +import { klona } from "klona/full"; +import type { PresetName } from "../presets/index.ts"; +import type { LoadConfigOptions, NitroConfig, NitroOptions, NitroPresetMeta } from "nitro/types"; + +import { NitroDefaults } from "./defaults.ts"; + +// Resolvers +import { resolveAssetsOptions } from "./resolvers/assets.ts"; +import { resolveCompatibilityOptions } from "./resolvers/compatibility.ts"; +import { resolveDatabaseOptions } from "./resolvers/database.ts"; +import { resolveExportConditionsOptions } from "./resolvers/export-conditions.ts"; +import { resolveImportsOptions } from "./resolvers/imports.ts"; +import { resolveOpenAPIOptions } from "./resolvers/open-api.ts"; +import { resolveTsconfig } from "./resolvers/tsconfig.ts"; +import { resolvePathOptions } from "./resolvers/paths.ts"; +import { resolveRouteRulesOptions } from "./resolvers/route-rules.ts"; +import { resolveRuntimeConfigOptions } from "./resolvers/runtime-config.ts"; +import { resolveStorageOptions } from "./resolvers/storage.ts"; +import { resolveURLOptions } from "./resolvers/url.ts"; +import { resolveErrorOptions } from "./resolvers/error.ts"; +import { resolveUnenv } from "./resolvers/unenv.ts"; +import { resolveBuilder } from "./resolvers/builder.ts"; + +const configResolvers = [ + resolveCompatibilityOptions, + resolveTsconfig, + resolvePathOptions, + resolveImportsOptions, + resolveRouteRulesOptions, + resolveDatabaseOptions, + resolveExportConditionsOptions, + resolveRuntimeConfigOptions, + resolveOpenAPIOptions, + resolveURLOptions, + resolveAssetsOptions, + resolveStorageOptions, + resolveErrorOptions, + resolveUnenv, + resolveBuilder, +] as const; + +export async function loadOptions( + configOverrides: NitroConfig = {}, + opts: LoadConfigOptions = {} +): Promise { + const options = await _loadUserConfig(configOverrides, opts); + for (const resolver of configResolvers) { + await resolver(options); + } + return options; +} + +async function _loadUserConfig( + configOverrides: NitroConfig = {}, + opts: LoadConfigOptions = {} +): Promise { + // Load configuration and preset + configOverrides = klona(configOverrides); + + // @ts-ignore + globalThis.defineNitroConfig = globalThis.defineNitroConfig || ((c) => c); + + // Compatibility date + let compatibilityDate: CompatibilityDateSpec | undefined = + configOverrides.compatibilityDate || + opts.compatibilityDate || + ((process.env.NITRO_COMPATIBILITY_DATE || + process.env.SERVER_COMPATIBILITY_DATE || + process.env.COMPATIBILITY_DATE) as CompatibilityDateSpec); + + // Preset resolver + const { resolvePreset } = await import("../presets/index.ts"); + + // prettier-ignore + let preset: string | undefined = (configOverrides.preset as string) || process.env.NITRO_PRESET || process.env.SERVER_PRESET + + const _dotenv = opts.dotenv ?? (configOverrides.dev && { fileName: [".env", ".env.local"] }); + const envName = opts.c12?.envName ?? (configOverrides.dev ? "development" : "production"); + const loadedConfig = await ( + opts.watch + ? watchConfig + : loadConfig + )({ + name: "nitro", + cwd: configOverrides.rootDir, + dotenv: _dotenv, + envName, + extend: { extendKey: ["extends", "preset"] }, + defaults: NitroDefaults, + async overrides({ rawConfigs }) { + // prettier-ignore + const getConf = (key: K) => (configOverrides[key] ?? (rawConfigs.main as NitroConfig)?.[key] ?? (rawConfigs.rc as NitroConfig)?.[key] ?? (rawConfigs.packageJson as NitroConfig)?.[key]) as NitroConfig[K]; + + if (!compatibilityDate) { + compatibilityDate = getConf("compatibilityDate"); + } + + // prettier-ignore + const framework = getConf("framework") + const isCustomFramework = framework?.name && framework.name !== "nitro"; + + if (!preset) { + preset = getConf("preset"); + } + + if (configOverrides.dev) { + // Check if preset has compatible dev support + // Otherwise use default nitro-dev preset + preset = + preset && preset !== "nitro-dev" + ? await resolvePreset(preset, { + static: getConf("static"), + dev: true, + compatibilityDate: compatibilityDate || "latest", + }) + .then((p) => p?._meta?.name || "nitro-dev") + .catch(() => "nitro-dev") + : "nitro-dev"; + } else if (!preset) { + // Auto detect production preset + preset = await resolvePreset("" /* auto detect */, { + static: getConf("static"), + dev: false, + compatibilityDate: compatibilityDate || "latest", + }).then((p) => p?._meta?.name); + } + + return { + ...configOverrides, + preset, + typescript: { + generateRuntimeConfigTypes: !isCustomFramework, + ...getConf("typescript"), + ...configOverrides.typescript, + }, + }; + }, + async resolve(id: string) { + const preset = await resolvePreset(id, { + static: configOverrides.static, + compatibilityDate: compatibilityDate || "latest", + dev: configOverrides.dev, + }); + if (preset) { + return { + config: klona(preset), + }; + } + }, + ...opts.c12, + }); + + const options = klona(loadedConfig.config) as NitroOptions; + + options._config = configOverrides; + options._c12 = loadedConfig; + + const _presetName = + (loadedConfig.layers || []).find((l) => l.config?._meta?.name)?.config?._meta?.name || preset; + options.preset = _presetName as PresetName; + + options.compatibilityDate = resolveCompatibilityDates( + compatibilityDate, + options.compatibilityDate + ); + + if (options.dev && options.preset !== "nitro-dev") { + consola.info(`Using \`${options.preset}\` emulation in development mode.`); + } + + return options; +} diff --git a/src/core/config/resolvers/assets.ts b/src/config/resolvers/assets.ts similarity index 74% rename from src/core/config/resolvers/assets.ts rename to src/config/resolvers/assets.ts index 69cd2f37a4..732335789c 100644 --- a/src/core/config/resolvers/assets.ts +++ b/src/config/resolvers/assets.ts @@ -1,6 +1,6 @@ import { existsSync } from "node:fs"; import { defu } from "defu"; -import type { NitroOptions } from "nitropack/types"; +import type { NitroOptions } from "nitro/types"; import { resolve } from "pathe"; import { withLeadingSlash, withoutTrailingSlash } from "ufo"; @@ -8,13 +8,11 @@ export async function resolveAssetsOptions(options: NitroOptions) { // Public Assets // 1. Normalize user paths for (const publicAsset of options.publicAssets) { - publicAsset.dir = resolve(options.srcDir, publicAsset.dir); - publicAsset.baseURL = withLeadingSlash( - withoutTrailingSlash(publicAsset.baseURL || "/") - ); + publicAsset.dir = resolve(options.rootDir, publicAsset.dir); + publicAsset.baseURL = withLeadingSlash(withoutTrailingSlash(publicAsset.baseURL || "/")); } // 2. Add public/ directories from each layer - for (const dir of options.scanDirs) { + for (const dir of [options.rootDir, ...options.scanDirs]) { const publicDir = resolve(dir, "public"); if (!existsSync(publicDir)) { continue; @@ -28,12 +26,12 @@ export async function resolveAssetsOptions(options: NitroOptions) { // Server Assets // 1. Normalize user paths for (const serverAsset of options.serverAssets) { - serverAsset.dir = resolve(options.srcDir, serverAsset.dir); + serverAsset.dir = resolve(options.rootDir, serverAsset.dir); } // 2. Add server/ directory options.serverAssets.push({ baseName: "server", - dir: resolve(options.srcDir, "assets"), + dir: resolve(options.rootDir, "assets"), }); // Infer `fallthrough` and `maxAge` from publicAssets @@ -42,8 +40,7 @@ export async function resolveAssetsOptions(options: NitroOptions) { const isTopLevel = asset.baseURL === "/"; asset.fallthrough = asset.fallthrough ?? isTopLevel; const routeRule = options.routeRules[asset.baseURL + "/**"]; - asset.maxAge = - (routeRule?.cache as { maxAge: number })?.maxAge ?? asset.maxAge ?? 0; + asset.maxAge = (routeRule?.cache as { maxAge: number })?.maxAge ?? asset.maxAge ?? 0; if (asset.maxAge && !asset.fallthrough) { options.routeRules[asset.baseURL + "/**"] = defu(routeRule, { headers: { diff --git a/src/config/resolvers/builder.ts b/src/config/resolvers/builder.ts new file mode 100644 index 0000000000..7229151c08 --- /dev/null +++ b/src/config/resolvers/builder.ts @@ -0,0 +1,78 @@ +import { existsSync, readFileSync } from "node:fs"; +import { createRequire } from "node:module"; +import consola from "consola"; +import type { NitroOptions } from "nitro/types"; +import { resolve } from "pathe"; + +const VALID_BUILDERS = ["rolldown", "rollup", "vite"] as const; + +export async function resolveBuilder(options: NitroOptions) { + // NITRO_BUILDER environment variable + options.builder ??= process.env.NITRO_BUILDER as any; + + // Builder is explicitly set + if (options.builder) { + // Validate builder name + if (!VALID_BUILDERS.includes(options.builder)) { + throw new Error( + `Invalid nitro builder "${options.builder}". Valid builders are: ${VALID_BUILDERS.join(", ")}.` + ); + } + // Check if the builder package is installed (rolldown is a direct dep) + const pkg = options.builder; + if (pkg !== "rolldown" && !isPkgInstalled(pkg, options.rootDir)) { + const shouldInstall = await consola.prompt( + `Nitro builder package \`${pkg}\` is not installed. Would you like to install it?`, + { type: "confirm", default: true, cancel: "null" } + ); + if (!shouldInstall) { + throw new Error( + `Nitro builder package "${options.builder}" is not installed. Please install it in your project dependencies.` + ); + } + await installPkg(pkg, options.rootDir); + } + return; + } + + // Auto-detect: check for vite.config with nitro() plugin + if (isPkgInstalled("vite", options.rootDir) && hasNitroViteConfig(options)) { + options.builder = "vite"; + return; + } + + // Default to rolldown (direct dependency of nitro) + options.builder = "rolldown"; +} + +const _require = createRequire(import.meta.url); + +function isPkgInstalled(pkg: string, root: string) { + try { + _require.resolve(pkg, { paths: [root] }); + return true; + } catch { + return false; + } +} + +async function installPkg(pkg: string, root: string) { + const { addDevDependency } = await import("nypm"); + return addDevDependency(pkg, { cwd: root }); +} + +function hasNitroViteConfig(options: NitroOptions): boolean { + const configExts = [".ts", ".mts", ".js", ".mjs"]; + for (const ext of configExts) { + const configPath = resolve(options.rootDir, `vite.config${ext}`); + if (existsSync(configPath)) { + try { + const content = readFileSync(configPath, "utf8"); + if (content.includes("nitro(")) { + return true; + } + } catch {} + } + } + return false; +} diff --git a/src/config/resolvers/compatibility.ts b/src/config/resolvers/compatibility.ts new file mode 100644 index 0000000000..c5a897a411 --- /dev/null +++ b/src/config/resolvers/compatibility.ts @@ -0,0 +1,6 @@ +import type { NitroOptions } from "nitro/types"; +import { resolveCompatibilityDatesFromEnv } from "compatx"; + +export async function resolveCompatibilityOptions(options: NitroOptions) { + options.compatibilityDate = resolveCompatibilityDatesFromEnv(options.compatibilityDate); +} diff --git a/src/core/config/resolvers/database.ts b/src/config/resolvers/database.ts similarity index 84% rename from src/core/config/resolvers/database.ts rename to src/config/resolvers/database.ts index 409fbb289e..8ad3217abb 100644 --- a/src/core/config/resolvers/database.ts +++ b/src/config/resolvers/database.ts @@ -1,9 +1,10 @@ -import type { NitroOptions } from "nitropack/types"; +import type { NitroOptions } from "nitro/types"; export async function resolveDatabaseOptions(options: NitroOptions) { if (options.experimental.database && options.imports) { + options.imports.presets ??= []; options.imports.presets.push({ - from: "nitropack/runtime/internal/database", + from: "nitro/database", imports: ["useDatabase"], }); if (options.dev && !options.database && !options.devDatabase) { diff --git a/src/config/resolvers/error.ts b/src/config/resolvers/error.ts new file mode 100644 index 0000000000..91399eef07 --- /dev/null +++ b/src/config/resolvers/error.ts @@ -0,0 +1,17 @@ +import { runtimeDir } from "nitro/meta"; +import type { NitroOptions } from "nitro/types"; +import { join } from "pathe"; +import { resolveNitroPath } from "../../utils/fs.ts"; + +export async function resolveErrorOptions(options: NitroOptions) { + if (!options.errorHandler) { + options.errorHandler = []; + } else if (!Array.isArray(options.errorHandler)) { + options.errorHandler = [options.errorHandler]; + } + + options.errorHandler = options.errorHandler.map((h) => resolveNitroPath(h, options)); + + // Always add the default error handler as the last one + options.errorHandler.push(join(runtimeDir, `internal/error/${options.dev ? "dev" : "prod"}`)); +} diff --git a/src/config/resolvers/export-conditions.ts b/src/config/resolvers/export-conditions.ts new file mode 100644 index 0000000000..8ea4d0c13f --- /dev/null +++ b/src/config/resolvers/export-conditions.ts @@ -0,0 +1,30 @@ +import type { NitroOptions } from "nitro/types"; + +export async function resolveExportConditionsOptions(options: NitroOptions) { + options.exportConditions = _resolveExportConditions(options.exportConditions || [], { + dev: options.dev, + node: options.node, + wasm: options.wasm !== false, + }); +} + +function _resolveExportConditions( + userConditions: string[], + opts: { dev: boolean; node: boolean; wasm?: boolean } +) { + const conditions: string[] = [...userConditions.filter((c) => !c.startsWith("!"))]; + + conditions.push(opts.dev ? "development" : "production"); + + if (opts.wasm) { + conditions.push("wasm", "unwasm"); + } + + if (opts.node) { + conditions.push("node"); + } + + const negated = new Set(userConditions.filter((c) => c.startsWith("!")).map((c) => c.slice(1))); + + return [...new Set(conditions)].filter((c) => !negated.has(c)); +} diff --git a/src/config/resolvers/imports.ts b/src/config/resolvers/imports.ts new file mode 100644 index 0000000000..79345df8f4 --- /dev/null +++ b/src/config/resolvers/imports.ts @@ -0,0 +1,35 @@ +import escapeRE from "escape-string-regexp"; +import type { NitroOptions } from "nitro/types"; +import { join } from "pathe"; + +export async function resolveImportsOptions(options: NitroOptions) { + // Skip loader entirely if imports disabled + if (options.imports === false) { + return; + } + + options.imports.presets ??= []; + + // Auto imports from utils dirs + options.imports.dirs ??= []; + options.imports.dirs.push(...options.scanDirs.map((dir) => join(dir, "utils/**/*"))); + + // Normalize exclude + if (Array.isArray(options.imports.exclude) && options.imports.exclude.length === 0) { + // Exclude .git and buildDir by default + options.imports.exclude.push(/[/\\]\.git[/\\]/); + options.imports.exclude.push(options.buildDir); + + // Exclude all node modules that are not a scanDir + const scanDirsInNodeModules = options.scanDirs + .map((dir) => dir.match(/(?<=\/)node_modules\/(.+)$/)?.[1]) + .filter(Boolean) as string[]; + options.imports.exclude.push( + scanDirsInNodeModules.length > 0 + ? new RegExp( + `node_modules\\/(?!${scanDirsInNodeModules.map((dir) => escapeRE(dir)).join("|")})` + ) + : /[/\\]node_modules[/\\]/ + ); + } +} diff --git a/src/core/config/resolvers/open-api.ts b/src/config/resolvers/open-api.ts similarity index 88% rename from src/core/config/resolvers/open-api.ts rename to src/config/resolvers/open-api.ts index 450b0e92cc..ede9642b97 100644 --- a/src/core/config/resolvers/open-api.ts +++ b/src/config/resolvers/open-api.ts @@ -1,5 +1,5 @@ -import { runtimeDir } from "nitropack/runtime/meta"; -import type { NitroOptions } from "nitropack/types"; +import { runtimeDir } from "nitro/meta"; +import type { NitroOptions } from "nitro/types"; import { join } from "pathe"; export async function resolveOpenAPIOptions(options: NitroOptions) { @@ -13,8 +13,7 @@ export async function resolveOpenAPIOptions(options: NitroOptions) { return; } - const shouldPrerender = - !options.dev && options.openAPI?.production === "prerender"; + const shouldPrerender = !options.dev && options.openAPI?.production === "prerender"; const handlersEnv = shouldPrerender ? "prerender" : ""; diff --git a/src/config/resolvers/paths.ts b/src/config/resolvers/paths.ts new file mode 100644 index 0000000000..c5bbb99db7 --- /dev/null +++ b/src/config/resolvers/paths.ts @@ -0,0 +1,157 @@ +import { prettyPath, resolveNitroPath } from "../../utils/fs.ts"; +import { runtimeDir } from "nitro/meta"; +import type { NitroOptions, NitroConfig } from "nitro/types"; +import { join, resolve } from "pathe"; +import { findWorkspaceDir } from "pkg-types"; +import { NitroDefaults } from "../defaults.ts"; +import { resolveModulePath } from "exsolve"; +import consola from "consola"; + +const RESOLVE_EXTENSIONS = [".ts", ".js", ".mts", ".mjs", ".tsx", ".jsx"]; + +export async function resolvePathOptions(options: NitroOptions) { + options.rootDir = resolve(options.rootDir || ".") + "/"; + options.buildDir = resolve(options.rootDir, options.buildDir || ".") + "/"; + options.workspaceDir ||= + (await findWorkspaceDir(options.rootDir).catch(() => options.rootDir)) + "/"; + + if (options.srcDir) { + if (options.serverDir === undefined) { + options.serverDir = options.srcDir; + } + consola.warn(`"srcDir" option is deprecated. Please use "serverDir" instead.`); + } + + if (options.serverDir !== false) { + if ((options as any).serverDir === true) { + options.serverDir = "server"; + } + options.serverDir = resolve(options.rootDir, options.serverDir || ".") + "/"; + } + + options.alias ??= {}; + + // Resolve possibly template paths + if (!options.static && !options.entry) { + throw new Error(`Nitro entry is missing! Is "${options.preset}" preset correct?`); + } + if (options.entry) { + options.entry = resolveNitroPath(options.entry, options); + } + + options.output.dir = + resolveNitroPath(options.output.dir || NitroDefaults.output!.dir!, options, options.rootDir) + + "/"; + options.output.publicDir = + resolveNitroPath( + options.output.publicDir || NitroDefaults.output!.publicDir!, + options, + options.rootDir + ) + "/"; + options.output.serverDir = + resolveNitroPath( + options.output.serverDir || NitroDefaults.output!.serverDir!, + options, + options.rootDir + ) + "/"; + + // Resolve plugin paths + options.plugins = options.plugins.map((p) => resolveNitroPath(p, options)); + + // Resolve scanDirs + if (options.serverDir) { + options.scanDirs.unshift(options.serverDir); + } + options.scanDirs = options.scanDirs.map((dir) => resolve(options.rootDir, dir)); + options.scanDirs = [...new Set(options.scanDirs.map((dir) => dir + "/"))]; + + // Resolve handler and route paths + options.handlers = options.handlers.map((h) => { + return { + ...h, + handler: resolveNitroPath(h.handler, options), + }; + }); + options.routes = Object.fromEntries( + Object.entries(options.routes).map(([route, h]) => { + if (typeof h === "string") { + h = { handler: h }; + } + h.handler = resolveNitroPath(h.handler, options); + return [route, h]; + }) + ); + + // Server entry + if (options.serverEntry !== false) { + if (typeof options?.serverEntry === "string") { + options.serverEntry = { handler: options.serverEntry }; + } + if (options.serverEntry?.handler) { + options.serverEntry.handler = resolveNitroPath(options.serverEntry.handler, options); + } else { + const detected = resolveModulePath("./server", { + try: true, + from: options.rootDir, + extensions: RESOLVE_EXTENSIONS.flatMap((ext) => [ext, `.node${ext}`]), + }); + if (detected) { + options.serverEntry ??= { handler: "" }; + options.serverEntry.handler = detected; + consola.info(`Detected \`${prettyPath(detected)}\` as server entry.`); + } + } + if (options.serverEntry?.handler && !options.serverEntry?.format) { + const isNode = /\.(node)\.\w+$/.test(options.serverEntry.handler); + options.serverEntry.format = isNode ? "node" : "web"; + } + } + + if ((options as NitroConfig).renderer === false) { + // Skip (auto) resolve renderer, + // and reset it to meet "NitroOptions" requirements + options.renderer = undefined; + } else { + // Resolve renderer handler + if (options.renderer?.handler) { + options.renderer.handler = resolveModulePath( + resolveNitroPath(options.renderer?.handler, options), + { + from: [options.rootDir, ...options.scanDirs], + extensions: RESOLVE_EXTENSIONS, + } + ); + } + + // Resolve renderer template + if (options.renderer?.template) { + options.renderer.template = resolveModulePath( + resolveNitroPath(options.renderer?.template, options), + { + from: [options.rootDir, ...options.scanDirs], + extensions: [".html"], + } + )!; + } else if (!options.renderer?.handler) { + const defaultIndex = resolveModulePath("./index.html", { + from: [options.rootDir, ...options.scanDirs], + extensions: [".html"], + try: true, + }); + if (defaultIndex) { + options.renderer ??= {}; + options.renderer.template = defaultIndex; + consola.info(`Using \`${prettyPath(defaultIndex)}\` as renderer template.`); + } + } + + // Default renderer handler if template is set + if (options.renderer?.template && !options.renderer?.handler) { + options.renderer ??= {}; + options.renderer.handler = join( + runtimeDir, + "internal/routes/renderer-template" + (options.dev ? ".dev" : "") + ); + } + } +} diff --git a/src/core/config/resolvers/route-rules.ts b/src/config/resolvers/route-rules.ts similarity index 78% rename from src/core/config/resolvers/route-rules.ts rename to src/config/resolvers/route-rules.ts index 15a899c53d..bec438a835 100644 --- a/src/core/config/resolvers/route-rules.ts +++ b/src/config/resolvers/route-rules.ts @@ -1,22 +1,11 @@ -import { defu } from "defu"; -import type { - NitroConfig, - NitroOptions, - NitroRouteConfig, - NitroRouteRules, -} from "nitropack/types"; +import type { NitroConfig, NitroOptions, NitroRouteConfig, NitroRouteRules } from "nitro/types"; import { withLeadingSlash } from "ufo"; export async function resolveRouteRulesOptions(options: NitroOptions) { - // Backward compatibility for options.routes - options.routeRules = defu(options.routeRules, (options as any).routes || {}); - options.routeRules = normalizeRouteRules(options); } -export function normalizeRouteRules( - config: NitroConfig -): Record { +export function normalizeRouteRules(config: NitroConfig): Record { const normalizedRules: Record = {}; for (let path in config.routeRules) { const routeConfig = config.routeRules[path] as NitroRouteConfig; @@ -31,7 +20,7 @@ export function normalizeRouteRules( routeRules.redirect = { // @ts-ignore to: "/", - statusCode: 307, + status: 307, ...(typeof routeConfig.redirect === "string" ? { to: routeConfig.redirect } : routeConfig.redirect), @@ -44,9 +33,7 @@ export function normalizeRouteRules( // Proxy if (routeConfig.proxy) { routeRules.proxy = - typeof routeConfig.proxy === "string" - ? { to: routeConfig.proxy } - : routeConfig.proxy; + typeof routeConfig.proxy === "string" ? { to: routeConfig.proxy } : routeConfig.proxy; if (path.endsWith("/**")) { // Internal flag (routeRules.proxy as any)._proxyStripBase = path.slice(0, -3); diff --git a/src/core/config/resolvers/runtime-config.ts b/src/config/resolvers/runtime-config.ts similarity index 86% rename from src/core/config/resolvers/runtime-config.ts rename to src/config/resolvers/runtime-config.ts index d927258575..3373cf496d 100644 --- a/src/core/config/resolvers/runtime-config.ts +++ b/src/config/resolvers/runtime-config.ts @@ -1,9 +1,6 @@ -import defu from "defu"; -import type { - NitroConfig, - NitroOptions, - NitroRuntimeConfig, -} from "nitropack/types"; +import { defu } from "defu"; + +import type { NitroConfig, NitroOptions, NitroRuntimeConfig } from "nitro/types"; export async function resolveRuntimeConfigOptions(options: NitroOptions) { options.runtimeConfig = normalizeRuntimeConfig(options); @@ -13,7 +10,7 @@ export function normalizeRuntimeConfig(config: NitroConfig) { provideFallbackValues(config.runtimeConfig || {}); const runtimeConfig: NitroRuntimeConfig = defu( config.runtimeConfig as NitroRuntimeConfig, - { + { app: { baseURL: config.baseURL, }, @@ -21,8 +18,9 @@ export function normalizeRuntimeConfig(config: NitroConfig) { envExpansion: config.experimental?.envExpansion, openAPI: config.openAPI, }, - } + } as NitroRuntimeConfig ); + runtimeConfig.nitro ??= {}; runtimeConfig.nitro.routeRules = config.routeRules; checkSerializableRuntimeConfig(runtimeConfig); return runtimeConfig as NitroRuntimeConfig; @@ -67,9 +65,5 @@ function checkSerializableRuntimeConfig(obj: any, path: string[] = []) { } function isPrimitiveValue(value: any) { - return ( - typeof value === "string" || - typeof value === "number" || - typeof value === "boolean" - ); + return typeof value === "string" || typeof value === "number" || typeof value === "boolean"; } diff --git a/src/config/resolvers/storage.ts b/src/config/resolvers/storage.ts new file mode 100644 index 0000000000..2fcdb9f867 --- /dev/null +++ b/src/config/resolvers/storage.ts @@ -0,0 +1,5 @@ +import type { NitroOptions } from "nitro/types"; + +export async function resolveStorageOptions(options: NitroOptions) { + // +} diff --git a/src/config/resolvers/tsconfig.ts b/src/config/resolvers/tsconfig.ts new file mode 100644 index 0000000000..b85ba3c5cd --- /dev/null +++ b/src/config/resolvers/tsconfig.ts @@ -0,0 +1,28 @@ +import type { NitroOptions } from "nitro/types"; +import type { TSConfig } from "pkg-types"; +import { join, resolve } from "pathe"; +import * as tsco from "tsconfck"; + +export async function resolveTsconfig(options: NitroOptions) { + const root = resolve(options.rootDir || ".") + "/"; + if (!options.typescript.tsConfig) { + options.typescript.tsConfig = await loadTsconfig(root); + } +} + +async function loadTsconfig(root: string): Promise { + const opts: tsco.TSConfckParseOptions = { + root, + cache: ((loadTsconfig as any)["__cache"] ??= new tsco.TSConfckCache()), + ignoreNodeModules: true, + }; + const tsConfigPath = join(root, "tsconfig.json"); + const parsed = await tsco.parse(tsConfigPath, opts).catch(() => undefined); + if (!parsed) return {} as TSConfig; + const { tsconfig, tsconfigFile } = parsed; + tsconfig.compilerOptions ??= {}; + if (!tsconfig.compilerOptions.baseUrl) { + tsconfig.compilerOptions.baseUrl = resolve(tsconfigFile, ".."); + } + return tsconfig; +} diff --git a/src/core/config/resolvers/unenv.ts b/src/config/resolvers/unenv.ts similarity index 88% rename from src/core/config/resolvers/unenv.ts rename to src/config/resolvers/unenv.ts index c82cbd560b..4fe4b0d306 100644 --- a/src/core/config/resolvers/unenv.ts +++ b/src/config/resolvers/unenv.ts @@ -1,4 +1,4 @@ -import type { NitroOptions } from "nitropack/types"; +import type { NitroOptions } from "nitro/types"; import type { Preset } from "unenv"; export const common: Preset = { @@ -7,11 +7,11 @@ export const common: Preset = { url: import.meta.url, }, alias: { - "node-mock-http/_polyfill/events": "node:events", - "node-mock-http/_polyfill/buffer": "node:buffer", "buffer/": "node:buffer", "buffer/index": "node:buffer", "buffer/index.js": "node:buffer", + "string_decoder/": "node:string_decoder", + "process/": "node:process", }, }; diff --git a/src/core/config/resolvers/url.ts b/src/config/resolvers/url.ts similarity index 79% rename from src/core/config/resolvers/url.ts rename to src/config/resolvers/url.ts index 3ed92147d8..1025de9554 100644 --- a/src/core/config/resolvers/url.ts +++ b/src/config/resolvers/url.ts @@ -1,4 +1,4 @@ -import type { NitroOptions } from "nitropack/types"; +import type { NitroOptions } from "nitro/types"; import { withLeadingSlash, withTrailingSlash } from "ufo"; export async function resolveURLOptions(options: NitroOptions) { diff --git a/src/config/update.ts b/src/config/update.ts new file mode 100644 index 0000000000..620d424ac0 --- /dev/null +++ b/src/config/update.ts @@ -0,0 +1,13 @@ +import consola from "consola"; +import type { Nitro, NitroDynamicConfig } from "nitro/types"; +import { normalizeRouteRules } from "./resolvers/route-rules.ts"; +import { normalizeRuntimeConfig } from "./resolvers/runtime-config.ts"; + +export async function updateNitroConfig(nitro: Nitro, config: NitroDynamicConfig) { + nitro.options.routeRules = normalizeRouteRules(config.routeRules ? config : nitro.options); + nitro.options.runtimeConfig = normalizeRuntimeConfig( + config.runtimeConfig ? config : nitro.options + ); + await nitro.hooks.callHook("rollup:reload"); + consola.success("Nitro config hot reloaded!"); +} diff --git a/src/core/build/build.ts b/src/core/build/build.ts deleted file mode 100644 index ae0e8cacdd..0000000000 --- a/src/core/build/build.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { getRollupConfig } from "nitropack/rollup"; -import type { Nitro } from "nitropack/types"; -import { watchDev } from "./dev"; -import { buildProduction } from "./prod"; - -export async function build(nitro: Nitro) { - await nitro.hooks.callHook("build:before", nitro); - const rollupConfig = getRollupConfig(nitro); - await nitro.hooks.callHook("rollup:before", nitro, rollupConfig); - return nitro.options.dev - ? watchDev(nitro, rollupConfig) - : buildProduction(nitro, rollupConfig); -} diff --git a/src/core/build/dev.ts b/src/core/build/dev.ts deleted file mode 100644 index 41250037b1..0000000000 --- a/src/core/build/dev.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { watch } from "chokidar"; -import defu from "defu"; -import type { Nitro, RollupConfig } from "nitropack/types"; -import { join } from "pathe"; -import { debounce } from "perfect-debounce"; -import * as rollup from "rollup"; -import { scanHandlers } from "../scan"; -import { nitroServerName } from "../utils/nitro"; -import { formatRollupError } from "./error"; -import { writeTypes } from "./types"; - -export async function watchDev(nitro: Nitro, rollupConfig: RollupConfig) { - let rollupWatcher: rollup.RollupWatcher; - - async function load() { - if (rollupWatcher) { - await rollupWatcher.close(); - } - await scanHandlers(nitro); - rollupWatcher = startRollupWatcher(nitro, rollupConfig); - await writeTypes(nitro); - } - const reload = debounce(load); - - const watchPatterns = nitro.options.scanDirs.flatMap((dir) => [ - join(dir, nitro.options.apiDir || "api"), - join(dir, nitro.options.routesDir || "routes"), - join(dir, "middleware"), - join(dir, "plugins"), - join(dir, "modules"), - ]); - - const watchReloadEvents = new Set(["add", "addDir", "unlink", "unlinkDir"]); - const reloadWatcher = watch(watchPatterns, { ignoreInitial: true }).on( - "all", - (event) => { - if (watchReloadEvents.has(event)) { - reload(); - } - } - ); - - nitro.hooks.hook("close", () => { - rollupWatcher.close(); - reloadWatcher.close(); - }); - - nitro.hooks.hook("rollup:reload", () => reload()); - - await load(); -} - -function startRollupWatcher(nitro: Nitro, rollupConfig: RollupConfig) { - const watcher = rollup.watch( - defu(rollupConfig, { - watch: { - chokidar: nitro.options.watchOptions, - }, - }) - ); - let start: number; - - watcher.on("event", (event) => { - // START > BUNDLE_START > BUNDLE_END > END - // START > BUNDLE_START > ERROR > END - switch (event.code) { - case "START": { - start = Date.now(); - nitro.hooks.callHook("dev:start"); - break; - } - case "BUNDLE_END": { - nitro.hooks.callHook("compiled", nitro); - if (nitro.options.logging.buildSuccess) { - nitro.logger.success( - `${nitroServerName(nitro)} built`, - start ? `in ${Date.now() - start}ms` : "" - ); - } - nitro.hooks.callHook("dev:reload"); - break; - } - case "ERROR": { - nitro.logger.error(formatRollupError(event.error)); - nitro.hooks.callHook("dev:error", event.error); - } - } - }); - - return watcher; -} diff --git a/src/core/build/error.ts b/src/core/build/error.ts deleted file mode 100644 index be780cbe3d..0000000000 --- a/src/core/build/error.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type esbuild from "esbuild"; -import { isAbsolute, relative } from "pathe"; -import type rollup from "rollup"; - -export function formatRollupError( - _error: rollup.RollupError | esbuild.OnResolveResult -) { - try { - const logs: string[] = [_error.toString()]; - const errors = (_error as any)?.errors || [_error as rollup.RollupError]; - for (const error of errors) { - const id = - (error as any).path || error.id || (_error as rollup.RollupError).id; - let path = isAbsolute(id) ? relative(process.cwd(), id) : id; - const location = - (error as rollup.RollupError).loc || - (error as esbuild.PartialMessage).location; - if (location) { - path += `:${location.line}:${location.column}`; - } - const text = - (error as esbuild.PartialMessage).text || - (error as rollup.RollupError).frame; - logs.push( - `Rollup error while processing \`${path}\`` + text ? "\n\n" + text : "" - ); - } - return logs.join("\n"); - } catch { - return _error?.toString(); - } -} diff --git a/src/core/build/prod.ts b/src/core/build/prod.ts deleted file mode 100644 index 201c91fd75..0000000000 --- a/src/core/build/prod.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { promises as fsp } from "node:fs"; -import { formatCompatibilityDate } from "compatx"; -import { writeFile } from "nitropack/kit"; -import { version as nitroVersion } from "nitropack/meta"; -import type { Nitro, NitroBuildInfo, RollupConfig } from "nitropack/types"; -import { dirname, join, relative, resolve } from "pathe"; -import * as rollup from "rollup"; -import { presetsWithConfig } from "../../presets/_types.gen"; -import { scanHandlers } from "../scan"; -import { generateFSTree } from "../utils/fs-tree"; -import { nitroServerName } from "../utils/nitro"; -import { snapshotStorage } from "../utils/storage"; -import { formatRollupError } from "./error"; -import { writeTypes } from "./types"; - -export async function buildProduction( - nitro: Nitro, - rollupConfig: RollupConfig -) { - await scanHandlers(nitro); - await writeTypes(nitro); - await _snapshot(nitro); - - if (!nitro.options.static) { - nitro.logger.info( - `Building ${nitroServerName(nitro)} (preset: \`${nitro.options.preset}\`, compatibility date: \`${formatCompatibilityDate(nitro.options.compatibilityDate)}\`)` - ); - const build = await rollup.rollup(rollupConfig).catch((error) => { - nitro.logger.error(formatRollupError(error)); - throw error; - }); - - await build.write(rollupConfig.output); - } - - // Write .output/nitro.json - const buildInfoPath = resolve(nitro.options.output.dir, "nitro.json"); - const buildInfo: NitroBuildInfo = { - date: new Date().toJSON(), - preset: nitro.options.preset, - framework: nitro.options.framework, - versions: { - nitro: nitroVersion, - }, - commands: { - preview: nitro.options.commands.preview, - deploy: nitro.options.commands.deploy, - }, - config: { - ...Object.fromEntries( - presetsWithConfig.map((key) => [key, nitro.options[key]]) - ), - }, - }; - await writeFile(buildInfoPath, JSON.stringify(buildInfo, null, 2)); - - if (!nitro.options.static) { - if (nitro.options.logging.buildSuccess) { - nitro.logger.success(`${nitroServerName(nitro)} built`); - } - if (nitro.options.logLevel > 1) { - process.stdout.write( - (await generateFSTree(nitro.options.output.serverDir, { - compressedSizes: nitro.options.logging.compressedSizes, - })) || "" - ); - } - } - - await nitro.hooks.callHook("compiled", nitro); - - // Show deploy and preview hints - const rOutput = relative(process.cwd(), nitro.options.output.dir); - const rewriteRelativePaths = (input: string) => { - return input.replace(/([\s:])\.\/(\S*)/g, `$1${rOutput}/$2`); - }; - if (buildInfo.commands!.preview) { - nitro.logger.success( - `You can preview this build using \`${rewriteRelativePaths( - buildInfo.commands!.preview - )}\`` - ); - } - if (buildInfo.commands!.deploy) { - nitro.logger.success( - `You can deploy this build using \`${rewriteRelativePaths( - buildInfo.commands!.deploy - )}\`` - ); - } -} - -async function _snapshot(nitro: Nitro) { - if ( - nitro.options.bundledStorage.length === 0 || - nitro.options.preset === "nitro-prerender" - ) { - return; - } - // TODO: Use virtual storage for server assets - const storageDir = resolve(nitro.options.buildDir, "snapshot"); - nitro.options.serverAssets.push({ - baseName: "nitro:bundled", - dir: storageDir, - }); - - const data = await snapshotStorage(nitro); - await Promise.all( - Object.entries(data).map(async ([path, contents]) => { - if (typeof contents !== "string") { - contents = JSON.stringify(contents); - } - const fsPath = join(storageDir, path.replace(/:/g, "/")); - await fsp.mkdir(dirname(fsPath), { recursive: true }); - await fsp.writeFile(fsPath, contents, "utf8"); - }) - ); -} diff --git a/src/core/config/loader.ts b/src/core/config/loader.ts deleted file mode 100644 index 223e4dd9f6..0000000000 --- a/src/core/config/loader.ts +++ /dev/null @@ -1,169 +0,0 @@ -import { loadConfig, watchConfig } from "c12"; -import { type CompatibilityDateSpec, resolveCompatibilityDates } from "compatx"; -import { klona } from "klona/full"; -import type { PresetName } from "nitropack/presets"; -import type { - LoadConfigOptions, - NitroConfig, - NitroOptions, - NitroPresetMeta, -} from "nitropack/types"; - -import { NitroDefaults } from "./defaults"; - -// Resolvers -import { resolveAssetsOptions } from "./resolvers/assets"; -import { - fallbackCompatibilityDate, - resolveCompatibilityOptions, -} from "./resolvers/compatibility"; -import { resolveDatabaseOptions } from "./resolvers/database"; -import { resolveExportConditionsOptions } from "./resolvers/export-conditions"; -import { resolveFetchOptions } from "./resolvers/fetch"; -import { resolveImportsOptions } from "./resolvers/imports"; -import { resolveOpenAPIOptions } from "./resolvers/open-api"; -import { resolvePathOptions } from "./resolvers/paths"; -import { resolveRouteRulesOptions } from "./resolvers/route-rules"; -import { resolveRuntimeConfigOptions } from "./resolvers/runtime-config"; -import { resolveStorageOptions } from "./resolvers/storage"; -import { resolveURLOptions } from "./resolvers/url"; -import { resolveErrorOptions } from "./resolvers/error"; -import { resolveUnenv } from "./resolvers/unenv"; - -const configResolvers = [ - resolveCompatibilityOptions, - resolvePathOptions, - resolveImportsOptions, - resolveRouteRulesOptions, - resolveDatabaseOptions, - resolveFetchOptions, - resolveExportConditionsOptions, - resolveRuntimeConfigOptions, - resolveOpenAPIOptions, - resolveURLOptions, - resolveAssetsOptions, - resolveStorageOptions, - resolveErrorOptions, - resolveUnenv, -] as const; - -export async function loadOptions( - configOverrides: NitroConfig = {}, - opts: LoadConfigOptions = {} -): Promise { - const options = await _loadUserConfig(configOverrides, opts); - for (const resolver of configResolvers) { - await resolver(options); - } - return options; -} - -async function _loadUserConfig( - configOverrides: NitroConfig = {}, - opts: LoadConfigOptions = {} -): Promise { - // Preset - let presetOverride = - (configOverrides.preset as string) || - process.env.NITRO_PRESET || - process.env.SERVER_PRESET; - if (configOverrides.dev) { - presetOverride = "nitro-dev"; - } - - // Load configuration and preset - configOverrides = klona(configOverrides); - - // @ts-ignore - globalThis.defineNitroConfig = globalThis.defineNitroConfig || ((c) => c); - - // Compatibility date - let compatibilityDate: CompatibilityDateSpec | undefined = - configOverrides.compatibilityDate || - opts.compatibilityDate || - ((process.env.NITRO_COMPATIBILITY_DATE || - process.env.SERVER_COMPATIBILITY_DATE || - process.env.COMPATIBILITY_DATE) as CompatibilityDateSpec); - - // Preset resolver - const { resolvePreset } = (await import( - "nitropack/" + "presets" - )) as typeof import("nitropack/presets"); - - const loadedConfig = await ( - opts.watch - ? watchConfig - : loadConfig - )({ - name: "nitro", - cwd: configOverrides.rootDir, - dotenv: configOverrides.dev, - extend: { extendKey: ["extends", "preset"] }, - overrides: { - ...configOverrides, - preset: presetOverride, - }, - async defaultConfig({ configs }) { - const getConf = (key: K) => - (configOverrides[key] ?? - configs.main?.[key] ?? - configs.rc?.[key] ?? - configs.packageJson?.[key]) as NitroConfig[K]; - - if (!compatibilityDate) { - compatibilityDate = getConf("compatibilityDate"); - } - const framework = configs.overrides?.framework || configs.main?.framework; - return { - typescript: { - generateRuntimeConfigTypes: - !framework?.name || framework.name === "nitro", - }, - preset: - presetOverride || - ( - await resolvePreset("" /* auto detect */, { - static: getConf("static"), - compatibilityDate: compatibilityDate || fallbackCompatibilityDate, - }) - )?._meta?.name, - }; - }, - defaults: NitroDefaults, - jitiOptions: { - alias: { - nitropack: "nitropack/config", - "nitropack/config": "nitropack/config", - }, - }, - async resolve(id: string) { - const preset = await resolvePreset(id, { - static: configOverrides.static, - compatibilityDate: compatibilityDate || fallbackCompatibilityDate, - }); - if (preset) { - return { - config: klona(preset), - }; - } - }, - ...opts.c12, - }); - - const options = klona(loadedConfig.config) as NitroOptions; - - options._config = configOverrides; - options._c12 = loadedConfig; - - const _presetName = - (loadedConfig.layers || []).find((l) => l.config?._meta?.name)?.config - ?._meta?.name || presetOverride; - options.preset = _presetName as PresetName; - - options.compatibilityDate = resolveCompatibilityDates( - compatibilityDate, - options.compatibilityDate - ); - - return options; -} diff --git a/src/core/config/resolvers/compatibility.ts b/src/core/config/resolvers/compatibility.ts deleted file mode 100644 index 38ba27a3ad..0000000000 --- a/src/core/config/resolvers/compatibility.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { - type DateString, - formatDate, - resolveCompatibilityDatesFromEnv, -} from "compatx"; -import _consola from "consola"; -import { colors } from "consola/utils"; -import type { NitroOptions } from "nitropack/types"; -import { relative } from "pathe"; - -// Nitro v2.9.6 release -export const fallbackCompatibilityDate = "2024-04-03" as DateString; - -export async function resolveCompatibilityOptions(options: NitroOptions) { - // Normalize and expand compatibility date from environment variables - options.compatibilityDate = resolveCompatibilityDatesFromEnv( - options.compatibilityDate - ); - - // If no compatibility date is specified, prompt or notify the user to set it - if ( - !options.compatibilityDate.default && - options.preset !== "nitro-prerender" - ) { - options.compatibilityDate.default = await _resolveDefault(options); - } -} - -let _fallbackInfoShown = false; -let _promptedUserToUpdate = false; - -async function _resolveDefault(options: NitroOptions): Promise { - const _todayDate = formatDate(new Date()); - - const consola = _consola.withTag("nitro"); - consola.warn(`No valid compatibility date is specified.`); - - const onFallback = () => { - if (!_fallbackInfoShown) { - consola.info( - [ - `Using \`${fallbackCompatibilityDate}\` as fallback.`, - ` Please specify compatibility date to avoid unwanted behavior changes:`, - ` - Add \`compatibilityDate: '${_todayDate}'\` to the config file.`, - ` - Or set \`COMPATIBILITY_DATE=${_todayDate}\` environment variable.`, - ``, - ].join("\n") - ); - _fallbackInfoShown = true; - } - return fallbackCompatibilityDate; - }; - - // Prompt user (once) to attempt auto update (only with Nitro CLI dev command) - const shallUpdate = - options._cli?.command === "dev" && - !_promptedUserToUpdate && - (await consola.prompt( - `Do you want to auto update config file to set ${colors.cyan(`compatibilityDate: '${_todayDate}'`)}?`, - { - type: "confirm", - default: true, - } - )); - _promptedUserToUpdate = true; - if (!shallUpdate) { - return onFallback(); - } - - const { updateConfig } = await import("c12/update"); - const updateResult = await updateConfig({ - configFile: "nitro.config", - cwd: options.rootDir, - async onCreate({ configFile }) { - const shallCreate = await consola.prompt( - `Do you want to initialize a new config in ${colors.cyan(relative(".", configFile))}?`, - { - type: "confirm", - default: true, - } - ); - if (shallCreate !== true) { - return false; - } - return _getDefaultNitroConfig(); - }, - async onUpdate(config) { - config.compatibilityDate = _todayDate; - }, - }).catch((error) => { - consola.error(`Failed to update config: ${error.message}`); - return null; - }); - - if (updateResult?.configFile) { - consola.success( - `Compatibility date set to \`${_todayDate}\` in \`${relative(".", updateResult.configFile)}\`` - ); - return _todayDate; - } - - return onFallback(); -} - -function _getDefaultNitroConfig() { - return /* js */ ` -import { defineNitroConfig } from 'nitropack/config' - -export default defineNitroConfig({}) - `; -} diff --git a/src/core/config/resolvers/error.ts b/src/core/config/resolvers/error.ts deleted file mode 100644 index 346903b139..0000000000 --- a/src/core/config/resolvers/error.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { runtimeDir } from "nitropack/runtime/meta"; -import type { NitroOptions } from "nitropack/types"; -import { join } from "pathe"; - -export async function resolveErrorOptions(options: NitroOptions) { - if (!options.errorHandler) { - options.errorHandler = []; - } else if (!Array.isArray(options.errorHandler)) { - options.errorHandler = [options.errorHandler]; - } - - // Always add the default error handler as the last one - options.errorHandler.push( - join(runtimeDir, `internal/error/${options.dev ? "dev" : "prod"}`) - ); -} diff --git a/src/core/config/resolvers/export-conditions.ts b/src/core/config/resolvers/export-conditions.ts deleted file mode 100644 index 785ae620fc..0000000000 --- a/src/core/config/resolvers/export-conditions.ts +++ /dev/null @@ -1,52 +0,0 @@ -import type { NitroOptions } from "nitropack/types"; - -export async function resolveExportConditionsOptions(options: NitroOptions) { - options.exportConditions = _resolveExportConditions( - options.exportConditions || [], - { dev: options.dev, node: options.node, wasm: options.experimental.wasm } - ); -} - -function _resolveExportConditions( - conditions: string[], - opts: { dev: boolean; node: boolean; wasm?: boolean } -) { - const resolvedConditions: string[] = []; - - // 1. Add dev or production - resolvedConditions.push(opts.dev ? "development" : "production"); - - // 2. Add user specified conditions - resolvedConditions.push(...conditions); - - // 3. Add runtime conditions (node or web) - if (opts.node) { - resolvedConditions.push("node"); - } else { - // https://runtime-keys.proposal.wintercg.org/ - resolvedConditions.push( - "wintercg", - "worker", - "web", - "browser", - "workerd", - "edge-light", - "netlify", - "edge-routine", - "deno" - ); - } - - // 4. Add unwasm conditions - if (opts.wasm) { - resolvedConditions.push("wasm", "unwasm"); - } - - // 5. Add default conditions - resolvedConditions.push("import", "default"); - - // Dedup with preserving order - return resolvedConditions.filter( - (c, i) => resolvedConditions.indexOf(c) === i - ); -} diff --git a/src/core/config/resolvers/fetch.ts b/src/core/config/resolvers/fetch.ts deleted file mode 100644 index d729af940d..0000000000 --- a/src/core/config/resolvers/fetch.ts +++ /dev/null @@ -1,24 +0,0 @@ -import consola from "consola"; -import { join } from "node:path"; -import type { NitroOptions } from "nitropack/types"; -import { nodeMajorVersion, provider } from "std-env"; -import { runtimeDir } from "nitropack/runtime/meta"; - -export async function resolveFetchOptions(options: NitroOptions) { - if (options.experimental.nodeFetchCompat === undefined) { - options.experimental.nodeFetchCompat = (nodeMajorVersion || 0) < 18; - if (options.experimental.nodeFetchCompat && provider !== "stackblitz") { - consola.warn( - "Node fetch compatibility is enabled. Please consider upgrading to Node.js >= 18." - ); - } - } - if (!options.experimental.nodeFetchCompat) { - options.alias = { - "node-fetch-native/polyfill": join(runtimeDir, "internal/empty"), - "node-fetch-native/native": "node-fetch-native/native", - "node-fetch-native": "node-fetch-native/native", - ...options.alias, - }; - } -} diff --git a/src/core/config/resolvers/imports.ts b/src/core/config/resolvers/imports.ts deleted file mode 100644 index 7668350e81..0000000000 --- a/src/core/config/resolvers/imports.ts +++ /dev/null @@ -1,110 +0,0 @@ -import escapeRE from "escape-string-regexp"; -import { resolveModuleExportNames } from "mlly"; -import type { NitroOptions } from "nitropack/types"; -import { join } from "pathe"; -import type { Preset } from "unimport"; - -export async function resolveImportsOptions(options: NitroOptions) { - // Skip loader entirely if imports disabled - if (options.imports === false) { - return; - } - - // Add nitro imports preset - options.imports.presets ??= []; - options.imports.presets.push(...getNitroImportsPreset()); - - // Add h3 auto imports preset - const h3Exports = await resolveModuleExportNames("h3", { - url: import.meta.url, - }); - options.imports.presets ??= []; - options.imports.presets.push({ - from: "h3", - imports: h3Exports.filter((n) => !/^[A-Z]/.test(n) && n !== "use"), - }); - - // Auto imports from utils dirs - options.imports.dirs ??= []; - options.imports.dirs.push( - ...options.scanDirs.map((dir) => join(dir, "utils/**/*")) - ); - - // Normalize exclude - if ( - Array.isArray(options.imports.exclude) && - options.imports.exclude.length === 0 - ) { - // Exclude .git and buildDir by default - options.imports.exclude.push(/[/\\]\.git[/\\]/); - options.imports.exclude.push(options.buildDir); - - // Exclude all node modules that are not a scanDir - const scanDirsInNodeModules = options.scanDirs - .map((dir) => dir.match(/(?<=\/)node_modules\/(.+)$/)?.[1]) - .filter(Boolean) as string[]; - options.imports.exclude.push( - scanDirsInNodeModules.length > 0 - ? new RegExp( - `node_modules\\/(?!${scanDirsInNodeModules - .map((dir) => escapeRE(dir)) - .join("|")})` - ) - : /[/\\]node_modules[/\\]/ - ); - } -} - -function getNitroImportsPreset(): Preset[] { - return [ - { - from: "nitropack/runtime/internal/app", - imports: ["useNitroApp"], - }, - { - from: "nitropack/runtime/internal/config", - imports: ["useRuntimeConfig", "useAppConfig"], - }, - { - from: "nitropack/runtime/internal/plugin", - imports: ["defineNitroPlugin", "nitroPlugin"], - }, - { - from: "nitropack/runtime/internal/cache", - imports: [ - "defineCachedFunction", - "defineCachedEventHandler", - "cachedFunction", - "cachedEventHandler", - ], - }, - { - from: "nitropack/runtime/internal/storage", - imports: ["useStorage"], - }, - { - from: "nitropack/runtime/internal/renderer", - imports: ["defineRenderHandler"], - }, - { - from: "nitropack/runtime/internal/meta", - imports: ["defineRouteMeta"], - }, - { - from: "nitropack/runtime/internal/route-rules", - imports: ["getRouteRules"], - }, - { - from: "nitropack/runtime/internal/context", - imports: ["useEvent"], - }, - { - from: "nitropack/runtime/internal/task", - imports: ["defineTask", "runTask"], - }, - { - from: "nitropack/runtime/internal/error/utils", - imports: ["defineNitroErrorHandler"], - }, - ]; -} diff --git a/src/core/config/resolvers/paths.ts b/src/core/config/resolvers/paths.ts deleted file mode 100644 index 973af6686c..0000000000 --- a/src/core/config/resolvers/paths.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { existsSync } from "node:fs"; -import { resolveNitroPath } from "nitropack/kit"; -import { pkgDir } from "nitropack/runtime/meta"; -import type { NitroOptions } from "nitropack/types"; -import { join, resolve } from "pathe"; -import { findWorkspaceDir } from "pkg-types"; -import { NitroDefaults } from "../defaults"; - -export async function resolvePathOptions(options: NitroOptions) { - options.rootDir = resolve(options.rootDir || "."); - options.workspaceDir ||= await findWorkspaceDir(options.rootDir).catch( - () => options.rootDir - ); - options.srcDir = resolve(options.srcDir || options.rootDir); - for (const key of ["srcDir", "buildDir"] as const) { - options[key] = resolve(options.rootDir, options[key]); - } - - // Add aliases - options.alias = { - ...options.alias, - "~/": join(options.srcDir, "/"), - "@/": join(options.srcDir, "/"), - "~~/": join(options.rootDir, "/"), - "@@/": join(options.rootDir, "/"), - }; - - // Resolve possibly template paths - if (!options.static && !options.entry) { - throw new Error( - `Nitro entry is missing! Is "${options.preset}" preset correct?` - ); - } - if (options.entry) { - options.entry = resolveNitroPath(options.entry, options); - } - options.output.dir = resolveNitroPath( - options.output.dir || NitroDefaults.output!.dir!, - options, - options.rootDir - ); - options.output.publicDir = resolveNitroPath( - options.output.publicDir || NitroDefaults.output!.publicDir!, - options, - options.rootDir - ); - options.output.serverDir = resolveNitroPath( - options.output.serverDir || NitroDefaults.output!.serverDir!, - options, - options.rootDir - ); - - options.nodeModulesDirs.push(resolve(options.workspaceDir, "node_modules")); - options.nodeModulesDirs.push(resolve(options.rootDir, "node_modules")); - options.nodeModulesDirs.push(resolve(pkgDir, "node_modules")); - options.nodeModulesDirs.push(resolve(pkgDir, "..")); // pnpm - options.nodeModulesDirs = [ - ...new Set( - // Adding trailing slash to optimize resolve performance (path is explicitly a dir) - options.nodeModulesDirs.map((dir) => resolve(options.rootDir, dir) + "/") - ), - ]; - - // Resolve plugin paths - options.plugins = options.plugins.map((p) => resolveNitroPath(p, options)); - - // Resolve scanDirs - options.scanDirs.unshift(options.srcDir); - options.scanDirs = options.scanDirs.map((dir) => - resolve(options.srcDir, dir) - ); - options.scanDirs = [...new Set(options.scanDirs)]; - - // Normalize app.config file paths - options.appConfigFiles ??= []; - options.appConfigFiles = options.appConfigFiles - .map((file) => _tryResolve(resolveNitroPath(file, options))) - .filter(Boolean) as string[]; - - // Detect app.config from scanDirs - for (const dir of options.scanDirs) { - const configFile = _tryResolve("app.config", dir); - if (configFile && !options.appConfigFiles.includes(configFile)) { - options.appConfigFiles.push(configFile); - } - } -} - -function _tryResolve( - path: string, - base = ".", - extensions = ["", ".js", ".ts", ".mjs", ".cjs", ".json"] -): string | undefined { - path = resolve(base, path); - if (existsSync(path)) { - return path; - } - for (const ext of extensions) { - const p = path + ext; - if (existsSync(p)) { - return p; - } - } -} diff --git a/src/core/config/resolvers/storage.ts b/src/core/config/resolvers/storage.ts deleted file mode 100644 index 93e351cdf4..0000000000 --- a/src/core/config/resolvers/storage.ts +++ /dev/null @@ -1,36 +0,0 @@ -import type { NitroOptions } from "nitropack/types"; -import { resolve } from "pathe"; - -export async function resolveStorageOptions(options: NitroOptions) { - // Build-only storage - const fsMounts = { - root: resolve(options.rootDir), - src: resolve(options.srcDir), - build: resolve(options.buildDir), - cache: resolve(options.buildDir, "cache"), - } as const; - for (const p in fsMounts) { - options.devStorage[p] = options.devStorage[p] || { - driver: "fs", - readOnly: p === "root" || p === "src", - base: fsMounts[p as keyof typeof fsMounts], - }; - } - - // Runtime storage - if ( - options.dev && - options.storage.data === undefined && - options.devStorage.data === undefined - ) { - options.devStorage.data = { - driver: "fs", - base: resolve(options.rootDir, ".data/kv"), - }; - } else if (options.node && options.storage.data === undefined) { - options.storage.data = { - driver: "fsLite", - base: "./.data/kv", - }; - } -} diff --git a/src/core/config/update.ts b/src/core/config/update.ts deleted file mode 100644 index 3702a0db76..0000000000 --- a/src/core/config/update.ts +++ /dev/null @@ -1,18 +0,0 @@ -import consola from "consola"; -import type { Nitro, NitroDynamicConfig } from "nitropack/types"; -import { normalizeRouteRules } from "./resolvers/route-rules"; -import { normalizeRuntimeConfig } from "./resolvers/runtime-config"; - -export async function updateNitroConfig( - nitro: Nitro, - config: NitroDynamicConfig -) { - nitro.options.routeRules = normalizeRouteRules( - config.routeRules ? config : nitro.options - ); - nitro.options.runtimeConfig = normalizeRuntimeConfig( - config.runtimeConfig ? config : nitro.options - ); - await nitro.hooks.callHook("rollup:reload"); - consola.success("Nitro config hot reloaded!"); -} diff --git a/src/core/dev-server/proxy.ts b/src/core/dev-server/proxy.ts deleted file mode 100644 index 417b41ef5b..0000000000 --- a/src/core/dev-server/proxy.ts +++ /dev/null @@ -1,49 +0,0 @@ -import type { TLSSocket } from "node:tls"; -import type { ProxyServerOptions, ProxyServer } from "httpxy"; -import type { H3Event } from "h3"; - -import { createProxyServer } from "httpxy"; - -export type HTTPProxy = { - proxy: ProxyServer; - handleEvent: (event: H3Event, opts?: ProxyServerOptions) => Promise; -}; - -export function createHTTPProxy(defaults: ProxyServerOptions = {}): HTTPProxy { - const proxy = createProxyServer(defaults); - - proxy.on("proxyReq", (proxyReq, req) => { - if (!proxyReq.hasHeader("x-forwarded-for")) { - const address = req.socket.remoteAddress; - if (address) { - proxyReq.appendHeader("x-forwarded-for", address); - } - } - if (!proxyReq.hasHeader("x-forwarded-port")) { - const localPort = req?.socket?.localPort; - if (localPort) { - proxyReq.setHeader("x-forwarded-port", req.socket.localPort); - } - } - if (!proxyReq.hasHeader("x-forwarded-Proto")) { - const encrypted = (req?.connection as TLSSocket)?.encrypted; - proxyReq.setHeader("x-forwarded-proto", encrypted ? "https" : "http"); - } - }); - - const handleEvent = async (event: H3Event, opts: ProxyServerOptions = {}) => { - try { - event._handled = true; - await proxy.web(event.node.req, event.node.res, opts); - } catch (error: any) { - if (error?.code !== "ECONNRESET") { - throw error; - } - } - }; - - return { - proxy, - handleEvent, - }; -} diff --git a/src/core/dev-server/server.ts b/src/core/dev-server/server.ts deleted file mode 100644 index d19458e16b..0000000000 --- a/src/core/dev-server/server.ts +++ /dev/null @@ -1,314 +0,0 @@ -import type { IncomingMessage, OutgoingMessage } from "node:http"; -import type { Duplex } from "node:stream"; -import type { GetPortInput } from "get-port-please"; -import type { FSWatcher } from "chokidar"; -import type { App } from "h3"; -import type { Listener, ListenOptions } from "listhen"; -import { NodeDevWorker, type DevWorker, type WorkerAddress } from "./worker"; -import type { Nitro, NitroBuildInfo, NitroDevServer } from "nitropack/types"; -import { - createApp, - createError, - eventHandler, - fromNodeMiddleware, - toNodeListener, -} from "h3"; -import { - default as devErrorHandler, - defaultHandler as devErrorHandlerInternal, - loadStackTrace, -} from "../../runtime/internal/error/dev"; -import { version as nitroVersion } from "nitropack/meta"; -import consola from "consola"; -import serveStatic from "serve-static"; -import { writeFile } from "node:fs/promises"; -import { resolve } from "pathe"; -import { watch } from "chokidar"; -import { listen as listhen } from "listhen"; -import { servePlaceholder } from "serve-placeholder"; -import { joinURL } from "ufo"; -import { createVFSHandler } from "./vfs"; -import { debounce } from "perfect-debounce"; -import { isTest, isCI } from "std-env"; -import { createHTTPProxy } from "./proxy"; - -export function createDevServer(nitro: Nitro): NitroDevServer { - const devServer = new DevServer(nitro); - return { - reload: () => devServer.reload(), - listen: (port, opts) => devServer.listen(port, opts), - close: () => devServer.close(), - upgrade: (req, socket, head) => devServer.handleUpgrade(req, socket, head), - get app() { - return devServer.app; - }, - get watcher() { - return devServer.watcher; - }, - }; -} - -let workerIdCtr = 0; - -class DevServer { - nitro: Nitro; - workerDir: string; - app: App; - listeners: Listener[] = []; - reloadPromise?: Promise; - watcher?: FSWatcher; - workers: DevWorker[] = []; - - workerError?: unknown; - - building?: boolean = true /* assume initial build will start soon */; - buildError?: unknown; - - constructor(nitro: Nitro) { - this.nitro = nitro; - - this.workerDir = resolve( - nitro.options.output.dir, - nitro.options.output.serverDir - ); - - this.app = this.createApp(); - - nitro.hooks.hook("close", () => this.close()); - - nitro.hooks.hook("dev:start", () => { - this.building = true; - this.buildError = undefined; - }); - - nitro.hooks.hook("dev:reload", () => { - this.buildError = undefined; - this.building = false; - this.reload(); - }); - - nitro.hooks.hook("dev:error", (cause: unknown) => { - this.buildError = cause; - this.building = false; - for (const worker of this.workers) { - worker.close(); - } - }); - - if (nitro.options.devServer.watch.length > 0) { - const debouncedReload = debounce(() => this.reload()); - this.watcher = watch( - nitro.options.devServer.watch, - nitro.options.watchOptions - ); - this.watcher.on("add", debouncedReload).on("change", debouncedReload); - } - } - - async listen(port: GetPortInput, opts?: Partial) { - const listener = await listhen(toNodeListener(this.app), { port, ...opts }); - this.listeners.push(listener); - listener.server.on("upgrade", (req, sock, head) => - this.handleUpgrade(req, sock, head) - ); - return listener; - } - - async close() { - await Promise.all( - [ - Promise.all(this.listeners.map((l) => l.close())).then(() => { - this.listeners = []; - }), - Promise.all(this.workers.map((w) => w.close())).then(() => { - this.workers = []; - }), - Promise.resolve(this.watcher?.close()).then(() => { - this.watcher = undefined; - }), - ].map((p) => - p.catch((error) => { - consola.error(error); - }) - ) - ); - } - - reload() { - for (const worker of this.workers) { - worker.close(); - } - const worker = new NodeDevWorker(++workerIdCtr, this.workerDir, { - onClose: (worker, cause) => { - this.workerError = cause; - const index = this.workers.indexOf(worker); - if (index !== -1) { - this.workers.splice(index, 1); - } - }, - onReady: (worker, addr) => { - this.writeBuildInfo(worker, addr); - }, - }); - if (!worker.closed) { - this.workers.unshift(worker); - } - } - - async getWorker() { - let retry = 0; - const maxRetries = isTest || isCI ? 100 : 10; - while (this.building || ++retry < maxRetries) { - if ((this.workers.length === 0 || this.buildError) && !this.building) { - return; - } - const activeWorker = this.workers.find((w) => w.ready); - if (activeWorker) { - return activeWorker; - } - await new Promise((resolve) => setTimeout(resolve, 600)); - } - } - - writeBuildInfo(_worker: DevWorker, addr?: WorkerAddress) { - const buildInfoPath = resolve(this.nitro.options.buildDir, "nitro.json"); - const buildInfo: NitroBuildInfo = { - date: new Date().toJSON(), - preset: this.nitro.options.preset, - framework: this.nitro.options.framework, - versions: { - nitro: nitroVersion, - }, - dev: { - pid: process.pid, - workerAddress: addr, - }, - }; - writeFile(buildInfoPath, JSON.stringify(buildInfo, null, 2)).catch( - (error) => { - consola.error(error); - } - ); - } - - createApp() { - // Init h3 app - const app = createApp({ - onError: async (error, event) => { - const errorHandler = - this.nitro.options.devErrorHandler || devErrorHandler; - await loadStackTrace(error).catch(() => {}); - return errorHandler(error, event, { - defaultHandler: devErrorHandlerInternal, - }); - }, - }); - - // Dev-only handlers - for (const handler of this.nitro.options.devHandlers) { - app.use(handler.route || "/", handler.handler); - } - - // Debugging endpoint to view vfs - app.use("/_vfs", createVFSHandler(this.nitro)); - - // Serve asset dirs - for (const asset of this.nitro.options.publicAssets) { - const url = joinURL( - this.nitro.options.runtimeConfig.app.baseURL, - asset.baseURL || "/" - ); - app.use(url, fromNodeMiddleware(serveStatic(asset.dir))); - if (!asset.fallthrough) { - app.use(url, fromNodeMiddleware(servePlaceholder())); - } - } - - // User defined dev proxy - const routes = Object.keys(this.nitro.options.devProxy).sort().reverse(); - for (const route of routes) { - let opts = this.nitro.options.devProxy[route]; - if (typeof opts === "string") { - opts = { target: opts }; - } - const proxy = createHTTPProxy(opts); - app.use( - route, - eventHandler((event) => proxy.handleEvent(event)) - ); - } - - // Main handler - app.use( - eventHandler(async (event) => { - const worker = await this.getWorker(); - if (!worker) { - return this.#generateError(); - } - return worker.handleEvent(event); - }) - ); - - return app; - } - - async handleUpgrade( - req: IncomingMessage, - socket: OutgoingMessage | Duplex, - head: any - ) { - const worker = await this.getWorker(); - if (!worker) { - throw createError({ - statusCode: 503, - message: "No worker available.", - }); - } - return worker.handleUpgrade(req, socket, head); - } - - #generateError() { - const error: any = this.buildError || this.workerError; - if (error) { - try { - error.unhandled = false; - let id = error.id || error.path; - if (id) { - const cause = (error as { errors?: any[] }).errors?.[0]; - const loc = - error.location || error.loc || cause?.location || cause?.loc; - if (loc) { - id += `:${loc.line}:${loc.column}`; - } - error.stack = (error.stack || "").replace( - /(^\s*at\s+.+)/m, - ` at ${id}\n$1` - ); - } - } catch { - // ignore - } - return createError(error); - } - - return new Response( - JSON.stringify( - { - error: "Dev server is unavailable.", - hint: "Please reload the page and check the console for errors if the issue persists.", - }, - null, - 2 - ), - { - status: 503, - statusText: "Dev server is unavailable", - headers: { - "Content-Type": "application/json", - "Cache-Control": "no-store", - Refresh: "3", - }, - } - ); - } -} diff --git a/src/core/dev-server/worker.ts b/src/core/dev-server/worker.ts deleted file mode 100644 index f3d405cf8c..0000000000 --- a/src/core/dev-server/worker.ts +++ /dev/null @@ -1,185 +0,0 @@ -import type { IncomingMessage, OutgoingMessage } from "node:http"; -import type { Duplex } from "node:stream"; -import { createError, type H3Event } from "h3"; -import type { HTTPProxy } from "./proxy"; -import { existsSync } from "node:fs"; -import { rm } from "node:fs/promises"; -import { join } from "pathe"; -import { Worker } from "node:worker_threads"; -import consola from "consola"; -import { isCI, isTest } from "std-env"; -import { createHTTPProxy } from "./proxy"; - -export type WorkerAddress = { host: string; port: number; socketPath?: string }; - -export interface WorkerHooks { - onClose?: (worker: DevWorker, cause?: unknown) => void; - onReady?: (worker: DevWorker, address?: WorkerAddress) => void; -} - -export interface DevWorker { - readonly ready: boolean; - readonly closed: boolean; - close(): Promise; - handleEvent: (event: H3Event) => Promise; - handleUpgrade: ( - req: IncomingMessage, - socket: OutgoingMessage | Duplex, - head: any - ) => void; -} - -export class NodeDevWorker implements DevWorker { - closed: boolean = false; - #id: number; - #workerDir: string; - #hooks: WorkerHooks; - - #address?: WorkerAddress; - #proxy?: HTTPProxy; - #worker?: Worker & { _exitCode?: number }; - - constructor(id: number, workerDir: string, hooks: WorkerHooks = {}) { - this.#id = id; - this.#workerDir = workerDir; - this.#hooks = hooks; - this.#proxy = createHTTPProxy(); - this.#initWorker(); - } - - get ready() { - return Boolean( - !this.closed && this.#address && this.#proxy && this.#worker - ); - } - - async handleEvent(event: H3Event) { - if (!this.#address || !this.#proxy) { - throw createError({ - status: 503, - statusText: "Dev worker is unavailable", - }); - } - await this.#proxy.handleEvent(event, { target: this.#address }); - } - - handleUpgrade( - req: IncomingMessage, - socket: OutgoingMessage | Duplex, - head: any - ) { - if (!this.ready) { - return; - } - return this.#proxy!.proxy.ws( - req, - socket as OutgoingMessage, - { target: this.#address, xfwd: true }, - head - ); - } - - #initWorker() { - const workerEntryPath = join(this.#workerDir, "index.mjs"); - - if (!existsSync(workerEntryPath)) { - this.close(`worker entry not found in "${workerEntryPath}".`); - return; - } - - const worker = new Worker(workerEntryPath, { - env: { - ...process.env, - NITRO_DEV_WORKER_ID: String(this.#id), - }, - }) as Worker & { _exitCode?: number }; - - worker.once("exit", (code) => { - worker._exitCode = code; - this.close(`worker exited with code ${code}`); - }); - - worker.once("error", (error) => { - this.close(error); - }); - - worker.on("message", (message) => { - if (message?.address) { - this.#address = message.address; - this.#hooks.onReady?.(this, this.#address); - } - }); - - this.#worker = worker; - } - - async close(cause?: unknown) { - if (this.closed) { - return; - } - this.closed = true; - this.#hooks.onClose?.(this, cause); - this.#hooks = {}; - await Promise.all( - [this.#closeProxy(), this.#closeSocket(), this.#closeWorker()].map((p) => - p.catch((error) => consola.error(error)) - ) - ); - } - - async #closeProxy() { - this.#proxy?.proxy?.close(() => { - // TODO: it will be never called! Investigate why and then await on it. - }); - this.#proxy = undefined; - } - - async #closeSocket() { - const socketPath = this.#address?.socketPath; - if ( - socketPath && - socketPath[0] !== "\0" && - !socketPath.startsWith(String.raw`\\.\pipe`) - ) { - await rm(socketPath).catch(() => {}); - } - this.#address = undefined; - } - - async #closeWorker() { - if (!this.#worker) { - return; - } - this.#worker.postMessage({ event: "shutdown" }); - - if (!this.#worker._exitCode && !isTest && !isCI) { - await new Promise((resolve) => { - const gracefulShutdownTimeoutSec = - Number.parseInt(process.env.NITRO_SHUTDOWN_TIMEOUT || "", 10) || 5; - const timeout = setTimeout(() => { - if (process.env.DEBUG) { - consola.warn(`force closing dev worker...`); - } - }, gracefulShutdownTimeoutSec * 1000); - - this.#worker?.on("message", (message) => { - if (message.event === "exit") { - clearTimeout(timeout); - resolve(); - } - }); - }); - } - this.#worker.removeAllListeners(); - await this.#worker.terminate().catch((error) => { - consola.error(error); - }); - this.#worker = undefined; - } - - [Symbol.for("nodejs.util.inspect.custom")]() { - // eslint-disable-next-line unicorn/no-nested-ternary - const status = this.closed ? "closed" : this.ready ? "ready" : "pending"; - return `NodeDevWorker#${this.#id}(${status})`; - } -} diff --git a/src/core/index.ts b/src/core/index.ts deleted file mode 100644 index f54142dc0a..0000000000 --- a/src/core/index.ts +++ /dev/null @@ -1,163 +0,0 @@ -import type { AppOptions, H3Event } from "h3"; -import type { - CaptureError, - NitroConfig, - NitroOpenAPIConfig, - NitroRouteConfig, - RenderResponse, - RenderContext, -} from "nitropack/types"; - -// Core -export { createNitro } from "./nitro"; - -// Prerender -export { prerender } from "./prerender/prerender"; - -// Dev server -export { createDevServer } from "./dev-server/server"; - -// Config loader -export { loadOptions } from "./config/loader"; - -// Tasks API -export { runTask, listTasks } from "./task"; - -// Build -export { build } from "./build/build"; -export { copyPublicAssets } from "./build/assets"; -export { prepare } from "./build/prepare"; -export { writeTypes } from "./build/types"; - -// ----------- Backward compatibility ----------- - -/** - * @deprecated Please import `defineNitroConfig` from nitropack/config instead - */ -export function defineNitroConfig(config: NitroConfig): NitroConfig { - return config; -} - -/** @deprecated Please import `defineNitroPreset` from nitropack/kit instead */ -export { defineNitroPreset } from "nitropack/kit"; - -/** @deprecated Avoid depending on GLOB_SCAN_PATTERN */ -export { GLOB_SCAN_PATTERN } from "./scan"; - -/** @deprecated Directly import { runtimeDependencies } from "nitropack/runtime/meta"; */ -export { runtimeDependencies as nitroRuntimeDependencies } from "nitropack/runtime/meta"; - -/** @deprecated Avoid depending on scan utils */ -export { - scanHandlers, - scanMiddleware, - scanModules, - scanPlugins, - scanServerRoutes, - scanTasks, -} from "./scan"; - -/** @deprecated Use `NitroRuntimeConfig` from `nitropack/types` */ -export interface NitroRuntimeConfig { - app: NitroRuntimeConfigApp; - nitro: { - envPrefix?: string; - envExpansion?: boolean; - routeRules?: { - [path: string]: NitroRouteConfig; - }; - openAPI?: NitroOpenAPIConfig; - }; - [key: string]: any; -} - -/** @deprecated Use `NitroRuntimeHooks` from `nitropack/types` */ -export interface NitroRuntimeHooks { - close: () => void; - error: CaptureError; - - request: NonNullable; - beforeResponse: NonNullable; - afterResponse: NonNullable; - - "render:before": (context: RenderContext) => void; - - "render:response": ( - response: Partial, - context: RenderContext - ) => void; -} - -/** @deprecated Use `NitroRuntimeConfigApp` from `nitropack/types` */ -export interface NitroRuntimeConfigApp { - baseURL: string; - [key: string]: any; -} - -/** @deprecated Directly import { ... } from "nitropack/types"; */ -export type { - LoadConfigOptions, - Nitro, - NitroConfig, - NitroDevServer, - NitroOptions, - NitroPreset, - NitroWorker, - Serialize, - SerializeObject, - SerializeTuple, - Simplify, - $Fetch, - AppConfig, - AvailableRouterMethod, - CompressOptions, - DatabaseConnectionConfig, - DatabaseConnectionConfigs, - DatabaseConnectionName, - DevServerOptions, - ExtractedRouteMethod, - H3Event$Fetch, - H3EventFetch, - InternalApi, - MatchedRoutes, - MiddlewareOf, - NitroBuildInfo, - NitroDevEventHandler, - NitroDynamicConfig, - NitroErrorHandler, - NitroEventHandler, - NitroFetchOptions, - NitroFetchRequest, - NitroFrameworkInfo, - NitroHooks, - NitroModule, - NitroModuleInput, - NitroRouteConfig, - NitroRouteRules, - // NitroRuntimeConfig, - // NitroRuntimeConfigApp, - NitroStaticBuildFlags, - NitroTypes, - PrerenderGenerateRoute, - PrerenderRoute, - PublicAssetDir, - ServerAssetDir, - StorageMounts, - TypedInternalResponse, - // KebabCase, - // Runtime - RenderResponse, - RenderHandler, - TaskContext, - TaskPayload, - TaskMeta, - TaskEvent, - TaskResult, - Task, - NitroAppPlugin, - CacheEntry, - CacheOptions, - ResponseCacheEntry, - CachedEventHandlerOptions, - NitroApp, -} from "nitropack/types"; diff --git a/src/core/task.ts b/src/core/task.ts deleted file mode 100644 index b4da412cf5..0000000000 --- a/src/core/task.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { existsSync } from "node:fs"; -import { readFile } from "node:fs/promises"; -import type { - Nitro, - NitroBuildInfo, - TaskEvent, - TaskRunnerOptions, -} from "nitropack/types"; -import { ofetch } from "ofetch"; -import { normalize, resolve } from "pathe"; - -/** @experimental */ -export async function runTask( - taskEvent: TaskEvent, - opts?: TaskRunnerOptions -): Promise<{ result: unknown }> { - const ctx = await _getTasksContext(opts); - const result = await ctx.devFetch(`/_nitro/tasks/${taskEvent.name}`, { - method: "POST", - body: taskEvent, - }); - return result; -} - -/** @experimental */ -export async function listTasks(opts?: TaskRunnerOptions) { - const ctx = await _getTasksContext(opts); - const res = (await ctx.devFetch("/_nitro/tasks")) as { - tasks: Record; - }; - return res.tasks; -} - -// --- nitro internal --- -export function addNitroTasksVirtualFile(nitro: Nitro) { - nitro.options.virtual["#nitro-internal-virtual/tasks"] = () => { - const _scheduledTasks = Object.entries(nitro.options.scheduledTasks || {}) - .map(([cron, _tasks]) => { - const tasks = (Array.isArray(_tasks) ? _tasks : [_tasks]).filter( - (name) => { - if (!nitro.options.tasks[name]) { - nitro.logger.warn(`Scheduled task \`${name}\` is not defined!`); - return false; - } - return true; - } - ); - return { cron, tasks }; - }) - .filter((e) => e.tasks.length > 0); - const scheduledTasks: false | { cron: string; tasks: string[] }[] = - _scheduledTasks.length > 0 ? _scheduledTasks : false; - - return /* js */ ` -export const scheduledTasks = ${JSON.stringify(scheduledTasks)}; - -export const tasks = { - ${Object.entries(nitro.options.tasks) - .map( - ([name, task]) => - `"${name}": { - meta: { - description: ${JSON.stringify(task.description)}, - }, - resolve: ${ - task.handler - ? `() => import("${normalize( - task.handler - )}").then(r => r.default || r)` - : "undefined" - }, - }` - ) - .join(",\n")} -};`; - }; -} - -// --- module internal --- - -const _devHint = `(is dev server running?)`; - -async function _getTasksContext(opts?: TaskRunnerOptions) { - const cwd = resolve(process.cwd(), opts?.cwd || "."); - const outDir = resolve(cwd, opts?.buildDir || ".nitro"); - - const buildInfoPath = resolve(outDir, "nitro.json"); - if (!existsSync(buildInfoPath)) { - throw new Error(`Missing info file: \`${buildInfoPath}\` ${_devHint}`); - } - - const buildInfo = JSON.parse( - await readFile(buildInfoPath, "utf8") - ) as NitroBuildInfo; - - if (!buildInfo.dev?.pid || !buildInfo.dev?.workerAddress) { - throw new Error( - `Missing dev server info in: \`${buildInfoPath}\` ${_devHint}` - ); - } - - if (!_pidIsRunning(buildInfo.dev.pid)) { - throw new Error(`Dev server is not running (pid: ${buildInfo.dev.pid})`); - } - - const devFetch = ofetch.create({ - baseURL: `http://${buildInfo.dev.workerAddress.host || "localhost"}:${ - buildInfo.dev.workerAddress.port || "3000" - }`, - // @ts-expect-error - socketPath: buildInfo.dev.workerAddress.socketPath, - }); - - return { - buildInfo, - devFetch, - }; -} - -function _pidIsRunning(pid: number) { - try { - process.kill(pid, 0); - return true; - } catch { - return false; - } -} diff --git a/src/core/utils/nitro.ts b/src/core/utils/nitro.ts deleted file mode 100644 index 4cc8aafd6b..0000000000 --- a/src/core/utils/nitro.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { Nitro } from "nitropack/types"; -import { upperFirst } from "scule"; - -export function nitroServerName(nitro: Nitro) { - return nitro.options.framework.name === "nitro" - ? "Nitro Server" - : `${upperFirst(nitro.options.framework.name as string)} Nitro server`; -} diff --git a/src/core/utils/storage.ts b/src/core/utils/storage.ts deleted file mode 100644 index 5e032ba093..0000000000 --- a/src/core/utils/storage.ts +++ /dev/null @@ -1,47 +0,0 @@ -import type { Nitro } from "nitropack/types"; -import { klona } from "klona"; -import { createStorage as _createStorage, builtinDrivers } from "unstorage"; - -export async function createStorage(nitro: Nitro) { - const storage = _createStorage(); - - // https://github.com/unjs/unstorage/issues/566 - const mounts = klona({ - ...nitro.options.storage, - ...nitro.options.devStorage, - }); - - for (const [path, opts] of Object.entries(mounts)) { - if (opts.driver) { - const driver = await import( - builtinDrivers[opts.driver as keyof typeof builtinDrivers] || - opts.driver - ).then((r) => r.default || r); - storage.mount(path, driver(opts)); - } else { - nitro.logger.warn(`No \`driver\` set for storage mount point "${path}".`); - } - } - - return storage; -} - -export async function snapshotStorage(nitro: Nitro) { - const data: Record = {}; - - const allKeys = [ - ...new Set( - await Promise.all( - nitro.options.bundledStorage.map((base) => nitro.storage.getKeys(base)) - ).then((r) => r.flat()) - ), - ]; - - await Promise.all( - allKeys.map(async (key) => { - data[key] = await nitro.storage.getItem(key); - }) - ); - - return data; -} diff --git a/src/dev/app.ts b/src/dev/app.ts new file mode 100644 index 0000000000..edf4f9289d --- /dev/null +++ b/src/dev/app.ts @@ -0,0 +1,164 @@ +import type { Nitro } from "nitro/types"; +import type { H3Event, HTTPHandler } from "h3"; +import { createProxyServer, type ProxyServerOptions } from "httpxy"; +import type { IncomingMessage, ServerResponse } from "node:http"; +import { H3, toEventHandler, serveStatic, fromNodeHandler, HTTPError } from "h3"; +import { joinURL } from "ufo"; +import mime from "mime"; +import { join, resolve, extname } from "pathe"; +import { stat } from "node:fs/promises"; +import { createReadStream } from "node:fs"; +import { createGzip, createBrotliCompress } from "node:zlib"; +import { createVFSHandler } from "./vfs.ts"; + +import devErrorHandler, { + defaultHandler as devErrorHandlerInternal, + loadStackTrace, +} from "../runtime/internal/error/dev.ts"; + +export class NitroDevApp { + nitro: Nitro; + fetch: (req: Request) => Response | Promise; + + constructor(nitro: Nitro, catchAllHandler?: HTTPHandler) { + this.nitro = nitro; + const app = this.#createApp(catchAllHandler); + this.fetch = app.fetch.bind(app); + } + + #createApp(catchAllHandler?: HTTPHandler) { + // Init h3 app + const app = new H3({ + debug: true, + onError: async (error, event) => { + const errorHandler = this.nitro.options.devErrorHandler || devErrorHandler; + await loadStackTrace(error).catch(() => {}); + return errorHandler(error, event, { + defaultHandler: devErrorHandlerInternal, + }); + }, + }); + + // Dev-only handlers + for (const h of this.nitro.options.devHandlers) { + const handler = toEventHandler(h.handler); + if (!handler) { + this.nitro.logger.warn("Invalid dev handler:", h); + continue; + } + if (h.middleware || !h.route) { + // Middleware + if (h.route) { + app.use(h.route, handler, { method: h.method }); + } else { + app.use(handler, { method: h.method }); + } + } else { + // Route + app.on(h.method || "", h.route, handler, { meta: h.meta as any }); + } + } + + // Debugging endpoint to view vfs + app.get("/_vfs/**", createVFSHandler(this.nitro)); + + // Serve asset dirs + for (const asset of this.nitro.options.publicAssets) { + const assetBase = joinURL(this.nitro.options.baseURL, asset.baseURL || "/"); + app.use(joinURL(assetBase, "**"), (event) => + serveStaticDir(event, { + dir: asset.dir, + base: assetBase, + fallthrough: asset.fallthrough, + }) + ); + } + + // User defined dev proxy + const routes = Object.keys(this.nitro.options.devProxy).sort().reverse(); + for (const route of routes) { + let opts = this.nitro.options.devProxy[route]; + if (typeof opts === "string") { + opts = { target: opts }; + } + const proxy = createHTTPProxy(opts); + app.all(route, proxy.handleEvent); + } + + // Main handler + if (catchAllHandler) { + app.all("/**", catchAllHandler); + } + + return app; + } +} + +// TODO: upstream to h3/node +function serveStaticDir( + event: H3Event, + opts: { dir: string; base: string; fallthrough?: boolean } +) { + const dir = resolve(opts.dir) + "/"; + const r = (id: string) => { + if (!id.startsWith(opts.base) || !extname(id)) return; + const resolved = join(dir, id.slice(opts.base.length)); + if (resolved.startsWith(dir)) { + return resolved; + } + }; + return serveStatic(event, { + fallthrough: opts.fallthrough, + getMeta: async (id) => { + const path = r(id); + if (!path) return; + const s = await stat(path).catch(() => null); + if (!s?.isFile()) return; + const ext = extname(path); + return { + size: s.size, + mtime: s.mtime, + type: mime.getType(ext) || "application/octet-stream", + }; + }, + getContents(id) { + const path = r(id); + if (!path) return; + const stream = createReadStream(path); + const acceptEncoding = event.req.headers.get("accept-encoding") || ""; + if (acceptEncoding.includes("br")) { + event.res.headers.set("Content-Encoding", "br"); + event.res.headers.delete("Content-Length"); + event.res.headers.set("Vary", "Accept-Encoding"); + return stream.pipe(createBrotliCompress()); + } else if (acceptEncoding.includes("gzip")) { + event.res.headers.set("Content-Encoding", "gzip"); + event.res.headers.delete("Content-Length"); + event.res.headers.set("Vary", "Accept-Encoding"); + return stream.pipe(createGzip()); + } + return stream as any; + }, + }); +} + +function createHTTPProxy(defaults: ProxyServerOptions = {}) { + const proxy = createProxyServer({ xfwd: true, ...defaults }); + return { + proxy, + async handleEvent(event: H3Event, opts?: ProxyServerOptions) { + try { + return await fromNodeHandler((req, res) => { + return proxy.web(req as IncomingMessage, res as ServerResponse, opts); + })(event); + } catch (error: any) { + event.res.headers.set("refresh", "3"); + throw new HTTPError({ + status: 503, + message: "Dev server is unavailable.", + cause: error, + }); + } + }, + }; +} diff --git a/src/dev/server.ts b/src/dev/server.ts new file mode 100644 index 0000000000..a6b5e33d87 --- /dev/null +++ b/src/dev/server.ts @@ -0,0 +1,250 @@ +import type { IncomingMessage } from "node:http"; +import type { Socket } from "node:net"; +import type { FSWatcher } from "chokidar"; +import type { ServerOptions, Server } from "srvx"; +import type { EnvRunnerData, RunnerMessageListener, RunnerRPCHooks } from "env-runner"; +import type { RunnerName } from "env-runner"; +import { RunnerManager, loadRunner } from "env-runner"; +import type { Nitro } from "nitro/types"; + +import { HTTPError } from "h3"; + +import consola from "consola"; +import { resolve } from "pathe"; +import { watch } from "chokidar"; +import { serve } from "srvx/node"; +import { debounce } from "perfect-debounce"; +import { isTest, isCI } from "std-env"; +import { NitroDevApp } from "./app.ts"; +import { writeDevBuildInfo } from "../build/info.ts"; + +export function createDevServer(nitro: Nitro): NitroDevServer { + return new NitroDevServer(nitro); +} + +export class NitroDevServer extends NitroDevApp implements RunnerRPCHooks { + #entry: string; + #workerData: EnvRunnerData = {}; + #listeners: Server[] = []; + #watcher?: FSWatcher; + #manager: RunnerManager; + #workerIdCtr: number = 0; + #workerError?: unknown; + #workerRetries: number = 0; + #building?: boolean = true; // Assume initial build will start soon + #buildError?: unknown; + #reloadPromise?: Promise; + + constructor(nitro: Nitro) { + super(nitro, async (event) => { + if (this.#building) { + await this.#waitForBuild(); + } + if (this.#reloadPromise) { + await this.#reloadPromise; + } + if (this.#buildError) { + return this.#generateError(); + } + const response = await this.#manager.fetch(event.req as Request); + if (response.status === 503 && !this.#manager.ready) { + return this.#generateError(); + } + return response; + }); + + // Bind all methods to `this` + for (const key of Object.getOwnPropertyNames(NitroDevServer.prototype)) { + const value = (this as any)[key]; + if (typeof value === "function" && key !== "constructor") { + (this as any)[key] = value.bind(this); + } + } + + // Attach to Nitro.fetch + nitro.fetch = this.fetch.bind(this); + + this.#entry = resolve(nitro.options.output.dir, nitro.options.output.serverDir, "index.mjs"); + + this.#manager = new RunnerManager(); + this.#manager.onReady(async (_runner, addr) => { + this.#workerRetries = 0; + writeDevBuildInfo(this.nitro, addr).catch((error) => { + this.nitro.logger.warn( + `Failed to write dev build info: ${error instanceof Error ? error.message : String(error)}` + ); + }); + }); + this.#manager.onClose((_runner, cause) => { + this.#workerError = cause; + if (this.#workerRetries++ < 3) { + this.nitro.logger.info("Restarting dev worker...", cause ? `Cause: ${cause}` : ""); + this.reload(); + } else { + this.nitro.logger.error( + "Dev worker failed after 3 retries.", + cause ? `Last cause: ${cause}` : "" + ); + } + }); + + nitro.hooks.hook("close", () => this.close()); + + nitro.hooks.hook("dev:start", () => { + this.#building = true; + this.#buildError = undefined; + }); + + nitro.hooks.hook("dev:reload", (payload) => { + this.#buildError = undefined; + this.#building = false; + if (payload?.entry) { + this.#entry = payload.entry; + } + if (payload?.workerData) { + this.#workerData = payload.workerData; + } + this.reload(); + }); + + nitro.hooks.hook("dev:error", (cause: unknown) => { + this.#buildError = cause; + this.#building = false; + }); + + const devWatch = nitro.options.devServer.watch; + if (devWatch && devWatch.length > 0) { + const debouncedReload = debounce(() => this.reload()); + this.#watcher = watch(devWatch, nitro.options.watchOptions); + this.#watcher.on("add", debouncedReload).on("change", debouncedReload); + } + } + + // #region Public Methods + + async upgrade(req: IncomingMessage, socket: Socket, head: any) { + if (!this.#manager.upgrade) { + throw new HTTPError({ + status: 501, + statusText: "Worker does not support upgrades.", + }); + } + return this.#manager.upgrade({ node: { req, socket, head } }); + } + + listen(opts?: Partial>): Server { + const server = serve({ + ...opts, + fetch: this.fetch, + gracefulShutdown: false, + }); + this.#listeners.push(server); + if (server.node?.server) { + server.node.server.on("upgrade", (req, sock, head) => this.upgrade(req, sock, head)); + } + return server; + } + + async close() { + await Promise.all( + [ + Promise.all(this.#listeners.map((l) => l.close())).then(() => { + this.#listeners = []; + }), + this.#manager.close(), + Promise.resolve(this.#watcher?.close()).then(() => { + this.#watcher = undefined; + }), + ].map((p) => + p.catch((error) => { + consola.error(error); + }) + ) + ); + } + + reload() { + const nextReload = (this.#reloadPromise ?? Promise.resolve()) + .catch(() => {}) + .then(() => this.#reload()); + this.#reloadPromise = nextReload.finally(() => { + if (this.#reloadPromise === nextReload) { + this.#reloadPromise = undefined; + } + }); + } + + async #reload() { + const runnerName = + this.nitro.options.devServer.runner || process.env.NITRO_DEV_RUNNER || "node-worker"; + const runner = await loadRunner(runnerName as RunnerName, { + name: `Nitro_${this.#workerIdCtr++}`, + data: { entry: this.#entry, ...this.#workerData }, + }); + await this.#manager.reload(runner); + } + + sendMessage(message: unknown) { + this.#manager.sendMessage(message); + } + + onMessage(listener: RunnerMessageListener) { + this.#manager.onMessage(listener); + } + + offMessage(listener: RunnerMessageListener) { + this.#manager.offMessage(listener); + } + + // #endregion + + // #region Private Methods + + async #waitForBuild() { + const timeout = isTest || isCI ? 60_000 : 6000; + await this.#manager.waitForReady(timeout); + } + + #generateError() { + const error: any = this.#buildError || this.#workerError; + if (error) { + try { + error.unhandled = false; + let id = error.id || error.path; + if (id) { + const cause = (error as { errors?: any[] }).errors?.[0]; + const loc = error.location || error.loc || cause?.location || cause?.loc; + if (loc) { + id += `:${loc.line}:${loc.column}`; + } + error.stack = (error.stack || "").replace(/(^\s*at\s+.+)/m, ` at ${id}\n$1`); + } + } catch { + // ignore + } + return new HTTPError(error); + } + + return new Response( + JSON.stringify( + { + error: "Dev server is unavailable.", + hint: "Please reload the page and check the console for errors if the issue persists.", + }, + null, + 2 + ), + { + status: 503, + statusText: "Dev server is unavailable", + headers: { + "Content-Type": "application/json", + "Cache-Control": "no-store", + Refresh: "3", + }, + } + ); + } + + // #endregion +} diff --git a/src/core/dev-server/vfs.ts b/src/dev/vfs.ts similarity index 72% rename from src/core/dev-server/vfs.ts rename to src/dev/vfs.ts index 1200615cbc..4b4af3e64e 100644 --- a/src/core/dev-server/vfs.ts +++ b/src/dev/vfs.ts @@ -1,41 +1,44 @@ -import { createError, eventHandler, getRequestHeader, getRequestIP } from "h3"; -import type { Nitro } from "nitropack/types"; +import { HTTPError, defineHandler, getRequestIP } from "h3"; +import type { Nitro } from "nitro/types"; export function createVFSHandler(nitro: Nitro) { - return eventHandler(async (event) => { - const ip = getRequestIP(event, { xForwardedFor: false }); + return defineHandler(async (event) => { + const { socket } = event.runtime?.node?.req || {}; + + // prettier-ignore + const isUnixSocket = + // No network addresses + (!socket?.remoteAddress && !socket?.localAddress) && + // Empty address object + Object.keys(socket?.address?.() || {}).length === 0 && + // Socket is readable/writable but has no port info + socket?.readable && socket?.writable && !socket?.remotePort; + + const ip = getRequestIP(event, { xForwardedFor: isUnixSocket }); + const isLocalRequest = ip && /^::1$|^127\.\d+\.\d+\.\d+$/.test(ip); if (!isLocalRequest) { - throw createError({ - message: `Forbidden IP: "${ip || "?"}"`, - statusCode: 403, + throw new HTTPError({ + statusText: `Forbidden IP: "${ip || "?"}"`, + status: 403, }); } - const vfsEntries = { - ...nitro.vfs, - ...nitro.options.virtual, - }; - - const url = event.path || ""; + const url = event.context.params?._ || ""; const isJson = - url.endsWith(".json") || - getRequestHeader(event, "accept")?.includes("application/json"); + url.endsWith(".json") || event.req.headers.get("accept")?.includes("application/json"); const id = decodeURIComponent(url.replace(/^(\.json)?\/?/, "") || ""); - if (id && !(id in vfsEntries)) { - throw createError({ message: "File not found", statusCode: 404 }); + if (id && !nitro.vfs.has(id)) { + throw new HTTPError({ message: "File not found", status: 404 }); } - let content = id ? vfsEntries[id] : undefined; - if (typeof content === "function") { - content = await content(); - } + const content = id ? await nitro.vfs.get(id)?.render() : undefined; if (isJson) { return { rootDir: nitro.options.rootDir, - entries: Object.keys(vfsEntries).map((id) => ({ + entries: [...nitro.vfs.keys()].map((id) => ({ id, path: "/_vfs.json/" + encodeURIComponent(id), })), @@ -49,13 +52,10 @@ export function createVFSHandler(nitro: Nitro) { } const directories: Record = { [nitro.options.rootDir]: {} }; - const fpaths = Object.keys(vfsEntries); + const fpaths = [...nitro.vfs.keys()]; for (const item of fpaths) { - const segments = item - .replace(nitro.options.rootDir, "") - .split("/") - .filter(Boolean); + const segments = item.replace(nitro.options.rootDir, "").split("/").filter(Boolean); let currentDir = item.startsWith(nitro.options.rootDir) ? directories[nitro.options.rootDir] : directories; @@ -69,10 +69,7 @@ export function createVFSHandler(nitro: Nitro) { } } - const generateHTML = ( - directory: Record, - path: string[] = [] - ): string => + const generateHTML = (directory: Record, path: string[] = []): string => Object.entries(directory) .map(([fname, value = {}]) => { const subpath = [...path, fname]; @@ -80,9 +77,7 @@ export function createVFSHandler(nitro: Nitro) { const encodedUrl = encodeURIComponent(key); const linkClass = - url === `/${encodedUrl}` - ? "bg-gray-700 text-white" - : "hover:bg-gray-800 text-gray-200"; + url === `/${encodedUrl}` ? "bg-gray-700 text-white" : "hover:bg-gray-800 text-gray-200"; return Object.keys(value).length === 0 ? ` @@ -109,9 +104,7 @@ export function createVFSHandler(nitro: Nitro) { const rootDirectory = directories[nitro.options.rootDir]; delete directories[nitro.options.rootDir]; - const items = - generateHTML(rootDirectory, [nitro.options.rootDir]) + - generateHTML(directories); + const items = generateHTML(rootDirectory, [nitro.options.rootDir]) + generateHTML(directories); const files = `
@@ -135,6 +128,7 @@ export function createVFSHandler(nitro: Nitro) {
`; + event.res.headers.set("Content-Type", "text/html; charset=utf-8"); return /* html */ ` @@ -180,9 +174,7 @@ const editorTemplate = (options: Record) => ` setTimeout(() => { require(['vs/editor/editor.main'], function () { - monaco.editor.create(document.getElementById('editor'), ${JSON.stringify( - options - )}) + monaco.editor.create(document.getElementById('editor'), ${JSON.stringify(options)}) }) }, 0); diff --git a/src/global.ts b/src/global.ts new file mode 100644 index 0000000000..b7149207eb --- /dev/null +++ b/src/global.ts @@ -0,0 +1,43 @@ +import type { Nitro } from "nitro/types"; + +const nitroInstances: Nitro[] = ((globalThis as any).__nitro_instances__ ||= []); + +const globalKey = "__nitro_builder__"; + +declare global { + var __nitro_builder__: { + fetch: (req: Request) => Promise; + }; +} + +export function registerNitroInstance(nitro: Nitro) { + if (nitroInstances.includes(nitro)) { + return; + } + globalInit(); + nitroInstances.unshift(nitro); + nitro.hooks.hookOnce("close", () => { + nitroInstances.splice(nitroInstances.indexOf(nitro), 1); + if (nitroInstances.length === 0) { + delete (globalThis as any)[globalKey]; + } + }); +} + +function globalInit() { + if (globalThis[globalKey]) { + return; + } + globalThis[globalKey] = { + async fetch(req) { + for (let r = 0; r < 10 && nitroInstances.length === 0; r++) { + await new Promise((resolve) => setTimeout(resolve, 300)); + } + const nitro = nitroInstances[0]; + if (!nitro) { + throw new Error("No Nitro instance is running."); + } + return nitro.fetch(req); + }, + }; +} diff --git a/src/kit/fs.ts b/src/kit/fs.ts deleted file mode 100644 index 7d3d50ce8a..0000000000 --- a/src/kit/fs.ts +++ /dev/null @@ -1,28 +0,0 @@ -import fsp from "node:fs/promises"; -import { consola } from "consola"; -import { dirname } from "pathe"; -import { prettyPath } from "./path"; - -export async function writeFile( - file: string, - contents: Buffer | string, - log = false -) { - await fsp.mkdir(dirname(file), { recursive: true }); - await fsp.writeFile( - file, - contents, - typeof contents === "string" ? "utf8" : undefined - ); - if (log) { - consola.info("Generated", prettyPath(file)); - } -} - -export async function isDirectory(path: string) { - try { - return (await fsp.stat(path)).isDirectory(); - } catch { - return false; - } -} diff --git a/src/kit/index.ts b/src/kit/index.ts deleted file mode 100644 index 9a91fff321..0000000000 --- a/src/kit/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { defineNitroPreset } from "./preset"; -export { defineNitroModule } from "./module"; - -export { writeFile, isDirectory } from "./fs"; -export { prettyPath, resolveNitroPath } from "./path"; diff --git a/src/kit/module.ts b/src/kit/module.ts deleted file mode 100644 index 76f524975c..0000000000 --- a/src/kit/module.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { NitroModule } from "../types/module"; - -export function defineNitroModule(def: NitroModule): NitroModule { - if (typeof def?.setup !== "function") { - def.setup = () => { - throw new TypeError("NitroModule must implement a `setup` method!"); - }; - } - return def; -} diff --git a/src/kit/preset.ts b/src/kit/preset.ts deleted file mode 100644 index 8a10b39740..0000000000 --- a/src/kit/preset.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { fileURLToPath } from "node:url"; -import type { NitroPreset, NitroPresetMeta } from "nitropack/types"; - -export function defineNitroPreset< - P extends NitroPreset, - M extends NitroPresetMeta, ->(preset: P, meta?: M): P & { _meta: NitroPresetMeta } { - if ( - meta?.url && - typeof preset !== "function" && - preset.entry && - preset.entry.startsWith(".") - ) { - preset.entry = fileURLToPath(new URL(preset.entry, meta.url)); - } - return { ...preset, _meta: meta } as P & { _meta: M }; -} diff --git a/src/meta/index.ts b/src/meta/index.ts deleted file mode 100644 index 272c8fe257..0000000000 --- a/src/meta/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { version } from "../../package.json"; diff --git a/src/core/module.ts b/src/module.ts similarity index 58% rename from src/core/module.ts rename to src/module.ts index 95b489518c..1af08d41ec 100644 --- a/src/core/module.ts +++ b/src/module.ts @@ -1,11 +1,9 @@ -import { createJiti } from "jiti"; -import type { Nitro, NitroModule, NitroModuleInput } from "nitropack/types"; +import type { Nitro, NitroModule, NitroModuleInput } from "nitro/types"; +import { resolveModuleURL } from "exsolve"; export async function installModules(nitro: Nitro) { const _modules = [...(nitro.options.modules || [])]; - const modules = await Promise.all( - _modules.map((mod) => _resolveNitroModule(mod, nitro.options)) - ); + const modules = await Promise.all(_modules.map((mod) => _resolveNitroModule(mod, nitro.options))); const _installedURLs = new Set(); for (const mod of modules) { if (mod._url) { @@ -25,26 +23,23 @@ async function _resolveNitroModule( let _url: string | undefined; if (typeof mod === "string") { - // @ts-ignore - globalThis.defineNitroModule = - // @ts-ignore - globalThis.defineNitroModule || ((mod) => mod); - - const jiti = createJiti(nitroOptions.rootDir, { - alias: nitroOptions.alias, + _url = resolveModuleURL(mod, { + from: [nitroOptions.rootDir], + extensions: [".mjs", ".cjs", ".js", ".mts", ".cts", ".ts"], }); - const _modPath = jiti.esmResolve(mod); - _url = _modPath; - mod = (await jiti.import(_modPath, { default: true })) as NitroModule; + mod = (await import(_url).then((m: any) => m.default || m)) as NitroModule; } if (typeof mod === "function") { mod = { setup: mod }; } + if ("nitro" in mod) { + mod = mod.nitro; + } + if (!mod.setup) { - // TODO: Warn? - mod.setup = () => {}; + throw new Error("Invalid Nitro module: missing setup() function."); } return { diff --git a/src/core/nitro.ts b/src/nitro.ts similarity index 53% rename from src/core/nitro.ts rename to src/nitro.ts index a8e543f793..05722b3d7d 100644 --- a/src/core/nitro.ts +++ b/src/nitro.ts @@ -1,20 +1,12 @@ import { consola } from "consola"; -import { createDebugger, createHooks } from "hookable"; -import { runtimeDir } from "nitropack/runtime/meta"; -import type { - LoadConfigOptions, - Nitro, - NitroConfig, - NitroDynamicConfig, -} from "nitropack/types"; -import { join } from "pathe"; -import { createUnimport } from "unimport"; -import { loadOptions } from "./config/loader"; -import { updateNitroConfig } from "./config/update"; -import { installModules } from "./module"; -import { scanAndSyncOptions } from "./scan"; -import { addNitroTasksVirtualFile } from "./task"; -import { createStorage } from "./utils/storage"; +import { Hookable, createDebugger } from "hookable"; +import type { LoadConfigOptions, Nitro, NitroConfig, NitroDynamicConfig } from "nitro/types"; +import { loadOptions } from "./config/loader.ts"; +import { updateNitroConfig } from "./config/update.ts"; +import { installModules } from "./module.ts"; +import { scanAndSyncOptions, scanHandlers } from "./scan.ts"; +import { initNitroRouting } from "./routing.ts"; +import { registerNitroInstance } from "./global.ts"; export async function createNitro( config: NitroConfig = {}, @@ -26,34 +18,33 @@ export async function createNitro( // Create nitro context const nitro: Nitro = { options, - hooks: createHooks(), - vfs: {}, + hooks: new Hookable(), + vfs: new Map(), + routing: {} as any, logger: consola.withTag("nitro"), scannedHandlers: [], - close: () => nitro.hooks.callHook("close"), - storage: undefined as any, + fetch: () => { + throw new Error("no dev server attached!"); + }, + close: () => Promise.resolve(nitro.hooks.callHook("close")), async updateConfig(config: NitroDynamicConfig) { updateNitroConfig(nitro, config); }, }; - // Scan dirs and sync options + // Global setup + registerNitroInstance(nitro); + + // Init routers + initNitroRouting(nitro); + + // Scan dirs (plugins, tasks, modules) and sync options // TODO: Make it side-effect free to allow proper watching await scanAndSyncOptions(nitro); - // Storage - nitro.storage = await createStorage(nitro); - nitro.hooks.hook("close", async () => { - await nitro.storage.dispose(); - }); - - // Debug and timing + // Debug if (nitro.options.debug) { createDebugger(nitro.hooks, { tag: "nitro" }); - nitro.options.plugins.push(join(runtimeDir, "internal/debug")); - } - if (nitro.options.timing) { - nitro.options.plugins.push(join(runtimeDir, "internal/timing")); } // Logger @@ -64,15 +55,13 @@ export async function createNitro( // Hooks nitro.hooks.addHooks(nitro.options.hooks); - // Tasks - addNitroTasksVirtualFile(nitro); - // Scan and install modules await installModules(nitro); // Auto imports if (nitro.options.imports) { // Create unimport instance + const { createUnimport } = await import("unimport"); nitro.unimport = createUnimport(nitro.options.imports); await nitro.unimport.init(); // Support for importing from '#imports' @@ -81,5 +70,11 @@ export async function createNitro( nitro.options.virtual["#nitro"] = 'export * from "#imports"'; } + // Ensure initial handlers are populated + await scanHandlers(nitro); + + // Sync routers + nitro.routing.sync(); + return nitro; } diff --git a/src/core/prerender/prerender.ts b/src/prerender/prerender.ts similarity index 74% rename from src/core/prerender/prerender.ts rename to src/prerender/prerender.ts index 25506f67e7..dfab32a8bb 100644 --- a/src/core/prerender/prerender.ts +++ b/src/prerender/prerender.ts @@ -1,38 +1,26 @@ import { pathToFileURL } from "node:url"; -import { colors } from "consola/utils"; import { defu } from "defu"; import mime from "mime"; -import { writeFile } from "nitropack/kit"; -import type { - Nitro, - NitroRouteRules, - PrerenderRoute, - PublicAssetDir, -} from "nitropack/types"; -import type { $Fetch } from "ofetch"; +import { writeFile } from "../utils/fs.ts"; +import type { Nitro, NitroRouteRules, PrerenderRoute, PublicAssetDir } from "nitro/types"; import { join, relative, resolve } from "pathe"; -import { createRouter as createRadixRouter, toRouteMatcher } from "radix3"; +import { createRouter, addRoute, findAllRoutes } from "rou3"; import { joinURL, withBase, withoutBase, withTrailingSlash } from "ufo"; -import { build } from "../build/build"; -import { createNitro } from "../nitro"; -import { compressPublicAssets } from "../utils/compress"; -import { runParallel } from "../utils/parallel"; -import { - extractLinks, - formatPrerenderRoute, - matchesIgnorePattern, -} from "./utils"; -import { scanUnprefixedPublicAssets } from "../build/assets"; +import { build } from "../build/build.ts"; +import { createNitro } from "../nitro.ts"; +import { compressPublicAssets } from "../utils/compress.ts"; +import { runParallel } from "../utils/parallel.ts"; +import { extractLinks, formatPrerenderRoute, matchesIgnorePattern } from "./utils.ts"; +import { scanUnprefixedPublicAssets } from "../build/assets.ts"; +import { toRequest } from "h3"; const JsonSigRx = /^\s*["[{]|^\s*-?\d{1,16}(\.\d{1,17})?([Ee][+-]?\d+)?\s*$/; // From unjs/destr -const linkParents = new Map>(); +// const linkParents = new Map>(); export async function prerender(nitro: Nitro) { if (nitro.options.noPublicDir) { - nitro.logger.warn( - "Skipping prerender since `noPublicDir` option is enabled." - ); + nitro.logger.warn("Skipping prerender since `noPublicDir` option is enabled."); return; } @@ -70,6 +58,7 @@ export async function prerender(nitro: Nitro) { rootDir: nitro.options.rootDir, logLevel: 0, preset: "nitro-prerender", + builder: nitro.options.builder === "vite" ? "rolldown" : nitro.options.builder, }; await nitro.hooks.callHook("prerender:config", prerendererConfig); const nitroRenderer = await createNitro(prerendererConfig); @@ -88,24 +77,29 @@ export async function prerender(nitro: Nitro) { // Import renderer entry const serverFilename = - typeof nitroRenderer.options.rollupConfig?.output?.entryFileNames === - "string" + typeof nitroRenderer.options.rollupConfig?.output?.entryFileNames === "string" ? nitroRenderer.options.rollupConfig.output.entryFileNames : "index.mjs"; - const serverEntrypoint = resolve( - nitroRenderer.options.output.serverDir, - serverFilename - ); - const { closePrerenderer, localFetch } = (await import( - pathToFileURL(serverEntrypoint).href - )) as { closePrerenderer: () => Promise; localFetch: $Fetch }; + const serverEntrypoint = resolve(nitroRenderer.options.output.serverDir, serverFilename); + const entryURL = pathToFileURL(serverEntrypoint).href; + const prerenderer = (await import(entryURL).then((m: any) => m.default)) as { + close: () => Promise; + fetch: (req: Request) => Promise; + }; // Create route rule matcher - const _routeRulesMatcher = toRouteMatcher( - createRadixRouter({ routes: nitro.options.routeRules }) - ); + const routeRules = createRouter(); + for (const [route, rules] of Object.entries(nitro.options.routeRules)) { + addRoute(routeRules, undefined, route, rules); + } + const _getRouteRules = (path: string) => - defu({}, ..._routeRulesMatcher.matchAll(path).reverse()) as NitroRouteRules; + defu( + {}, + ...findAllRoutes(routeRules, undefined, path) + .map((r) => r.data) + .reverse() + ) as NitroRouteRules; // Start prerendering const generatedRoutes = new Set(); @@ -120,8 +114,7 @@ export async function prerender(nitro: Nitro) { ) .map((a) => withTrailingSlash(a.baseURL)); - const scannedPublicAssets = nitro.options.prerender - .ignoreUnprefixedPublicAssets + const scannedPublicAssets = nitro.options.prerender.ignoreUnprefixedPublicAssets ? new Set(await scanUnprefixedPublicAssets(nitro)) : new Set(); @@ -132,9 +125,11 @@ export async function prerender(nitro: Nitro) { } // Check for explicitly ignored routes - for (const pattern of nitro.options.prerender.ignore) { - if (matchesIgnorePattern(route, pattern)) { - return false; + if (nitro.options.prerender.ignore) { + for (const pattern of nitro.options.prerender.ignore) { + if (matchesIgnorePattern(route, pattern)) { + return false; + } } } @@ -155,8 +150,8 @@ export async function prerender(nitro: Nitro) { }; const canWriteToDisk = (route: PrerenderRoute) => { - // Cannot write routes with query - if (route.route.includes("?")) { + // Cannot write routes with query or containing .. + if (route.route.includes("?") || route.route.includes("..")) { return false; } @@ -165,8 +160,7 @@ export async function prerender(nitro: Nitro) { const FS_MAX_SEGMENT = 255; // 1024 is the max path length on APFS (undocumented) const FS_MAX_PATH = 1024; - const FS_MAX_PATH_PUBLIC_HTML = - FS_MAX_PATH - (nitro.options.output.publicDir.length + 10); + const FS_MAX_PATH_PUBLIC_HTML = FS_MAX_PATH - (nitro.options.output.publicDir.length + 10); if ( (route.route.length >= FS_MAX_PATH_PUBLIC_HTML || @@ -209,14 +203,13 @@ export async function prerender(nitro: Nitro) { // Fetch the route const encodedRoute = encodeURI(route); - const res = await localFetch( - withBase(encodedRoute, nitro.options.baseURL), - { - headers: { "x-nitro-prerender": encodedRoute }, - retry: nitro.options.prerender.retry, - retryDelay: nitro.options.prerender.retryDelay, - } - ); + const req = toRequest(withBase(encodedRoute, nitro.options.baseURL), { + headers: [["x-nitro-prerender", encodedRoute]], + // TODO + // retry: nitro.options.prerender.retry, + // retryDelay: nitro.options.prerender.retryDelay, + }); + const res = await prerenderer.fetch(req); // Data will be removed as soon as written to the disk let dataBuff: Buffer | undefined = Buffer.from(await res.arrayBuffer()); @@ -247,8 +240,10 @@ export async function prerender(nitro: Nitro) { const redirectCodes = [301, 302, 303, 304, 307, 308]; if (![200, ...redirectCodes].includes(res.status)) { _route.error = new Error(`[${res.status}] ${res.statusText}`) as any; - _route.error!.statusCode = res.status; - _route.error!.statusMessage = res.statusText; + // @ts-expect-error (typed as readonly) + _route.error!.status = res.status; + // @ts-expect-error (typed as readonly) + _route.error!.statusText = res.statusText; } // Measure actual time taken for generating route @@ -259,7 +254,7 @@ export async function prerender(nitro: Nitro) { const isImplicitHTML = !route.endsWith(".html") && contentType.includes("html") && - !JsonSigRx.test(dataBuff.subarray(0, 32).toString("utf8")); + !JsonSigRx.test(dataBuff!.subarray(0, 32).toString("utf8")); const routeWithIndex = route.endsWith("/") ? route + "index" : route; const htmlPath = route.endsWith("/") || nitro.options.prerender.autoSubfolderIndex @@ -294,9 +289,9 @@ export async function prerender(nitro: Nitro) { } // Write to the disk - if (canWriteToDisk(_route)) { - const filePath = join(nitro.options.output.publicDir, _route.fileName); - await writeFile(filePath, dataBuff); + const filePath = join(nitro.options.output.publicDir, _route.fileName); + if (canWriteToDisk(_route) && filePath.startsWith(nitro.options.output.publicDir)) { + await writeFile(filePath, dataBuff!); nitro._prerenderedRoutes!.push(_route); } else { _route.skip = true; @@ -305,10 +300,10 @@ export async function prerender(nitro: Nitro) { // Crawl route links if (!_route.error && (isImplicitHTML || route.endsWith(".html"))) { const extractedLinks = await extractLinks( - dataBuff.toString("utf8"), + dataBuff!.toString("utf8"), route, res, - nitro.options.prerender.crawlLinks + nitro.options.prerender.crawlLinks ?? false ); for (const _link of extractedLinks) { if (canPrerender(_link)) { @@ -331,11 +326,11 @@ export async function prerender(nitro: Nitro) { ); await runParallel(routes, generateRoute, { - concurrency: nitro.options.prerender.concurrency, + concurrency: nitro.options.prerender.concurrency || 1, interval: nitro.options.prerender.interval, }); - await closePrerenderer(); + await prerenderer.close(); await nitro.hooks.callHook("prerender:done", { prerenderedRoutes: nitro._prerenderedRoutes, @@ -345,12 +340,12 @@ export async function prerender(nitro: Nitro) { if (nitro.options.prerender.failOnError && failedRoutes.size > 0) { nitro.logger.log("\nErrors prerendering:"); for (const route of failedRoutes) { - const parents = linkParents.get(route.route); - const parentsText = parents?.size - ? `\n${[...parents.values()] - .map((link) => colors.gray(` │ └── Linked from ${link}`)) - .join("\n")}` - : ""; + // const parents = linkParents.get(route.route); + // const parentsText = parents?.size + // ? `\n${[...parents.values()] + // .map((link) => colors.gray(` │ └── Linked from ${link}`)) + // .join("\n")}` + // : ""; nitro.logger.log(formatPrerenderRoute(route)); } nitro.logger.log(""); @@ -359,9 +354,7 @@ export async function prerender(nitro: Nitro) { const prerenderTimeInMs = Date.now() - prerenderStartTime; nitro.logger.info( - `Prerendered ${nitro._prerenderedRoutes.length} routes in ${ - prerenderTimeInMs / 1000 - } seconds` + `Prerendered ${nitro._prerenderedRoutes.length} routes in ${prerenderTimeInMs / 1000} seconds` ); if (nitro.options.compressPublicAssets) { diff --git a/src/core/prerender/utils.ts b/src/prerender/utils.ts similarity index 80% rename from src/core/prerender/utils.ts rename to src/prerender/utils.ts index e73c58325f..520667cd97 100644 --- a/src/core/prerender/utils.ts +++ b/src/prerender/utils.ts @@ -1,5 +1,5 @@ import { colors } from "consola/utils"; -import type { PrerenderRoute } from "nitropack/types"; +import type { PrerenderRoute } from "nitro/types"; import { parseURL } from "ufo"; import { parse as parseHTML, walk } from "ultrahtml"; @@ -16,18 +16,10 @@ const HTML_ENTITIES = { } as Record; function escapeHtml(text: string) { - return text.replace( - /&(lt|gt|amp|apos|quot);/g, - (ch) => HTML_ENTITIES[ch] || ch - ); + return text.replace(/&(lt|gt|amp|apos|quot);/g, (ch) => HTML_ENTITIES[ch] || ch); } -export async function extractLinks( - html: string, - from: string, - res: Response, - crawlLinks: boolean -) { +export async function extractLinks(html: string, from: string, res: Response, crawlLinks: boolean) { const links: string[] = []; const _links: string[] = []; @@ -39,10 +31,7 @@ export async function extractLinks( } const link = escapeHtml(node.attributes.href); - if ( - !decodeURIComponent(link).startsWith("#") && - allowedExtensions.has(getExtension(link)) - ) { + if (!decodeURIComponent(link).startsWith("#") && allowedExtensions.has(getExtension(link))) { _links.push(link); } }); @@ -86,15 +75,12 @@ export function formatPrerenderRoute(route: PrerenderRoute) { if (route.error) { const parents = linkParents.get(route.route); - const errorColor = - colors[route.error.statusCode === 404 ? "yellow" : "red"]; + const errorColor = colors[route.error.status === 404 ? "yellow" : "red"]; const errorLead = parents?.size ? "├──" : "└──"; - str += `\n │ ${errorLead} ${errorColor(route.error.message)}`; + str += `\n │ ${errorLead} ${errorColor(route.error.message || "unknown error")}`; if (parents?.size) { - str += `\n${[...parents.values()] - .map((link) => ` │ └── Linked from ${link}`) - .join("\n")}`; + str += `\n${[...parents.values()].map((link) => ` │ └── Linked from ${link}`).join("\n")}`; } } @@ -112,7 +98,7 @@ type IgnorePattern = | ((path: string) => undefined | null | boolean); export function matchesIgnorePattern(path: string, pattern: IgnorePattern) { if (typeof pattern === "string") { - // TODO: support radix3 patterns + // TODO: support rou3 patterns return path.startsWith(pattern as string); } diff --git a/src/presets/_all.gen.ts b/src/presets/_all.gen.ts index 3dde1f03c6..18730bb704 100644 --- a/src/presets/_all.gen.ts +++ b/src/presets/_all.gen.ts @@ -1,32 +1,33 @@ // Auto-generated using gen-presets script -import _nitro from "./_nitro/preset"; -import _static from "./_static/preset"; -import _alwaysdata from "./alwaysdata/preset"; -import _awsAmplify from "./aws-amplify/preset"; -import _awsLambda from "./aws-lambda/preset"; -import _azure from "./azure/preset"; -import _bun from "./bun/preset"; -import _cleavr from "./cleavr/preset"; -import _cloudflare from "./cloudflare/preset"; -import _deno from "./deno/preset"; -import _digitalocean from "./digitalocean/preset"; -import _edgio from "./edgio/preset"; -import _firebase from "./firebase/preset"; -import _flightcontrol from "./flightcontrol/preset"; -import _genezio from "./genezio/preset"; -import _heroku from "./heroku/preset"; -import _iis from "./iis/preset"; -import _koyeb from "./koyeb/preset"; -import _netlify from "./netlify/preset"; -import _node from "./node/preset"; -import _platformSh from "./platform.sh/preset"; -import _renderCom from "./render.com/preset"; -import _stormkit from "./stormkit/preset"; -import _vercel from "./vercel/preset"; -import _winterjs from "./winterjs/preset"; -import _zeabur from "./zeabur/preset"; -import _zerops from "./zerops/preset"; +import _nitro from "./_nitro/preset.ts"; +import _static from "./_static/preset.ts"; +import _alwaysdata from "./alwaysdata/preset.ts"; +import _awsAmplify from "./aws-amplify/preset.ts"; +import _awsLambda from "./aws-lambda/preset.ts"; +import _azure from "./azure/preset.ts"; +import _bun from "./bun/preset.ts"; +import _cleavr from "./cleavr/preset.ts"; +import _cloudflare from "./cloudflare/preset.ts"; +import _deno from "./deno/preset.ts"; +import _digitalocean from "./digitalocean/preset.ts"; +import _firebase from "./firebase/preset.ts"; +import _flightcontrol from "./flightcontrol/preset.ts"; +import _genezio from "./genezio/preset.ts"; +import _heroku from "./heroku/preset.ts"; +import _iis from "./iis/preset.ts"; +import _koyeb from "./koyeb/preset.ts"; +import _netlify from "./netlify/preset.ts"; +import _node from "./node/preset.ts"; +import _platformSh from "./platform.sh/preset.ts"; +import _renderCom from "./render.com/preset.ts"; +import _standard from "./standard/preset.ts"; +import _stormkit from "./stormkit/preset.ts"; +import _vercel from "./vercel/preset.ts"; +import _winterjs from "./winterjs/preset.ts"; +import _zeabur from "./zeabur/preset.ts"; +import _zephyr from "./zephyr/preset.ts"; +import _zerops from "./zerops/preset.ts"; export default [ ..._nitro, @@ -40,7 +41,6 @@ export default [ ..._cloudflare, ..._deno, ..._digitalocean, - ..._edgio, ..._firebase, ..._flightcontrol, ..._genezio, @@ -51,9 +51,11 @@ export default [ ..._node, ..._platformSh, ..._renderCom, + ..._standard, ..._stormkit, ..._vercel, ..._winterjs, ..._zeabur, + ..._zephyr, ..._zerops, ] as const; diff --git a/src/presets/_nitro/base-worker.ts b/src/presets/_nitro/base-worker.ts index 51a6cca061..e3f2c64037 100644 --- a/src/presets/_nitro/base-worker.ts +++ b/src/presets/_nitro/base-worker.ts @@ -1,4 +1,4 @@ -import { defineNitroPreset } from "nitropack/kit"; +import { defineNitroPreset } from "../_utils/preset.ts"; const baseWorker = defineNitroPreset( { @@ -18,7 +18,6 @@ const baseWorker = defineNitroPreset( }, { name: "base-worker" as const, - url: import.meta.url, } ); diff --git a/src/presets/_nitro/nitro-dev.ts b/src/presets/_nitro/nitro-dev.ts index cc36847369..17de02e503 100644 --- a/src/presets/_nitro/nitro-dev.ts +++ b/src/presets/_nitro/nitro-dev.ts @@ -1,19 +1,30 @@ -import { defineNitroPreset } from "nitropack/kit"; +import { runtimeDir } from "nitro/meta"; +import { defineNitroPreset } from "../_utils/preset.ts"; +import { join } from "pathe"; const nitroDev = defineNitroPreset( { - extends: "node", - entry: "./runtime/nitro-dev", + entry: "./_nitro/runtime/nitro-dev", output: { + dir: "{{ buildDir }}/dev", serverDir: "{{ buildDir }}/dev", + publicDir: "{{ buildDir }}/dev", }, - externals: { trace: false }, + handlers: [ + { + route: "/_nitro/tasks/**", + lazy: true, + handler: join(runtimeDir, "internal/routes/dev-tasks"), + }, + ], + externals: { noTrace: true }, + serveStatic: true, inlineDynamicImports: true, // externals plugin limitation - sourceMap: true, + sourcemap: true, }, { name: "nitro-dev" as const, - url: import.meta.url, + dev: true, } ); diff --git a/src/presets/_nitro/nitro-prerender.ts b/src/presets/_nitro/nitro-prerender.ts index d51147bfcf..9249ae3d2c 100644 --- a/src/presets/_nitro/nitro-prerender.ts +++ b/src/presets/_nitro/nitro-prerender.ts @@ -1,18 +1,16 @@ -import { defineNitroPreset } from "nitropack/kit"; +import { defineNitroPreset } from "../_utils/preset.ts"; const nitroPrerender = defineNitroPreset( { - extends: "node", + entry: "./_nitro/runtime/nitro-prerenderer", serveStatic: true, - entry: "./runtime/nitro-prerenderer", output: { serverDir: "{{ buildDir }}/prerender", }, - externals: { trace: false }, + externals: { noTrace: true }, }, { name: "nitro-prerender" as const, - url: import.meta.url, } ); diff --git a/src/presets/_nitro/preset.ts b/src/presets/_nitro/preset.ts index 9cd521ed09..dd9bce6dd3 100644 --- a/src/presets/_nitro/preset.ts +++ b/src/presets/_nitro/preset.ts @@ -1,6 +1,5 @@ -import worker from "./base-worker"; -import dev from "./nitro-dev"; -import prerender from "./nitro-prerender"; -import sw from "./service-worker"; +import worker from "./base-worker.ts"; +import dev from "./nitro-dev.ts"; +import prerender from "./nitro-prerender.ts"; -export default [...worker, ...dev, ...prerender, ...sw] as const; +export default [...worker, ...dev, ...prerender] as const; diff --git a/src/presets/_nitro/runtime/nitro-dev.ts b/src/presets/_nitro/runtime/nitro-dev.ts index 32c067863d..684b9a6470 100644 --- a/src/presets/_nitro/runtime/nitro-dev.ts +++ b/src/presets/_nitro/runtime/nitro-dev.ts @@ -1,144 +1,36 @@ -import "#nitro-internal-pollyfills"; -import { tmpdir } from "node:os"; -import { useNitroApp } from "nitropack/runtime"; -import { runTask } from "nitropack/runtime"; -import { trapUnhandledNodeErrors } from "nitropack/runtime/internal"; -import { startScheduleRunner } from "nitropack/runtime/internal"; -import { scheduledTasks, tasks } from "#nitro-internal-virtual/tasks"; -import { Server } from "node:http"; -import { join } from "node:path"; -import nodeCrypto from "node:crypto"; -import { parentPort, threadId } from "node:worker_threads"; -import wsAdapter from "crossws/adapters/node"; -import { - defineEventHandler, - getQuery, - getRouterParam, - readBody, - toNodeListener, -} from "h3"; +import "#nitro/virtual/polyfills"; -// globalThis.crypto support for Node.js 18 -if (!globalThis.crypto) { - globalThis.crypto = nodeCrypto as unknown as Crypto; -} - -const { NITRO_NO_UNIX_SOCKET, NITRO_DEV_WORKER_ID } = process.env; +import { useNitroApp, useNitroHooks } from "nitro/app"; +import { startScheduleRunner } from "#nitro/runtime/task"; +import { trapUnhandledErrors } from "#nitro/runtime/error/hooks"; +import { resolveWebsocketHooks } from "#nitro/runtime/app"; -// Trap unhandled errors -trapUnhandledNodeErrors(); - -// Listen for shutdown signal from runner -parentPort?.on("message", (msg) => { - if (msg && msg.event === "shutdown") { - shutdown(); - } -}); +import type { AppEntry } from "env-runner"; const nitroApp = useNitroApp(); +const nitroHooks = useNitroHooks(); -const server = new Server(toNodeListener(nitroApp.h3App)); -let listener: Server | undefined; - -listen() - .catch(() => listen(true /* use random port */)) - // eslint-disable-next-line unicorn/prefer-top-level-await - .catch((error) => { - console.error("Dev worker failed to listen:", error); - return shutdown(); - }); - -// https://crossws.unjs.io/adapters/node -if (import.meta._websocket) { - const { handleUpgrade } = wsAdapter(nitroApp.h3App.websocket); - server.on("upgrade", handleUpgrade); -} - -// Register tasks handlers -nitroApp.router.get( - "/_nitro/tasks", - defineEventHandler(async (event) => { - const _tasks = await Promise.all( - Object.entries(tasks).map(async ([name, task]) => { - const _task = await task.resolve?.(); - return [name, { description: _task?.meta?.description }]; - }) - ); - return { - tasks: Object.fromEntries(_tasks), - scheduledTasks, - }; - }) -); -nitroApp.router.use( - "/_nitro/tasks/:name", - defineEventHandler(async (event) => { - const name = getRouterParam(event, "name") as string; - const payload = { - ...getQuery(event), - ...(await readBody(event) - .then((r) => r?.payload) - .catch(() => ({}))), - }; - return await runTask(name, { payload }); - }) -); +trapUnhandledErrors(); // Scheduled tasks if (import.meta._tasks) { - startScheduleRunner(); + startScheduleRunner({}); } -// --- utils --- - -function listen( - useRandomPort: boolean = Boolean( - NITRO_NO_UNIX_SOCKET || - process.versions.webcontainer || - ("Bun" in globalThis && process.platform === "win32") - ) -) { - return new Promise((resolve, reject) => { - try { - listener = server.listen(useRandomPort ? 0 : getSocketAddress(), () => { - const address = server.address(); - parentPort?.postMessage({ - event: "listen", - address: - typeof address === "string" - ? { socketPath: address } - : { host: "localhost", port: address?.port }, - }); - resolve(); - }); - } catch (error) { - reject(error); - } - }); -} - -function getSocketAddress() { - const socketName = `nitro-worker-${process.pid}-${threadId}-${NITRO_DEV_WORKER_ID}-${Math.round(Math.random() * 10_000)}.sock`; - // Windows: pipe - if (process.platform === "win32") { - return join(String.raw`\\.\pipe`, socketName); - } - // Linux: abstract namespace - if (process.platform === "linux") { - const nodeMajor = Number.parseInt(process.versions.node.split(".")[0], 10); - if (nodeMajor >= 20) { - return `\0${socketName}`; - } - } - // Unix socket - return join(tmpdir(), socketName); -} - -async function shutdown() { - server.closeAllConnections?.(); - await Promise.all([ - new Promise((resolve) => listener?.close(resolve)), - nitroApp.hooks.callHook("close").catch(console.error), - ]); - parentPort?.postMessage({ event: "exit" }); -} +const ws = import.meta._websocket + ? await import("crossws/adapters/node").then((m) => + (m.default || m)({ resolve: resolveWebsocketHooks }) + ) + : undefined; + +export default { + fetch: nitroApp.fetch, + upgrade: ws + ? (context: { node: { req: any; socket: any; head: any } }) => { + ws.handleUpgrade(context.node.req, context.node.socket, context.node.head); + } + : undefined, + ipc: { + onClose: () => nitroHooks.callHook("close"), + }, +} satisfies AppEntry; diff --git a/src/presets/_nitro/runtime/nitro-prerenderer.ts b/src/presets/_nitro/runtime/nitro-prerenderer.ts index d49a222bd3..0edab06074 100644 --- a/src/presets/_nitro/runtime/nitro-prerenderer.ts +++ b/src/presets/_nitro/runtime/nitro-prerenderer.ts @@ -1,11 +1,28 @@ -import "#nitro-internal-pollyfills"; -import { useNitroApp } from "nitropack/runtime"; -import { trapUnhandledNodeErrors } from "nitropack/runtime/internal"; +import "#nitro/virtual/polyfills"; +import consola from "consola"; +import { HTTPError } from "h3"; +import { useNitroApp, useNitroHooks } from "nitro/app"; const nitroApp = useNitroApp(); +const nitroHooks = useNitroHooks(); -export const localFetch = nitroApp.localFetch; -export const closePrerenderer = () => nitroApp.hooks.callHook("close"); +export default { + fetch: nitroApp.fetch, + close: () => nitroHooks.callHook("close"), +}; -// Trap unhandled errors -trapUnhandledNodeErrors(); +nitroHooks.hook("error", (error, context) => { + if ( + !(error as HTTPError).unhandled && + (error as HTTPError).status >= 500 && + context.event?.req?.headers instanceof Headers && + context.event.req.headers.get("x-nitro-prerender") + ) { + consola.error( + `[prerender error]`, + `[${context.event.req.method}]`, + `[${context.event.req.url}]`, + error + ); + } +}); diff --git a/src/presets/_nitro/runtime/service-worker.ts b/src/presets/_nitro/runtime/service-worker.ts index 59c8bbda70..dfe8138e54 100644 --- a/src/presets/_nitro/runtime/service-worker.ts +++ b/src/presets/_nitro/runtime/service-worker.ts @@ -1,6 +1,7 @@ -import "#nitro-internal-pollyfills"; -import { useNitroApp } from "nitropack/runtime"; -import { isPublicAssetURL } from "#nitro-internal-virtual/public-assets"; +import "#nitro/virtual/polyfills"; +import { useNitroApp } from "nitro/app"; +import { isPublicAssetURL } from "#nitro/virtual/public-assets"; +import type { ServerRequest } from "srvx"; const nitroApp = useNitroApp(); @@ -11,24 +12,14 @@ addEventListener("fetch", (event: FetchEvent) => { return; } - event.respondWith(handleEvent(url, event)); -}); - -async function handleEvent(url: URL, event: FetchEvent) { - let body; - if (event.request.body) { - body = await event.request.arrayBuffer(); - } + // srvx compatibility + const req = event.request as unknown as ServerRequest; + req.runtime ??= { name: "service-worker" }; + req.runtime.serviceWorker ??= { event } as any; + req.waitUntil = event.waitUntil.bind(event); - return nitroApp.localFetch(url.pathname + url.search, { - host: url.hostname, - protocol: url.protocol, - headers: event.request.headers, - method: event.request.method, - redirect: event.request.redirect, - body, - }); -} + event.respondWith(nitroApp.fetch(req)); +}); declare const self: ServiceWorkerGlobalScope; diff --git a/src/presets/_nitro/service-worker.ts b/src/presets/_nitro/service-worker.ts deleted file mode 100644 index 92fc15e0e8..0000000000 --- a/src/presets/_nitro/service-worker.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { existsSync, promises as fsp } from "node:fs"; -import { defineNitroPreset } from "nitropack/kit"; -import type { Nitro } from "nitropack/types"; -import { resolve } from "pathe"; -import { joinURL } from "ufo"; - -const serviceWorker = defineNitroPreset( - () => { - return { - extends: "base-worker", - entry: "./runtime/service-worker", - output: { - serverDir: "{{ output.dir }}/public/server", - }, - commands: { - preview: "npx serve ./public", - }, - hooks: { - "prerender:generate"(route, nitro) { - const script = scriptTemplate(nitro.options.baseURL); - route.contents = (route.contents || "").replace( - "", - `${script}\n` - ); - }, - async compiled(nitro: Nitro) { - // Write sw.js file - await fsp.writeFile( - resolve(nitro.options.output.publicDir, "sw.js"), - `self.importScripts('${joinURL( - nitro.options.baseURL, - "server/index.mjs" - )}');`, - "utf8" - ); - - // Write fallback initializer files - const html = htmlTemplate(nitro.options.baseURL); - if ( - !existsSync(resolve(nitro.options.output.publicDir, "index.html")) - ) { - await fsp.writeFile( - resolve(nitro.options.output.publicDir, "index.html"), - html, - "utf8" - ); - } - if ( - !existsSync(resolve(nitro.options.output.publicDir, "200.html")) - ) { - await fsp.writeFile( - resolve(nitro.options.output.publicDir, "200.html"), - html, - "utf8" - ); - } - if ( - !existsSync(resolve(nitro.options.output.publicDir, "404.html")) - ) { - await fsp.writeFile( - resolve(nitro.options.output.publicDir, "404.html"), - html, - "utf8" - ); - } - }, - }, - }; - }, - { - name: "service-worker" as const, - url: import.meta.url, - } -); - -export default [serviceWorker] as const; - -function htmlTemplate(baseURL = "/") { - return /* html */ ` - - - - - - ${scriptTemplate(baseURL)} - - - Initializing nitro service worker... - -`; -} - -function scriptTemplate(baseURL = "/") { - return /* js */ ` - -`; -} diff --git a/src/presets/_resolve.ts b/src/presets/_resolve.ts index f996668c00..ab33108ea1 100644 --- a/src/presets/_resolve.ts +++ b/src/presets/_resolve.ts @@ -1,13 +1,10 @@ -import { - type CompatibilityDateSpec, - type PlatformName, - resolveCompatibilityDatesFromEnv, - formatCompatibilityDate, -} from "compatx"; -import type { NitroPreset, NitroPresetMeta } from "nitropack/types"; +import { resolveCompatibilityDatesFromEnv, formatCompatibilityDate } from "compatx"; +import type { CompatibilityDateSpec, PlatformName } from "compatx"; +import type { NitroPreset, NitroPresetMeta } from "nitro/types"; import { kebabCase } from "scule"; -import { type ProviderName, provider } from "std-env"; -import allPresets from "./_all.gen"; +import { provider, runtime } from "std-env"; +import type { ProviderName } from "std-env"; +import allPresets from "./_all.gen.ts"; // std-env has more specific keys for providers than compatx const _stdProviderMap: Partial> = { @@ -18,8 +15,16 @@ const _stdProviderMap: Partial> = { export async function resolvePreset( name: string, - opts: { static?: boolean; compatibilityDate?: false | CompatibilityDateSpec } + opts: { + static?: boolean; + compatibilityDate?: false | CompatibilityDateSpec; + dev?: boolean; + } = {} ): Promise<(NitroPreset & { _meta?: NitroPresetMeta }) | undefined> { + if (name === ".") { + return undefined; // invalid input + } + const _name = kebabCase(name) || provider; const _compatDates = opts.compatibilityDate @@ -34,11 +39,14 @@ export async function resolvePreset( return false; } + // Match dev|prod + if ((opts.dev && !preset._meta.dev) || (!opts.dev && preset._meta.dev)) { + return false; + } + if (_compatDates) { const _date = - _compatDates[ - _stdProviderMap[preset._meta.stdName!] as PlatformName - ] || + _compatDates[_stdProviderMap[preset._meta.stdName!] as PlatformName] || _compatDates[preset._meta.stdName as PlatformName] || _compatDates[preset._meta.name as PlatformName] || _compatDates.default; @@ -61,18 +69,20 @@ export async function resolvePreset( }); const preset = - matches.find( - (p) => (p._meta.static || false) === (opts?.static || false) - ) || matches[0]; + matches.find((p) => (p._meta.static || false) === (opts?.static || false)) || matches[0]; if (typeof preset === "function") { + // @ts-expect-error unreachable return preset(); } + // Auto-detect preset if (!name && !preset) { - return opts?.static - ? resolvePreset("static", opts) - : resolvePreset("node-server", opts); + if (opts?.static) { + return resolvePreset("static", opts); + } + const runtimeMap = { deno: "deno", bun: "bun" } as Record; + return resolvePreset(runtimeMap[runtime] || "node", opts); } if (name && !preset) { diff --git a/src/presets/_static/preset.ts b/src/presets/_static/preset.ts index e3e039fd63..167912151e 100644 --- a/src/presets/_static/preset.ts +++ b/src/presets/_static/preset.ts @@ -1,5 +1,5 @@ import fsp from "node:fs/promises"; -import { defineNitroPreset } from "nitropack/kit"; +import { defineNitroPreset } from "../_utils/preset.ts"; import { join } from "pathe"; const _static = defineNitroPreset( @@ -19,7 +19,6 @@ const _static = defineNitroPreset( { name: "static" as const, static: true, - url: import.meta.url, } ); @@ -38,17 +37,13 @@ const githubPages = defineNitroPreset( }, hooks: { async compiled(nitro) { - await fsp.writeFile( - join(nitro.options.output.publicDir, ".nojekyll"), - "" - ); + await fsp.writeFile(join(nitro.options.output.publicDir, ".nojekyll"), ""); }, }, }, { name: "github-pages" as const, static: true, - url: import.meta.url, } ); @@ -66,7 +61,6 @@ const gitlabPages = defineNitroPreset( { name: "gitlab-pages" as const, static: true, - url: import.meta.url, } ); diff --git a/src/presets/_types.gen.ts b/src/presets/_types.gen.ts index d0909dcd8e..4ab069d368 100644 --- a/src/presets/_types.gen.ts +++ b/src/presets/_types.gen.ts @@ -1,25 +1,27 @@ // Auto-generated using gen-presets script -import type { PresetOptions as AwsAmplifyOptions } from "./aws-amplify/preset"; -import type { PresetOptions as AwsLambdaOptions } from "./aws-lambda/preset"; -import type { PresetOptions as AzureOptions } from "./azure/preset"; -import type { PresetOptions as CloudflareOptions } from "./cloudflare/preset"; -import type { PresetOptions as FirebaseOptions } from "./firebase/preset"; -import type { PresetOptions as NetlifyOptions } from "./netlify/preset"; -import type { PresetOptions as VercelOptions } from "./vercel/preset"; +import type { PresetOptions as AwsAmplifyOptions } from "./aws-amplify/preset.ts"; +import type { PresetOptions as AwsLambdaOptions } from "./aws-lambda/preset.ts"; +import type { PresetOptions as AzureOptions } from "./azure/preset.ts"; +import type { PresetOptions as CloudflareOptions } from "./cloudflare/preset.ts"; +import type { PresetOptions as FirebaseOptions } from "./firebase/preset.ts"; +import type { PresetOptions as NetlifyOptions } from "./netlify/preset.ts"; +import type { PresetOptions as VercelOptions } from "./vercel/preset.ts"; +import type { PresetOptions as ZephyrOptions } from "./zephyr/preset.ts"; export interface PresetOptions { - awsAmplify: AwsAmplifyOptions; - awsLambda: AwsLambdaOptions; - azure: AzureOptions; - cloudflare: CloudflareOptions; - firebase: FirebaseOptions; - netlify: NetlifyOptions; - vercel: VercelOptions; + awsAmplify?: AwsAmplifyOptions; + awsLambda?: AwsLambdaOptions; + azure?: AzureOptions; + cloudflare?: CloudflareOptions; + firebase?: FirebaseOptions; + netlify?: NetlifyOptions; + vercel?: VercelOptions; + zephyr?: ZephyrOptions; } -export const presetsWithConfig = ["awsAmplify","awsLambda","azure","cloudflare","firebase","netlify","vercel"] as const; +export const presetsWithConfig = ["awsAmplify","awsLambda","azure","cloudflare","firebase","netlify","vercel","zephyr"] as const; -export type PresetName = "alwaysdata" | "aws-amplify" | "aws-lambda" | "azure" | "azure-functions" | "azure-swa" | "base-worker" | "bun" | "cleavr" | "cli" | "cloudflare" | "cloudflare-durable" | "cloudflare-module" | "cloudflare-module-legacy" | "cloudflare-pages" | "cloudflare-pages-static" | "cloudflare-worker" | "deno" | "deno-deploy" | "deno-server" | "deno-server-legacy" | "digital-ocean" | "edgio" | "firebase" | "firebase-app-hosting" | "flight-control" | "genezio" | "github-pages" | "gitlab-pages" | "heroku" | "iis" | "iis-handler" | "iis-node" | "koyeb" | "layer0" | "netlify" | "netlify-builder" | "netlify-edge" | "netlify-legacy" | "netlify-static" | "nitro-dev" | "nitro-prerender" | "node" | "node-cluster" | "node-listener" | "node-server" | "platform-sh" | "render-com" | "service-worker" | "static" | "stormkit" | "vercel" | "vercel-edge" | "vercel-static" | "winterjs" | "zeabur" | "zeabur-static" | "zerops" | "zerops-static"; +export type PresetName = "alwaysdata" | "aws-amplify" | "aws-lambda" | "azure-swa" | "base-worker" | "bun" | "cleavr" | "cloudflare-dev" | "cloudflare-durable" | "cloudflare-module" | "cloudflare-pages" | "cloudflare-pages-static" | "deno" | "deno-deploy" | "deno-server" | "digital-ocean" | "firebase-app-hosting" | "flight-control" | "genezio" | "github-pages" | "gitlab-pages" | "heroku" | "iis-handler" | "iis-node" | "koyeb" | "netlify" | "netlify-edge" | "netlify-static" | "nitro-dev" | "nitro-prerender" | "node" | "node-cluster" | "node-middleware" | "node-server" | "platform-sh" | "render-com" | "standard" | "static" | "stormkit" | "vercel" | "vercel-static" | "winterjs" | "zeabur" | "zeabur-static" | "zephyr" | "zerops" | "zerops-static"; -export type PresetNameInput = "alwaysdata" | "aws-amplify" | "awsAmplify" | "aws_amplify" | "aws-lambda" | "awsLambda" | "aws_lambda" | "azure" | "azure-functions" | "azureFunctions" | "azure_functions" | "azure-swa" | "azureSwa" | "azure_swa" | "base-worker" | "baseWorker" | "base_worker" | "bun" | "cleavr" | "cli" | "cloudflare" | "cloudflare-durable" | "cloudflareDurable" | "cloudflare_durable" | "cloudflare-module" | "cloudflareModule" | "cloudflare_module" | "cloudflare-module-legacy" | "cloudflareModuleLegacy" | "cloudflare_module_legacy" | "cloudflare-pages" | "cloudflarePages" | "cloudflare_pages" | "cloudflare-pages-static" | "cloudflarePagesStatic" | "cloudflare_pages_static" | "cloudflare-worker" | "cloudflareWorker" | "cloudflare_worker" | "deno" | "deno-deploy" | "denoDeploy" | "deno_deploy" | "deno-server" | "denoServer" | "deno_server" | "deno-server-legacy" | "denoServerLegacy" | "deno_server_legacy" | "digital-ocean" | "digitalOcean" | "digital_ocean" | "edgio" | "firebase" | "firebase-app-hosting" | "firebaseAppHosting" | "firebase_app_hosting" | "flight-control" | "flightControl" | "flight_control" | "genezio" | "github-pages" | "githubPages" | "github_pages" | "gitlab-pages" | "gitlabPages" | "gitlab_pages" | "heroku" | "iis" | "iis-handler" | "iisHandler" | "iis_handler" | "iis-node" | "iisNode" | "iis_node" | "koyeb" | "layer0" | "netlify" | "netlify-builder" | "netlifyBuilder" | "netlify_builder" | "netlify-edge" | "netlifyEdge" | "netlify_edge" | "netlify-legacy" | "netlifyLegacy" | "netlify_legacy" | "netlify-static" | "netlifyStatic" | "netlify_static" | "nitro-dev" | "nitroDev" | "nitro_dev" | "nitro-prerender" | "nitroPrerender" | "nitro_prerender" | "node" | "node-cluster" | "nodeCluster" | "node_cluster" | "node-listener" | "nodeListener" | "node_listener" | "node-server" | "nodeServer" | "node_server" | "platform-sh" | "platformSh" | "platform_sh" | "render-com" | "renderCom" | "render_com" | "service-worker" | "serviceWorker" | "service_worker" | "static" | "stormkit" | "vercel" | "vercel-edge" | "vercelEdge" | "vercel_edge" | "vercel-static" | "vercelStatic" | "vercel_static" | "winterjs" | "zeabur" | "zeabur-static" | "zeaburStatic" | "zeabur_static" | "zerops" | "zerops-static" | "zeropsStatic" | "zerops_static" | (string & {}); +export type PresetNameInput = "alwaysdata" | "aws-amplify" | "awsAmplify" | "aws_amplify" | "aws-lambda" | "awsLambda" | "aws_lambda" | "azure-swa" | "azureSwa" | "azure_swa" | "base-worker" | "baseWorker" | "base_worker" | "bun" | "cleavr" | "cloudflare-dev" | "cloudflareDev" | "cloudflare_dev" | "cloudflare-durable" | "cloudflareDurable" | "cloudflare_durable" | "cloudflare-module" | "cloudflareModule" | "cloudflare_module" | "cloudflare-pages" | "cloudflarePages" | "cloudflare_pages" | "cloudflare-pages-static" | "cloudflarePagesStatic" | "cloudflare_pages_static" | "deno" | "deno-deploy" | "denoDeploy" | "deno_deploy" | "deno-server" | "denoServer" | "deno_server" | "digital-ocean" | "digitalOcean" | "digital_ocean" | "firebase-app-hosting" | "firebaseAppHosting" | "firebase_app_hosting" | "flight-control" | "flightControl" | "flight_control" | "genezio" | "github-pages" | "githubPages" | "github_pages" | "gitlab-pages" | "gitlabPages" | "gitlab_pages" | "heroku" | "iis-handler" | "iisHandler" | "iis_handler" | "iis-node" | "iisNode" | "iis_node" | "koyeb" | "netlify" | "netlify-edge" | "netlifyEdge" | "netlify_edge" | "netlify-static" | "netlifyStatic" | "netlify_static" | "nitro-dev" | "nitroDev" | "nitro_dev" | "nitro-prerender" | "nitroPrerender" | "nitro_prerender" | "node" | "node-cluster" | "nodeCluster" | "node_cluster" | "node-middleware" | "nodeMiddleware" | "node_middleware" | "node-server" | "nodeServer" | "node_server" | "platform-sh" | "platformSh" | "platform_sh" | "render-com" | "renderCom" | "render_com" | "standard" | "static" | "stormkit" | "vercel" | "vercel-static" | "vercelStatic" | "vercel_static" | "winterjs" | "zeabur" | "zeabur-static" | "zeaburStatic" | "zeabur_static" | "zephyr" | "zerops" | "zerops-static" | "zeropsStatic" | "zerops_static" | (string & {}); diff --git a/src/presets/_unenv/node-compat/cloudflare.ts b/src/presets/_unenv/node-compat/cloudflare.ts deleted file mode 100644 index c31f77910b..0000000000 --- a/src/presets/_unenv/node-compat/cloudflare.ts +++ /dev/null @@ -1,84 +0,0 @@ -// Auto generated using gen-node-compat.ts on 2025-03-08 -// Source: https://platform-node-compat.pi0.workers.dev/ -// Do not edit this file manually - -// prettier-ignore -export const builtnNodeModules = [ - "_stream_duplex", - "_stream_passthrough", - "_stream_readable", - "_stream_transform", - "_stream_writable", - "assert", // Missing exports: CallTracker, partialDeepStrictEqual - "assert/strict", // Missing exports: CallTracker, partialDeepStrictEqual - "async_hooks", - "buffer", - "diagnostics_channel", - "dns", - "dns/promises", - "events", // Missing exports: captureRejections, init - "net", - "path", - "path/posix", - "path/win32", - "querystring", - "stream", // Missing exports: duplexPair - "stream/consumers", - "stream/promises", - "stream/web", - "string_decoder", - "timers", - "timers/promises", - "url", - "util/types", - "zlib", -]; - -// prettier-ignore -export const hybridNodeModules = [ - "console", - "crypto", // Missing exports: Cipher, Cipheriv, Decipher, Decipheriv, ECDH, constants, createCipheriv, createDecipheriv, createECDH, getCipherInfo, hash, privateDecrypt, privateEncrypt, publicDecrypt, publicEncrypt - "module", // Missing exports: Module, SourceMap, constants, enableCompileCache, findPackageJSON, findSourceMap, flushCompileCache, getCompileCacheDir, getSourceMapsSupport, globalPaths, register, runMain, setSourceMapsSupport, stripTypeScriptTypes, syncBuiltinESMExports - "process", // Missing exports: abort, allowedNodeEnvironmentFlags, arch, argv, argv0, assert, availableMemory, binding, chdir, config, constrainedMemory, cpuUsage, cwd, debugPort, dlopen, domain, emitWarning, execArgv, execPath, exitCode, features, finalization, getActiveResourcesInfo, getegid, geteuid, getgid, getgroups, getuid, hasUncaughtExceptionCaptureCallback, hrtime, initgroups, kill, loadEnvFile, memoryUsage, moduleLoadList, openStdin, pid, ppid, reallyExit, ref, release, report, resourceUsage, setSourceMapsEnabled, setUncaughtExceptionCaptureCallback, setegid, seteuid, setgid, setgroups, setuid, sourceMapsEnabled, stderr, stdin, stdout, title, umask, unref, uptime, version, versions - "util", // Missing exports: isBoolean, isBuffer, isDate, isError, isFunction, isNull, isNullOrUndefined, isNumber, isObject, isPrimitive, isRegExp, isString, isSymbol, isUndefined -]; - -// prettier-ignore -export const unsupportedNodeModules = [ - "_http_agent", - "_http_client", - "_http_common", - "_http_incoming", - "_http_outgoing", - "_http_server", - "_stream_wrap", - "_tls_common", - "_tls_wrap", - "child_process", - "cluster", - "constants", - "dgram", - "domain", - "fs", - "fs/promises", - "http", - "http2", - "https", - "inspector", - "inspector/promises", - "os", - "perf_hooks", - "punycode", - "readline", - "readline/promises", - "repl", - "sys", - "tls", - "trace_events", - "tty", - "v8", - "vm", - "wasi", - "worker_threads", - "sqlite", -]; diff --git a/src/presets/_unenv/node-compat/deno.ts b/src/presets/_unenv/node-compat/deno.ts deleted file mode 100644 index db801e9f18..0000000000 --- a/src/presets/_unenv/node-compat/deno.ts +++ /dev/null @@ -1,85 +0,0 @@ -// Auto generated using gen-node-compat.ts on 2025-02-27 -// Source: https://platform-node-compat.deno.dev/ -// Do not edit this file manually - -// prettier-ignore -export const builtnNodeModules = [ - "_http_agent", - "_http_common", // Missing exports: freeParser, isLenient, parsers, prepareError - "_http_outgoing", - "_http_server", // Missing exports: Server, ServerResponse, httpServerPreClose, kConnectionsCheckingInterval, kServerResponse, setupConnectionsTracking, storeHTTPOptions - "_stream_duplex", - "_stream_passthrough", - "_stream_readable", - "_stream_transform", - "_stream_writable", - "_tls_common", // Missing exports: SecureContext, translatePeerCertificate - "_tls_wrap", - "assert", // Missing exports: CallTracker, partialDeepStrictEqual - "assert/strict", // Missing exports: CallTracker, partialDeepStrictEqual - "async_hooks", - "buffer", // Missing exports: File, resolveObjectURL - "child_process", - "cluster", - "console", // Missing exports: context, createTask - "constants", // Missing exports: EXTENSIONLESS_FORMAT_JAVASCRIPT, EXTENSIONLESS_FORMAT_WASM, O_DIRECT, O_NOATIME, defaultCipherList - "crypto", // Missing exports: Cipher, Decipher - "dgram", - "diagnostics_channel", // Missing exports: Channel - "dns", // Missing exports: getDefaultResultOrder, lookupService - "dns/promises", // Missing exports: getDefaultResultOrder, lookupService - "domain", - "events", // Missing exports: captureRejections, getMaxListeners, init, usingDomains - "fs", // Missing exports: FileReadStream, FileWriteStream, fchmod, fchmodSync, fchown, fchownSync, glob, globSync, lchmod, lchmodSync, lchown, lchownSync, openAsBlob - "fs/promises", // Missing exports: glob, lchmod, lchown, lutimes, statfs - "http", // Missing exports: CloseEvent, MessageEvent, WebSocket, setMaxIdleHTTPParsers - "http2", // Missing exports: performServerHandshake - "https", - "inspector", - "inspector/promises", - "module", // Missing exports: SourceMap, constants, enableCompileCache, findPackageJSON, flushCompileCache, getCompileCacheDir, getSourceMapsSupport, runMain, setSourceMapsSupport, stripTypeScriptTypes, syncBuiltinESMExports - "net", - "os", - "path", // Missing exports: matchesGlob - "path/posix", // Missing exports: matchesGlob - "path/win32", // Missing exports: matchesGlob - "perf_hooks", // Missing exports: Performance, PerformanceMark, PerformanceMeasure, PerformanceObserverEntryList, PerformanceResourceTiming, createHistogram - "process", // Missing exports: assert, availableMemory, binding, config, constrainedMemory, cpuUsage, debugPort, domain, exitCode, features, finalization, getActiveResourcesInfo, getgroups, hasUncaughtExceptionCaptureCallback, initgroups, loadEnvFile, moduleLoadList, openStdin, ppid, reallyExit, ref, release, report, resourceUsage, setSourceMapsEnabled, setUncaughtExceptionCaptureCallback, setegid, seteuid, setgid, setgroups, setuid, sourceMapsEnabled, title, unref, uptime - "punycode", - "querystring", - "readline", - "readline/promises", - "repl", // Missing exports: Recoverable, writer - "stream", // Missing exports: duplexPair, promises - "stream/consumers", - "stream/promises", - "stream/web", - "string_decoder", - "sys", // Missing exports: MIMEParams, MIMEType, getCallSite, getCallSites, getSystemErrorMap, getSystemErrorMessage, parseEnv, transferableAbortController, transferableAbortSignal - "timers", // Missing exports: active, enroll, unenroll - "timers/promises", - "tls", // Missing exports: SecureContext, convertALPNProtocols - "trace_events", - "tty", - "url", - "util", // Missing exports: MIMEParams, MIMEType, getCallSite, getCallSites, getSystemErrorMap, getSystemErrorMessage, parseEnv, transferableAbortController, transferableAbortSignal - "util/types", // Missing exports: isExternal - "v8", // Missing exports: GCProfiler, promiseHooks, queryObjects, setHeapSnapshotNearHeapLimit, startupSnapshot - "vm", - "wasi", - "worker_threads", // Missing exports: isInternalThread, isMarkedAsUntransferable, markAsUncloneable, postMessageToThread - "zlib", -]; - -// prettier-ignore -export const hybridNodeModules = [ - -]; - -// prettier-ignore -export const unsupportedNodeModules = [ - "_http_client", - "_http_incoming", - "_stream_wrap", - "sqlite", -]; diff --git a/src/presets/_unenv/node-compat/netlify.ts b/src/presets/_unenv/node-compat/netlify.ts deleted file mode 100644 index b295563efc..0000000000 --- a/src/presets/_unenv/node-compat/netlify.ts +++ /dev/null @@ -1,85 +0,0 @@ -// Auto generated using gen-node-compat.ts on 2025-02-27 -// Source: https://platform-node-compat.netlify.app/ -// Do not edit this file manually - -// prettier-ignore -export const builtnNodeModules = [ - "_http_agent", - "_http_common", // Missing exports: freeParser, isLenient, parsers, prepareError - "_http_outgoing", - "_http_server", // Missing exports: Server, ServerResponse, httpServerPreClose, kConnectionsCheckingInterval, kServerResponse, setupConnectionsTracking, storeHTTPOptions - "_stream_duplex", - "_stream_passthrough", - "_stream_readable", - "_stream_transform", - "_stream_writable", - "_tls_common", // Missing exports: SecureContext, translatePeerCertificate - "_tls_wrap", - "assert", // Missing exports: CallTracker, partialDeepStrictEqual - "assert/strict", // Missing exports: CallTracker, partialDeepStrictEqual - "async_hooks", - "buffer", // Missing exports: File, resolveObjectURL - "child_process", - "cluster", - "console", // Missing exports: context, createTask - "constants", // Missing exports: EXTENSIONLESS_FORMAT_JAVASCRIPT, EXTENSIONLESS_FORMAT_WASM, O_DIRECT, O_NOATIME, defaultCipherList - "crypto", // Missing exports: Cipher, Decipher - "dgram", - "diagnostics_channel", // Missing exports: Channel - "dns", // Missing exports: getDefaultResultOrder, lookupService - "dns/promises", // Missing exports: getDefaultResultOrder, lookupService - "domain", - "events", // Missing exports: captureRejections, getMaxListeners, init, usingDomains - "fs", // Missing exports: FileReadStream, FileWriteStream, fchmod, fchmodSync, fchown, fchownSync, glob, globSync, lchmod, lchmodSync, lchown, lchownSync, openAsBlob - "fs/promises", // Missing exports: glob, lchmod, lchown, lutimes, statfs - "http", // Missing exports: CloseEvent, MessageEvent, WebSocket, setMaxIdleHTTPParsers - "http2", // Missing exports: performServerHandshake - "https", - "inspector", - "inspector/promises", - "module", // Missing exports: SourceMap, constants, enableCompileCache, findPackageJSON, flushCompileCache, getCompileCacheDir, getSourceMapsSupport, runMain, setSourceMapsSupport, stripTypeScriptTypes, syncBuiltinESMExports - "net", - "os", - "path", // Missing exports: matchesGlob - "path/posix", // Missing exports: matchesGlob - "path/win32", // Missing exports: matchesGlob - "perf_hooks", // Missing exports: Performance, PerformanceMark, PerformanceMeasure, PerformanceObserverEntryList, PerformanceResourceTiming, createHistogram - "process", // Missing exports: assert, availableMemory, binding, config, constrainedMemory, cpuUsage, debugPort, domain, exitCode, features, finalization, getActiveResourcesInfo, getgroups, hasUncaughtExceptionCaptureCallback, initgroups, loadEnvFile, moduleLoadList, openStdin, ppid, reallyExit, ref, release, report, resourceUsage, setSourceMapsEnabled, setUncaughtExceptionCaptureCallback, setegid, seteuid, setgid, setgroups, setuid, sourceMapsEnabled, title, unref, uptime - "punycode", - "querystring", - "readline", - "readline/promises", - "repl", // Missing exports: Recoverable, writer - "stream", // Missing exports: duplexPair, promises - "stream/consumers", - "stream/promises", - "stream/web", - "string_decoder", - "sys", // Missing exports: MIMEParams, MIMEType, getCallSite, getCallSites, getSystemErrorMap, getSystemErrorMessage, parseEnv, transferableAbortController, transferableAbortSignal - "timers", // Missing exports: active, enroll, unenroll - "timers/promises", - "tls", // Missing exports: SecureContext, convertALPNProtocols - "trace_events", - "tty", - "url", - "util", // Missing exports: MIMEParams, MIMEType, getCallSite, getCallSites, getSystemErrorMap, getSystemErrorMessage, parseEnv, transferableAbortController, transferableAbortSignal - "util/types", // Missing exports: isExternal - "v8", // Missing exports: GCProfiler, promiseHooks, queryObjects, setHeapSnapshotNearHeapLimit, startupSnapshot - "vm", - "wasi", - "worker_threads", // Missing exports: isInternalThread, isMarkedAsUntransferable, markAsUncloneable, postMessageToThread - "zlib", -]; - -// prettier-ignore -export const hybridNodeModules = [ - -]; - -// prettier-ignore -export const unsupportedNodeModules = [ - "_http_client", - "_http_incoming", - "_stream_wrap", - "sqlite", -]; diff --git a/src/presets/_unenv/node-compat/vercel.ts b/src/presets/_unenv/node-compat/vercel.ts deleted file mode 100644 index 397404c6bd..0000000000 --- a/src/presets/_unenv/node-compat/vercel.ts +++ /dev/null @@ -1,85 +0,0 @@ -// Auto generated using gen-node-compat.ts on 2025-02-28 -// Source: https://platform-node-compat.vercel.app/ -// Do not edit this file manually - -// prettier-ignore -export const builtnNodeModules = [ - "assert", // Missing exports: CallTracker, partialDeepStrictEqual - "async_hooks", - "buffer", - "events", // Missing exports: captureRejections, init - "util", // Missing exports: isBoolean, isBuffer, isDate, isError, isFunction, isNull, isNullOrUndefined, isNumber, isObject, isPrimitive, isRegExp, isString, isSymbol, isUndefined -]; - -// prettier-ignore -export const hybridNodeModules = [ - -]; - -// prettier-ignore -export const unsupportedNodeModules = [ - "_http_agent", - "_http_client", - "_http_common", - "_http_incoming", - "_http_outgoing", - "_http_server", - "_stream_duplex", - "_stream_passthrough", - "_stream_readable", - "_stream_transform", - "_stream_wrap", - "_stream_writable", - "_tls_common", - "_tls_wrap", - "assert/strict", - "child_process", - "cluster", - "console", - "constants", - "crypto", - "dgram", - "diagnostics_channel", - "dns", - "dns/promises", - "domain", - "fs", - "fs/promises", - "http", - "http2", - "https", - "inspector", - "inspector/promises", - "module", - "net", - "os", - "path", - "path/posix", - "path/win32", - "perf_hooks", - "process", - "punycode", - "querystring", - "readline", - "readline/promises", - "repl", - "stream", - "stream/consumers", - "stream/promises", - "stream/web", - "string_decoder", - "sys", - "timers", - "timers/promises", - "tls", - "trace_events", - "tty", - "url", - "util/types", - "v8", - "vm", - "wasi", - "worker_threads", - "zlib", - "sqlite", -]; diff --git a/src/presets/_unenv/preset-deno.ts b/src/presets/_unenv/preset-deno.ts deleted file mode 100644 index 485c5a95c3..0000000000 --- a/src/presets/_unenv/preset-deno.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { Preset } from "unenv"; -import { builtnNodeModules } from "./node-compat/deno"; - -// https://platform-node-compat.deno.dev/ -// https://platform-node-compat.netlify.app/ - -export const unenvDenoPreset: Preset = { - meta: { - name: "nitro-deno", - url: import.meta.url, - }, - external: builtnNodeModules.map((m) => `node:${m}`), - alias: { - // (native) - ...Object.fromEntries( - [...builtnNodeModules, "sys"].flatMap((m) => [ - [m, `node:${m}`], - [`node:${m}`, `node:${m}`], - ]) - ), - }, - inject: { - performance: false, - }, -}; diff --git a/src/presets/_unenv/preset-workerd.ts b/src/presets/_unenv/preset-workerd.ts deleted file mode 100644 index cdd7ae5d75..0000000000 --- a/src/presets/_unenv/preset-workerd.ts +++ /dev/null @@ -1,69 +0,0 @@ -import type { Preset } from "unenv"; -import type { Plugin } from "rollup"; - -import { fileURLToPath } from "mlly"; -import { join } from "pathe"; - -import { builtnNodeModules, hybridNodeModules } from "./node-compat/cloudflare"; - -const workerdDir = fileURLToPath(new URL("workerd/", import.meta.url)); -const resolvePresetRuntime = (m: string) => join(workerdDir, `${m}.mjs`); - -export const unenvCfExternals: Preset = { - meta: { - name: "nitro-cloudflare:externals", - url: import.meta.url, - }, - external: [ - "cloudflare:email", - "cloudflare:sockets", - "cloudflare:workers", - "cloudflare:workflows", - ], -}; - -export const unenvWorkerdWithNodeCompat: Preset = { - meta: { - name: "nitro-cloudflare:node-compat", - url: import.meta.url, - }, - external: builtnNodeModules.map((m) => `node:${m}`), - alias: { - // (native) - ...Object.fromEntries( - builtnNodeModules.flatMap((m) => [ - [m, `node:${m}`], - [`node:${m}`, `node:${m}`], - ]) - ), - // (hybrid) - ...Object.fromEntries( - hybridNodeModules.flatMap((m) => { - const resolved = resolvePresetRuntime(m); - return [ - [`node:${m}`, resolved], - [m, resolved], - ]; - }) - ), - }, -}; - -export const workerdHybridNodeCompatPlugin: Plugin = { - name: "nitro:cloudflare:hybrid-node-compat", - resolveId(id) { - if (id.startsWith("cloudflare:")) { - return { id, external: true, moduleSideEffects: false }; - } - if (id.startsWith("#workerd/node:")) { - return { - id: id.slice("#workerd/".length), - external: true, - moduleSideEffects: false, - }; - } - if (id.startsWith(workerdDir)) { - return { id, moduleSideEffects: false }; - } - }, -}; diff --git a/src/presets/_unenv/workerd/console.mjs b/src/presets/_unenv/workerd/console.mjs deleted file mode 100644 index 6cfe4d8506..0000000000 --- a/src/presets/_unenv/workerd/console.mjs +++ /dev/null @@ -1,69 +0,0 @@ -import workerdConsole from "#workerd/node:console"; - -import { - Console, - _ignoreErrors, - _stderr, - _stderrErrorHandler, - _stdout, - _stdoutErrorHandler, - _times, -} from "unenv/node/console"; - -export { - Console, - _ignoreErrors, - _stderr, - _stderrErrorHandler, - _stdout, - _stdoutErrorHandler, - _times, -} from "unenv/node/console"; - -export const { - assert, - clear, - context, - count, - countReset, - createTask, - debug, - dir, - dirxml, - error, - group, - groupCollapsed, - groupEnd, - info, - log, - profile, - profileEnd, - table, - time, - timeEnd, - timeLog, - timeStamp, - trace, - warn, -} = workerdConsole; - -const consolePolyfill = { - Console, - _ignoreErrors, - _stderr, - _stderrErrorHandler, - _stdout, - _stdoutErrorHandler, - _times, -}; - -const consoleModule = /*@__PURE__*/ new Proxy(workerdConsole, { - get(target, prop) { - if (Reflect.has(target, prop)) { - return Reflect.get(target, prop); - } - return Reflect.get(consolePolyfill, prop); - }, -}); - -export default consoleModule; diff --git a/src/presets/_unenv/workerd/crypto.mjs b/src/presets/_unenv/workerd/crypto.mjs deleted file mode 100644 index 9b91711fbf..0000000000 --- a/src/presets/_unenv/workerd/crypto.mjs +++ /dev/null @@ -1,183 +0,0 @@ -// https://github.com/cloudflare/workerd/blob/main/src/node/crypto.ts - -import workerdCrypto from "#workerd/node:crypto"; - -import { - Cipher, - Cipheriv, - constants, - createCipher, - createCipheriv, - createDecipher, - createDecipheriv, - createECDH, - Decipher, - Decipheriv, - diffieHellman, - ECDH, - getCipherInfo, - hash, - privateDecrypt, - privateEncrypt, - pseudoRandomBytes, - publicDecrypt, - publicEncrypt, - webcrypto as unenvCryptoWebcrypto, -} from "unenv/node/crypto"; - -export { - Cipher, - Cipheriv, - Decipher, - Decipheriv, - ECDH, - constants, - createCipheriv, - createDecipheriv, - createECDH, - diffieHellman, - getCipherInfo, - hash, - privateDecrypt, - privateEncrypt, - publicDecrypt, - publicEncrypt, -} from "unenv/node/crypto"; - -export const { - Certificate, - DiffieHellman, - DiffieHellmanGroup, - Hash, - Hmac, - KeyObject, - X509Certificate, - checkPrime, - checkPrimeSync, - createDiffieHellman, - createDiffieHellmanGroup, - createHash, - createHmac, - createPrivateKey, - createPublicKey, - createSecretKey, - generateKey, - generateKeyPair, - generateKeyPairSync, - generateKeySync, - generatePrime, - generatePrimeSync, - getCiphers, - getCurves, - getDiffieHellman, - getFips, - getHashes, - hkdf, - hkdfSync, - pbkdf2, - pbkdf2Sync, - randomBytes, - randomFill, - randomFillSync, - randomInt, - randomUUID, - scrypt, - scryptSync, - secureHeapUsed, - setEngine, - setFips, - subtle, - timingSafeEqual, - fips, - Sign, - Verify, - createSign, - createVerify, - sign, - verify, -} = workerdCrypto; - -export const getRandomValues = workerdCrypto.getRandomValues.bind( - workerdCrypto.webcrypto -); - -export const webcrypto = { - CryptoKey: unenvCryptoWebcrypto.CryptoKey, - getRandomValues, - randomUUID, - subtle, -}; - -export default { - Certificate, - Cipher, - Cipheriv, - Decipher, - Decipheriv, - ECDH, - Sign, - Verify, - X509Certificate, - constants, - createCipheriv, - createDecipheriv, - createECDH, - createSign, - createVerify, - diffieHellman, - getCipherInfo, - hash, - privateDecrypt, - privateEncrypt, - publicDecrypt, - publicEncrypt, - scrypt, - scryptSync, - sign, - verify, - createCipher, - createDecipher, - pseudoRandomBytes, - DiffieHellman, - DiffieHellmanGroup, - Hash, - Hmac, - KeyObject, - checkPrime, - checkPrimeSync, - createDiffieHellman, - createDiffieHellmanGroup, - createHash, - createHmac, - createPrivateKey, - createPublicKey, - createSecretKey, - generateKey, - generateKeyPair, - generateKeyPairSync, - generateKeySync, - generatePrime, - generatePrimeSync, - getCiphers, - getCurves, - getDiffieHellman, - getFips, - getHashes, - getRandomValues, - hkdf, - hkdfSync, - pbkdf2, - pbkdf2Sync, - randomBytes, - randomFill, - randomFillSync, - randomInt, - randomUUID, - secureHeapUsed, - setEngine, - setFips, - subtle, - timingSafeEqual, - fips, - webcrypto, -}; diff --git a/src/presets/_unenv/workerd/module.mjs b/src/presets/_unenv/workerd/module.mjs deleted file mode 100644 index cb5459bacb..0000000000 --- a/src/presets/_unenv/workerd/module.mjs +++ /dev/null @@ -1,109 +0,0 @@ -// https://github.com/cloudflare/workerd/blob/main/src/node/module.ts - -import workerdModule from "#workerd/node:module"; - -import { notImplemented } from "unenv/_internal/utils"; - -import { - constants, - enableCompileCache, - findSourceMap, - getCompileCacheDir, - globalPaths, - Module, - register, - runMain, - SourceMap, - syncBuiltinESMExports, - wrap, - flushCompileCache, - stripTypeScriptTypes, - wrapper, - _readPackage, - _stat, - _cache, - _debug, - _extensions, - _findPath, - _initPaths, - _load, - _nodeModulePaths, - _pathCache, - _preloadModules, - _resolveFilename, - _resolveLookupPaths, -} from "unenv/node/module"; - -export { - Module, - SourceMap, - constants, - enableCompileCache, - findSourceMap, - getCompileCacheDir, - globalPaths, - register, - runMain, - syncBuiltinESMExports, - wrap, - flushCompileCache, - stripTypeScriptTypes, - wrapper, - _cache, - _extensions, - _debug, - _pathCache, - _findPath, - _initPaths, - _load, - _nodeModulePaths, - _preloadModules, - _resolveFilename, - _resolveLookupPaths, - _readPackage, - _stat, -} from "unenv/node/module"; - -export const { builtinModules, isBuiltin } = workerdModule; - -export const createRequire = (file) => { - return Object.assign(workerdModule.createRequire(file), { - resolve: Object.assign(notImplemented("module.require.resolve"), { - paths: notImplemented("module.require.resolve.paths"), - }), - cache: Object.create(null), - extensions: _extensions, - main: undefined, - }); -}; - -export default { - Module, - SourceMap, - builtinModules, - enableCompileCache, - constants, - createRequire, - findSourceMap, - getCompileCacheDir, - globalPaths, - isBuiltin, - register, - runMain, - syncBuiltinESMExports, - wrap, - flushCompileCache, - stripTypeScriptTypes, - wrapper, - _cache, - _extensions, - _debug, - _pathCache, - _findPath, - _initPaths, - _load, - _nodeModulePaths, - _preloadModules, - _resolveFilename, - _resolveLookupPaths, -}; diff --git a/src/presets/_unenv/workerd/process.mjs b/src/presets/_unenv/workerd/process.mjs deleted file mode 100644 index 162b3eb778..0000000000 --- a/src/presets/_unenv/workerd/process.mjs +++ /dev/null @@ -1,131 +0,0 @@ -// https://github.com/cloudflare/workerd/blob/main/src/node/internal/process.ts -// https://github.com/unjs/unenv/blob/main/src/runtime/node/process.ts - -import workerdProcess from "#workerd/node:process"; - -import { Process as UnenvProcess } from "unenv/node/internal/process/process"; -import { env as UnenvEnv } from "unenv/node/internal/process/env"; -import { hrtime as UnenvHrTime } from "unenv/node/internal/process/hrtime"; - -const mixedProcess = new UnenvProcess({ - env: UnenvEnv, - hrtime: UnenvHrTime, - nextTick: workerdProcess.nextTick, -}); - -// https://github.com/cloudflare/workerd/blob/main/src/node/internal/process.ts#L94 -for (const key of ["exit", "getBuiltinModule", "platform"]) { - if (key in workerdProcess) { - mixedProcess[key] = workerdProcess[key]; - } -} - -export default mixedProcess; - -export const { - abort, - addListener, - allowedNodeEnvironmentFlags, - hasUncaughtExceptionCaptureCallback, - setUncaughtExceptionCaptureCallback, - loadEnvFile, - sourceMapsEnabled, - arch, - argv, - argv0, - chdir, - config, - connected, - constrainedMemory, - availableMemory, - cpuUsage, - cwd, - debugPort, - dlopen, - disconnect, - emit, - emitWarning, - env, - eventNames, - execArgv, - execPath, - exit, - finalization, - features, - getBuiltinModule, - getActiveResourcesInfo, - getMaxListeners, - hrtime, - kill, - listeners, - listenerCount, - memoryUsage, - nextTick, - on, - off, - once, - pid, - platform, - ppid, - prependListener, - prependOnceListener, - rawListeners, - release, - removeAllListeners, - removeListener, - report, - resourceUsage, - setMaxListeners, - setSourceMapsEnabled, - stderr, - stdin, - stdout, - title, - umask, - uptime, - version, - versions, - domain, - initgroups, - moduleLoadList, - reallyExit, - openStdin, - assert, - binding, - send, - exitCode, - channel, - getegid, - geteuid, - getgid, - getgroups, - getuid, - setegid, - seteuid, - setgid, - setgroups, - setuid, - permission, - mainModule, - _events, - _eventsCount, - _exiting, - _maxListeners, - _debugEnd, - _debugProcess, - _fatalException, - _getActiveHandles, - _getActiveRequests, - _kill, - _preload_modules, - _rawDebug, - _startProfilerIdleNotifier, - _stopProfilerIdleNotifier, - _tickCallback, - _disconnect, - _handleQueue, - _pendingMessage, - _channel, - _send, - _linkedBinding, -} = mixedProcess; diff --git a/src/presets/_unenv/workerd/util.mjs b/src/presets/_unenv/workerd/util.mjs deleted file mode 100644 index 828afe7da5..0000000000 --- a/src/presets/_unenv/workerd/util.mjs +++ /dev/null @@ -1,126 +0,0 @@ -// https://github.com/cloudflare/workerd/blob/main/src/node/util.ts - -import workerdUtil from "#workerd/node:util"; - -import { - _errnoException, - _exceptionWithHostPort, - getSystemErrorMap, - getSystemErrorName, - isBoolean, - isBuffer, - isDate, - isError, - isFunction, - isNull, - isNullOrUndefined, - isNumber, - isObject, - isPrimitive, - isRegExp, - isString, - isSymbol, - isUndefined, - parseEnv, - styleText, -} from "unenv/node/util"; - -export { - _errnoException, - _exceptionWithHostPort, - getSystemErrorMap, - getSystemErrorName, - isBoolean, - isBuffer, - isDate, - isError, - isFunction, - isNull, - isNullOrUndefined, - isNumber, - isObject, - isPrimitive, - isRegExp, - isString, - isSymbol, - isUndefined, - parseEnv, - styleText, -} from "unenv/node/util"; - -export const { - MIMEParams, - MIMEType, - TextDecoder, - TextEncoder, - _extend, - aborted, - callbackify, - debug, - debuglog, - deprecate, - format, - formatWithOptions, - getCallSite, - inherits, - inspect, - log, - parseArgs, - promisify, - stripVTControlCharacters, - toUSVString, - transferableAbortController, - transferableAbortSignal, - isArray, - isDeepStrictEqual, -} = workerdUtil; - -export const types = workerdUtil.types; - -export default { - _errnoException, - _exceptionWithHostPort, - getSystemErrorMap, - getSystemErrorName, - isArray, - isBoolean, - isBuffer, - isDate, - isDeepStrictEqual, - isError, - isFunction, - isNull, - isNullOrUndefined, - isNumber, - isObject, - isPrimitive, - isRegExp, - isString, - isSymbol, - isUndefined, - parseEnv, - styleText, - MIMEParams, - MIMEType, - TextDecoder, - TextEncoder, - _extend, - aborted, - callbackify, - debug, - debuglog, - deprecate, - format, - formatWithOptions, - getCallSite, - inherits, - inspect, - log, - parseArgs, - promisify, - stripVTControlCharacters, - toUSVString, - transferableAbortController, - transferableAbortSignal, - types, -}; diff --git a/src/presets/_utils/fs.ts b/src/presets/_utils/fs.ts new file mode 100644 index 0000000000..a1bc8c8db9 --- /dev/null +++ b/src/presets/_utils/fs.ts @@ -0,0 +1,25 @@ +import fsp from "node:fs/promises"; +import { relative, dirname } from "pathe"; +import consola from "consola"; +import { colors } from "consola/utils"; + +export function prettyPath(p: string, highlight = true) { + p = relative(process.cwd(), p); + return highlight ? colors.cyan(p) : p; +} + +export async function writeFile(file: string, contents: Buffer | string, log = false) { + await fsp.mkdir(dirname(file), { recursive: true }); + await fsp.writeFile(file, contents, typeof contents === "string" ? "utf8" : undefined); + if (log) { + consola.info("Generated", prettyPath(file)); + } +} + +export async function isDirectory(path: string) { + try { + return (await fsp.stat(path)).isDirectory(); + } catch { + return false; + } +} diff --git a/src/presets/_utils/preset.ts b/src/presets/_utils/preset.ts new file mode 100644 index 0000000000..f79babaaca --- /dev/null +++ b/src/presets/_utils/preset.ts @@ -0,0 +1,14 @@ +import type { NitroPreset, NitroPresetMeta } from "nitro/types"; + +import { presetsDir } from "nitro/meta"; +import { resolve } from "node:path"; + +export function defineNitroPreset

( + preset: P, + meta?: M +): P & { _meta: NitroPresetMeta } { + if (typeof preset !== "function" && preset.entry && preset.entry.startsWith(".")) { + preset.entry = resolve(presetsDir, preset.entry); + } + return { ...preset, _meta: meta } as P & { _meta: M }; +} diff --git a/src/presets/alwaysdata/preset.ts b/src/presets/alwaysdata/preset.ts index d12a47f5ce..417135e2aa 100644 --- a/src/presets/alwaysdata/preset.ts +++ b/src/presets/alwaysdata/preset.ts @@ -1,16 +1,15 @@ -import { defineNitroPreset } from "nitropack/kit"; +import { defineNitroPreset } from "../_utils/preset.ts"; const alwaysdata = defineNitroPreset( { extends: "node-server", + serveStatic: true, commands: { - deploy: - "rsync -rRt --info=progress2 ./ [account]@ssh-[account].alwaysdata.net:www/my-app", + deploy: "rsync -rRt --info=progress2 ./ [account]@ssh-[account].alwaysdata.net:www/my-app", }, }, { name: "alwaysdata" as const, - url: import.meta.url, } ); diff --git a/src/presets/aws-amplify/preset.ts b/src/presets/aws-amplify/preset.ts index d2fc4a0bf7..7e76cd4309 100644 --- a/src/presets/aws-amplify/preset.ts +++ b/src/presets/aws-amplify/preset.ts @@ -1,12 +1,16 @@ -import { defineNitroPreset } from "nitropack/kit"; -import { writeAmplifyFiles } from "./utils"; +import { defineNitroPreset } from "../_utils/preset.ts"; +import { writeAmplifyFiles } from "./utils.ts"; -export type { AWSAmplifyOptions as PresetOptions } from "./types"; +export type { AWSAmplifyOptions as PresetOptions } from "./types.ts"; const awsAmplify = defineNitroPreset( { - extends: "node-server", - entry: "./runtime/aws-amplify", + entry: "./aws-amplify/runtime/aws-amplify", + manifest: { + // https://docs.aws.amazon.com/amplify/latest/userguide/environment-variables.html#amplify-console-environment-variables + deploymentId: process.env.AWS_JOB_ID, + }, + serveStatic: true, output: { dir: "{{ rootDir }}/.amplify-hosting", serverDir: "{{ output.dir }}/compute/default", @@ -24,7 +28,6 @@ const awsAmplify = defineNitroPreset( { name: "aws-amplify" as const, stdName: "aws_amplify", - url: import.meta.url, } ); diff --git a/src/presets/aws-amplify/runtime/aws-amplify.ts b/src/presets/aws-amplify/runtime/aws-amplify.ts index 3b28a1cfad..673fb81d68 100644 --- a/src/presets/aws-amplify/runtime/aws-amplify.ts +++ b/src/presets/aws-amplify/runtime/aws-amplify.ts @@ -1,12 +1,13 @@ -import "#nitro-internal-pollyfills"; -import { useNitroApp } from "nitropack/runtime"; +import "#nitro/virtual/polyfills"; +import { useNitroApp } from "nitro/app"; import { Server } from "node:http"; -import { toNodeListener } from "h3"; +import type { NodeHttp1Handler } from "srvx"; +import { toNodeHandler } from "srvx/node"; const nitroApp = useNitroApp(); -const server = new Server(toNodeListener(nitroApp.h3App)); +const server = new Server(toNodeHandler(nitroApp.fetch) as NodeHttp1Handler); // @ts-ignore server.listen(3000, (err) => { diff --git a/src/presets/aws-amplify/types.ts b/src/presets/aws-amplify/types.ts index b2934c800b..4a67e5519e 100644 --- a/src/presets/aws-amplify/types.ts +++ b/src/presets/aws-amplify/types.ts @@ -8,7 +8,7 @@ export interface AmplifyComputeConfig { * The runtime property dictates the runtime of the provisioned compute resource. * Values are subset of https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html */ - runtime: "nodejs16.x" | "nodejs18.x"; + runtime: "nodejs20.x" | "nodejs22.x"; /** * Specifies the starting file from which code will run for the given compute resource. @@ -85,13 +85,7 @@ export type AmplifyImageSettings = { }[]; /** Array of allowed output image formats. */ - formats: ( - | "image/avif" - | "image/webp" - | "image/gif" - | "image/png" - | "image/jpeg" - )[]; + formats: ("image/avif" | "image/webp" | "image/gif" | "image/png" | "image/jpeg")[]; /** Cache duration (in seconds) for the optimized images. */ minimumCacheTTL: number; @@ -158,4 +152,5 @@ export interface AWSAmplifyOptions { cacheControl?: string; }; imageSettings?: AmplifyImageSettings; + runtime?: "nodejs20.x" | "nodejs22.x"; } diff --git a/src/presets/aws-amplify/utils.ts b/src/presets/aws-amplify/utils.ts index 02430f56ed..b6c70742b6 100644 --- a/src/presets/aws-amplify/utils.ts +++ b/src/presets/aws-amplify/utils.ts @@ -1,12 +1,8 @@ import { writeFile } from "node:fs/promises"; import { resolve } from "node:path"; -import type { Nitro } from "nitropack/types"; +import type { Nitro } from "nitro/types"; import { joinURL } from "ufo"; -import type { - AmplifyDeployManifest, - AmplifyRoute, - AmplifyRouteTarget, -} from "./types"; +import type { AmplifyDeployManifest, AmplifyRoute, AmplifyRouteTarget } from "./types.ts"; export async function writeAmplifyFiles(nitro: Nitro) { const outDir = nitro.options.output.dir; @@ -17,8 +13,7 @@ export async function writeAmplifyFiles(nitro: Nitro) { let hasWildcardPublicAsset = false; if (nitro.options.awsAmplify?.imageOptimization && !nitro.options.static) { - const { path, cacheControl } = - nitro.options.awsAmplify?.imageOptimization || {}; + const { path, cacheControl } = nitro.options.awsAmplify?.imageOptimization || {}; if (path) { routes.push({ path, @@ -44,9 +39,7 @@ export async function writeAmplifyFiles(nitro: Nitro) { target: { kind: "Static", cacheControl: - publicAsset.maxAge > 0 - ? `public, max-age=${publicAsset.maxAge}, immutable` - : undefined, + publicAsset.maxAge > 0 ? `public, max-age=${publicAsset.maxAge}, immutable` : undefined, }, fallback: publicAsset.fallthrough ? computeTarget : undefined, }); @@ -89,7 +82,7 @@ export async function writeAmplifyFiles(nitro: Nitro) { { name: "default", entrypoint: "server.js", - runtime: "nodejs18.x", + runtime: nitro.options.awsAmplify?.runtime || "nodejs20.x", }, ], framework: { @@ -97,16 +90,10 @@ export async function writeAmplifyFiles(nitro: Nitro) { version: nitro.options.framework.version || "0.0.0", }, }; - await writeFile( - resolve(outDir, "deploy-manifest.json"), - JSON.stringify(deployManifest, null, 2) - ); + await writeFile(resolve(outDir, "deploy-manifest.json"), JSON.stringify(deployManifest, null, 2)); // Write server.js (CJS) if (!nitro.options.static) { - await writeFile( - resolve(outDir, "compute/default/server.js"), - `import("./index.mjs")` - ); + await writeFile(resolve(outDir, "compute/default/server.js"), `import("./index.mjs")`); } } diff --git a/src/presets/aws-lambda/preset.ts b/src/presets/aws-lambda/preset.ts index 14be332239..10fc5ec06e 100644 --- a/src/presets/aws-lambda/preset.ts +++ b/src/presets/aws-lambda/preset.ts @@ -1,15 +1,16 @@ -import { defineNitroPreset } from "nitropack/kit"; -export type { AwsLambdaOptions as PresetOptions } from "./types"; +import { defineNitroPreset } from "../_utils/preset.ts"; + +export type { AwsLambdaOptions as PresetOptions } from "./types.ts"; const awsLambda = defineNitroPreset( { - entry: "./runtime/aws-lambda", + entry: "./aws-lambda/runtime/aws-lambda", awsLambda: { streaming: false, }, hooks: { "rollup:before": (nitro, rollupConfig) => { - if (nitro.options.awsLambda.streaming) { + if (nitro.options.awsLambda?.streaming) { (rollupConfig.input as string) += "-streaming"; } }, @@ -17,7 +18,6 @@ const awsLambda = defineNitroPreset( }, { name: "aws-lambda" as const, - url: import.meta.url, } ); diff --git a/src/presets/aws-lambda/runtime/_utils.ts b/src/presets/aws-lambda/runtime/_utils.ts new file mode 100644 index 0000000000..a5efd6cdbf --- /dev/null +++ b/src/presets/aws-lambda/runtime/_utils.ts @@ -0,0 +1,146 @@ +import type { APIGatewayProxyEvent, APIGatewayProxyEventV2 } from "aws-lambda"; +import type { ServerRequest } from "srvx"; +import { stringifyQuery } from "ufo"; + +// Incoming (AWS => Web) + +export function awsRequest( + event: APIGatewayProxyEvent | APIGatewayProxyEventV2, + context: unknown +): ServerRequest { + const method = awsEventMethod(event); + const url = awsEventURL(event); + const headers = awsEventHeaders(event); + const body = awsEventBody(event); + + const req = new Request(url, { method, headers, body }) as ServerRequest; + + // srvx compatibility + req.runtime ??= { name: "aws-lambda" }; + // @ts-expect-error (add to srvx types) + req.runtime.aws ??= { event, context } as any; + + return new Request(url, { method, headers, body }); +} + +function awsEventMethod(event: APIGatewayProxyEvent | APIGatewayProxyEventV2): string { + return ( + (event as APIGatewayProxyEvent).httpMethod || + (event as APIGatewayProxyEventV2).requestContext?.http?.method || + "GET" + ); +} + +function awsEventURL(event: APIGatewayProxyEvent | APIGatewayProxyEventV2): URL { + const hostname = + event.headers.host || event.headers.Host || event.requestContext?.domainName || "."; + + const path = (event as APIGatewayProxyEvent).path || (event as APIGatewayProxyEventV2).rawPath; + + const query = awsEventQuery(event); + + const protocol = + (event.headers["X-Forwarded-Proto"] || event.headers["x-forwarded-proto"]) === "http" + ? "http" + : "https"; + + return new URL(`${path}${query ? `?${query}` : ""}`, `${protocol}://${hostname}`); +} + +function awsEventQuery(event: APIGatewayProxyEvent | APIGatewayProxyEventV2) { + if (typeof (event as APIGatewayProxyEventV2).rawQueryString === "string") { + return (event as APIGatewayProxyEventV2).rawQueryString; + } + const queryObj = { + ...event.queryStringParameters, + ...(event as APIGatewayProxyEvent).multiValueQueryStringParameters, + }; + return stringifyQuery(queryObj); +} + +function awsEventHeaders(event: APIGatewayProxyEvent | APIGatewayProxyEventV2): Headers { + const headers = new Headers(); + for (const [key, value] of Object.entries(event.headers)) { + if (value) { + headers.set(key, value); + } + } + if ("cookies" in event && event.cookies) { + for (const cookie of event.cookies) { + headers.append("cookie", cookie); + } + } + return headers; +} + +function awsEventBody(event: APIGatewayProxyEvent | APIGatewayProxyEventV2): BodyInit | undefined { + if (!event.body) { + return undefined; + } + if (event.isBase64Encoded) { + return Buffer.from(event.body || "", "base64"); + } + return event.body; +} + +// Outgoing (Web => AWS) + +export function awsResponseHeaders(response: Response) { + const headers: Record = Object.create(null); + for (const [key, value] of response.headers) { + if (value) { + headers[key] = Array.isArray(value) ? value.join(",") : String(value); + } + } + + const cookies = response.headers.getSetCookie(); + + return cookies.length > 0 + ? { + headers, + cookies, // ApiGateway v2 + multiValueHeaders: { "set-cookie": cookies }, // ApiGateway v1 + } + : { headers }; +} + +// AWS Lambda proxy integrations requires base64 encoded buffers +// binaryMediaTypes should be */* +// see https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-payload-encodings.html +export async function awsResponseBody( + response: Response +): Promise<{ body: string; isBase64Encoded?: boolean }> { + if (!response.body) { + return { body: "" }; + } + const buffer = await toBuffer(response.body as any); + const contentType = response.headers.get("content-type") || ""; + return isTextType(contentType) + ? { body: buffer.toString("utf8") } + : { body: buffer.toString("base64"), isBase64Encoded: true }; +} + +function isTextType(contentType = "") { + return /^text\/|\/(javascript|json|xml)|utf-?8/i.test(contentType); +} + +function toBuffer(data: ReadableStream): Promise { + return new Promise((resolve, reject) => { + const chunks: Buffer[] = []; + data + .pipeTo( + new WritableStream({ + write(chunk) { + chunks.push(chunk); + }, + close() { + resolve(Buffer.concat(chunks)); + }, + abort(reason) { + reject(reason); + }, + }) + ) + .catch(reject); + }); +} diff --git a/src/presets/aws-lambda/runtime/aws-lambda-streaming.ts b/src/presets/aws-lambda/runtime/aws-lambda-streaming.ts index 1efaf50a22..bfba0e93f4 100644 --- a/src/presets/aws-lambda/runtime/aws-lambda-streaming.ts +++ b/src/presets/aws-lambda/runtime/aws-lambda-streaming.ts @@ -1,66 +1,42 @@ +import "#nitro/virtual/polyfills"; +import { useNitroApp } from "nitro/app"; +import { awsRequest, awsResponseHeaders } from "./_utils.ts"; + +import type { StreamingResponse } from "@netlify/functions"; import type { Readable } from "node:stream"; -import type { - APIGatewayProxyEventV2, - APIGatewayProxyStructuredResultV2, - Context, -} from "aws-lambda"; -import "#nitro-internal-pollyfills"; -import { useNitroApp } from "nitropack/runtime"; -import { - normalizeLambdaIncomingHeaders, - normalizeLambdaOutgoingHeaders, -} from "nitropack/runtime/internal"; -import { withQuery } from "ufo"; +import type { APIGatewayProxyEventV2 } from "aws-lambda"; const nitroApp = useNitroApp(); export const handler = awslambda.streamifyResponse( async (event: APIGatewayProxyEventV2, responseStream, context) => { - const query = { - ...event.queryStringParameters, - }; - const url = withQuery(event.rawPath, query); - const method = event.requestContext?.http?.method || "get"; + const request = awsRequest(event, context); - if ("cookies" in event && event.cookies) { - event.headers.cookie = event.cookies.join(";"); - } + const response = await nitroApp.fetch(request); - const r = await nitroApp.localCall({ - event, - url, - context, - headers: normalizeLambdaIncomingHeaders(event.headers) as Record< - string, - string | string[] - >, - method, - query, - body: event.isBase64Encoded - ? Buffer.from(event.body || "", "base64").toString("utf8") - : event.body, - }); - const httpResponseMetadata = { - statusCode: r.status, - headers: { - ...normalizeLambdaOutgoingHeaders(r.headers, true), - "Transfer-Encoding": "chunked", - }, + const httpResponseMetadata: Omit = { + statusCode: response.status, + ...awsResponseHeaders(response), }; - if (r.body) { - const writer = awslambda.HttpResponseStream.from( - responseStream, - httpResponseMetadata - ); - if (!(r.body as ReadableStream).getReader) { - writer.write(r.body as any /* TODO */); - writer.end(); - return; - } - const reader = (r.body as ReadableStream).getReader(); - await streamToNodeStream(reader, responseStream); - writer.end(); + + if (!httpResponseMetadata.headers!["transfer-encoding"]) { + httpResponseMetadata.headers!["transfer-encoding"] = "chunked"; } + + const body = + response.body ?? + new ReadableStream({ + start(controller) { + controller.enqueue(""); + controller.close(); + }, + }); + + const writer = awslambda.HttpResponseStream.from(responseStream, httpResponseMetadata); + + const reader = body.getReader(); + await streamToNodeStream(reader, responseStream); + writer.end(); } ); @@ -75,28 +51,3 @@ async function streamToNodeStream( } writer.end(); } - -declare global { - // eslint-disable-next-line @typescript-eslint/no-namespace - namespace awslambda { - // https://docs.aws.amazon.com/lambda/latest/dg/configuration-response-streaming.html - function streamifyResponse( - handler: ( - event: APIGatewayProxyEventV2, - responseStream: NodeJS.WritableStream, - context: Context - ) => Promise - ): any; - - // eslint-disable-next-line @typescript-eslint/no-namespace - namespace HttpResponseStream { - function from( - stream: NodeJS.WritableStream, - metadata: { - statusCode: APIGatewayProxyStructuredResultV2["statusCode"]; - headers: APIGatewayProxyStructuredResultV2["headers"]; - } - ): NodeJS.WritableStream; - } - } -} diff --git a/src/presets/aws-lambda/runtime/aws-lambda.ts b/src/presets/aws-lambda/runtime/aws-lambda.ts index d9d3372515..cfe419c2ca 100644 --- a/src/presets/aws-lambda/runtime/aws-lambda.ts +++ b/src/presets/aws-lambda/runtime/aws-lambda.ts @@ -1,3 +1,7 @@ +import "#nitro/virtual/polyfills"; +import { useNitroApp } from "nitro/app"; +import { awsRequest, awsResponseHeaders, awsResponseBody } from "./_utils.ts"; + import type { APIGatewayProxyEvent, APIGatewayProxyEventV2, @@ -5,76 +9,20 @@ import type { APIGatewayProxyResultV2, Context, } from "aws-lambda"; -import "#nitro-internal-pollyfills"; -import { useNitroApp } from "nitropack/runtime"; -import { - normalizeCookieHeader, - normalizeLambdaIncomingHeaders, - normalizeLambdaOutgoingBody, - normalizeLambdaOutgoingHeaders, -} from "nitropack/runtime/internal"; -import { withQuery } from "ufo"; const nitroApp = useNitroApp(); -export async function handler( - event: APIGatewayProxyEvent, - context: Context -): Promise; -export async function handler( - event: APIGatewayProxyEventV2, - context: Context -): Promise; export async function handler( event: APIGatewayProxyEvent | APIGatewayProxyEventV2, context: Context ): Promise { - const query = { - ...event.queryStringParameters, - ...(event as APIGatewayProxyEvent).multiValueQueryStringParameters, - }; - const url = withQuery( - (event as APIGatewayProxyEvent).path || - (event as APIGatewayProxyEventV2).rawPath, - query - ); - const method = - (event as APIGatewayProxyEvent).httpMethod || - (event as APIGatewayProxyEventV2).requestContext?.http?.method || - "get"; - - if ("cookies" in event && event.cookies) { - event.headers.cookie = event.cookies.join(";"); - } + const request = awsRequest(event, context); - const r = await nitroApp.localCall({ - event, - url, - context, - headers: normalizeLambdaIncomingHeaders(event.headers) as Record< - string, - string | string[] - >, - method, - query, - body: event.isBase64Encoded - ? Buffer.from(event.body || "", "base64").toString("utf8") - : event.body, - }); + const response = await nitroApp.fetch(request); - // ApiGateway v2 https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html#http-api-develop-integrations-lambda.v2 - const isApiGwV2 = "cookies" in event || "rawPath" in event; - const awsBody = await normalizeLambdaOutgoingBody(r.body, r.headers); - const cookies = normalizeCookieHeader(r.headers["set-cookie"]); return { - ...(cookies.length > 0 && { - ...(isApiGwV2 - ? { cookies } - : { multiValueHeaders: { "set-cookie": cookies } }), - }), - statusCode: r.status, - headers: normalizeLambdaOutgoingHeaders(r.headers, true), - body: awsBody.body, - isBase64Encoded: awsBody.type === "binary", + statusCode: response.status, + ...awsResponseHeaders(response), + ...(await awsResponseBody(response)), }; } diff --git a/src/presets/azure/preset.ts b/src/presets/azure/preset.ts index e1e3c0380a..816bc3654d 100644 --- a/src/presets/azure/preset.ts +++ b/src/presets/azure/preset.ts @@ -1,19 +1,18 @@ -import { defineNitroPreset } from "nitropack/kit"; -import type { Nitro } from "nitropack/types"; -import { writeFunctionsRoutes, writeSWARoutes } from "./utils"; +import { defineNitroPreset } from "../_utils/preset.ts"; +import type { Nitro } from "nitro/types"; +import { writeSWARoutes } from "./utils.ts"; -export type { AzureOptions as PresetOptions } from "./types"; +export type { AzureOptions as PresetOptions } from "./types.ts"; -const azure = defineNitroPreset( +const azureSWA = defineNitroPreset( { - entry: "./runtime/azure-swa", + entry: "./azure/runtime/azure-swa", output: { serverDir: "{{ output.dir }}/server/functions", publicDir: "{{ output.dir }}/public/{{ baseURL }}", }, commands: { - preview: - "npx @azure/static-web-apps-cli start ./public --api-location ./server", + preview: "npx @azure/static-web-apps-cli start ./public --api-location ./server", }, hooks: { async compiled(ctx: Nitro) { @@ -23,30 +22,8 @@ const azure = defineNitroPreset( }, { name: "azure-swa" as const, - aliases: ["azure"] as const, stdName: "azure_static", - url: import.meta.url, } ); -const azureFunctions = defineNitroPreset( - { - serveStatic: true, - entry: "./runtime/azure-functions", - commands: { - deploy: - "az functionapp deployment source config-zip -g -n --src {{ output.dir }}/deploy.zip", - }, - hooks: { - async compiled(ctx: Nitro) { - await writeFunctionsRoutes(ctx); - }, - }, - }, - { - name: "azure-functions" as const, - url: import.meta.url, - } -); - -export default [azure, azureFunctions] as const; +export default [azureSWA] as const; diff --git a/src/runtime/internal/utils.azure.ts b/src/presets/azure/runtime/_utils.ts similarity index 79% rename from src/runtime/internal/utils.azure.ts rename to src/presets/azure/runtime/_utils.ts index 3bd770c9b4..711140b4ff 100644 --- a/src/runtime/internal/utils.azure.ts +++ b/src/presets/azure/runtime/_utils.ts @@ -1,20 +1,13 @@ import type { Cookie } from "@azure/functions"; import { parse } from "cookie-es"; -import { splitCookiesString } from "h3"; -export function getAzureParsedCookiesFromHeaders( - headers: Record -): Cookie[] { - const setCookieHeader = headers["set-cookie"]; - if ( - !setCookieHeader || - typeof setCookieHeader === "number" || - setCookieHeader.length === 0 - ) { +export function getAzureParsedCookiesFromHeaders(headers: Headers): Cookie[] { + const setCookieHeader = headers.getSetCookie(); + if (setCookieHeader.length === 0) { return []; } const azureCookies: Cookie[] = []; - for (const setCookieStr of splitCookiesString(setCookieHeader)) { + for (const setCookieStr of setCookieHeader) { const setCookie = Object.entries(parse(setCookieStr)); if (setCookie.length === 0) { continue; diff --git a/src/presets/azure/runtime/azure-functions.ts b/src/presets/azure/runtime/azure-functions.ts deleted file mode 100644 index 8a173268ad..0000000000 --- a/src/presets/azure/runtime/azure-functions.ts +++ /dev/null @@ -1,30 +0,0 @@ -import "#nitro-internal-pollyfills"; -import { useNitroApp } from "nitropack/runtime"; -import { - getAzureParsedCookiesFromHeaders, - normalizeLambdaOutgoingHeaders, -} from "nitropack/runtime/internal"; - -import type { HttpRequest, HttpResponse } from "@azure/functions"; - -const nitroApp = useNitroApp(); - -export async function handle(context: { res: HttpResponse }, req: HttpRequest) { - const url = "/" + (req.params.url || ""); - - const { body, status, statusText, headers } = await nitroApp.localCall({ - url, - headers: req.headers, - method: req.method || undefined, - // https://github.com/Azure/azure-functions-host/issues/293 - body: req.rawBody, - }); - - context.res = { - status, - // cookies https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-node?tabs=typescript%2Cwindows%2Cazure-cli&pivots=nodejs-model-v4#http-response - cookies: getAzureParsedCookiesFromHeaders(headers), - headers: normalizeLambdaOutgoingHeaders(headers, true), - body: body ?? statusText, - }; -} diff --git a/src/presets/azure/runtime/azure-swa.ts b/src/presets/azure/runtime/azure-swa.ts index 861c9ab9e9..de7cf65860 100644 --- a/src/presets/azure/runtime/azure-swa.ts +++ b/src/presets/azure/runtime/azure-swa.ts @@ -1,12 +1,9 @@ -import "#nitro-internal-pollyfills"; -import { useNitroApp } from "nitropack/runtime"; -import { - getAzureParsedCookiesFromHeaders, - normalizeLambdaOutgoingHeaders, -} from "nitropack/runtime/internal"; - -import type { HttpRequest, HttpResponse } from "@azure/functions"; +import "#nitro/virtual/polyfills"; import { parseURL } from "ufo"; +import { useNitroApp } from "nitro/app"; +import { getAzureParsedCookiesFromHeaders } from "./_utils.ts"; + +import type { HttpRequest, HttpResponse, HttpResponseSimple } from "@azure/functions"; const nitroApp = useNitroApp(); @@ -22,20 +19,23 @@ export async function handle(context: { res: HttpResponse }, req: HttpRequest) { url = "/api/" + (req.params.url || ""); } - const { body, status, headers } = await nitroApp.localCall({ - url, - headers: req.headers, + const request = new Request(url, { method: req.method || undefined, + // https://github.com/Azure/azure-functions-nodejs-worker/issues/294 // https://github.com/Azure/azure-functions-host/issues/293 - body: req.rawBody, + body: req.bufferBody ?? req.rawBody, }); + const response = await nitroApp.fetch(request); + // (v3 - current) https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-node?tabs=typescript%2Cwindows%2Cazure-cli&pivots=nodejs-model-v3#http-response // (v4) https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-node?tabs=typescript%2Cwindows%2Cazure-cli&pivots=nodejs-model-v4#http-response context.res = { - status, - cookies: getAzureParsedCookiesFromHeaders(headers), - headers: normalizeLambdaOutgoingHeaders(headers, true), - body, - }; + status: response.status, + body: response.body, + cookies: getAzureParsedCookiesFromHeaders(response.headers), + headers: Object.fromEntries( + [...response.headers.entries()].filter(([key]) => key !== "set-cookie") + ), + } satisfies HttpResponseSimple; } diff --git a/src/presets/azure/utils.ts b/src/presets/azure/utils.ts index 88aaeba121..484a0729a1 100644 --- a/src/presets/azure/utils.ts +++ b/src/presets/azure/utils.ts @@ -1,56 +1,15 @@ -import { createWriteStream } from "node:fs"; import fsp from "node:fs/promises"; -import archiver from "archiver"; -import { writeFile } from "nitropack/kit"; -import type { Nitro } from "nitropack/types"; +import { writeFile } from "../_utils/fs.ts"; +import type { Nitro } from "nitro/types"; import { join, resolve } from "pathe"; -export async function writeFunctionsRoutes(nitro: Nitro) { - const host = { - version: "2.0", - extensions: { http: { routePrefix: "" } }, - }; - - const functionDefinition = { - entryPoint: "handle", - bindings: [ - { - authLevel: "anonymous", - type: "httpTrigger", - direction: "in", - name: "req", - route: "{*url}", - methods: ["delete", "get", "head", "options", "patch", "post", "put"], - }, - { - type: "http", - direction: "out", - name: "res", - }, - ], - }; - - await writeFile( - resolve(nitro.options.output.serverDir, "function.json"), - JSON.stringify(functionDefinition) - ); - await writeFile( - resolve(nitro.options.output.dir, "host.json"), - JSON.stringify(host) - ); - await _zipDirectory( - nitro.options.output.dir, - join(nitro.options.output.dir, "deploy.zip") - ); -} - export async function writeSWARoutes(nitro: Nitro) { const host = { version: "2.0", }; // https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-node?tabs=typescript%2Cwindows%2Cazure-cli&pivots=nodejs-model-v4#supported-versions - const supportedNodeVersions = new Set(["16", "18", "20"]); + const supportedNodeVersions = new Set(["20", "22"]); let nodeVersion = "18"; try { const currentNodeVersion = JSON.parse( @@ -83,9 +42,7 @@ export async function writeSWARoutes(nitro: Nitro) { const routeFiles = nitro._prerenderedRoutes || []; - const indexFileExists = routeFiles.some( - (route) => route.fileName === "/index.html" - ); + const indexFileExists = routeFiles.some((route) => route.fileName === "/index.html"); if (!indexFileExists) { config.routes.unshift( { @@ -112,18 +69,12 @@ export async function writeSWARoutes(nitro: Nitro) { } for (const { fileName } of routeFiles) { - if ( - !fileName || - !fileName.endsWith(".html") || - fileName.endsWith("index.html") - ) { + if (!fileName || !fileName.endsWith(".html") || fileName.endsWith("index.html")) { continue; } const route = fileName.slice(0, -".html".length); - const existingRouteIndex = config.routes.findIndex( - (_route) => _route.route === route - ); + const existingRouteIndex = config.routes.findIndex((_route) => _route.route === route); if (existingRouteIndex !== -1) { config.routes.splice(existingRouteIndex, 1); } @@ -182,10 +133,7 @@ export async function writeSWARoutes(nitro: Nitro) { resolve(nitro.options.output.serverDir, "../host.json"), JSON.stringify(host, null, 2) ); - const stubPackageJson = resolve( - nitro.options.output.serverDir, - "../package.json" - ); + const stubPackageJson = resolve(nitro.options.output.serverDir, "../package.json"); await writeFile(stubPackageJson, JSON.stringify({ private: true })); await writeFile( resolve(nitro.options.rootDir, "staticwebapp.config.json"), @@ -203,18 +151,3 @@ export async function writeSWARoutes(nitro: Nitro) { ); } } - -function _zipDirectory(dir: string, outfile: string): Promise { - const archive = archiver("zip", { zlib: { level: 9 } }); - const stream = createWriteStream(outfile); - - return new Promise((resolve, reject) => { - archive - .glob("**/*", { cwd: dir, nodir: true, dot: true, follow: true }) - .on("error", (err: Error) => reject(err)) - .pipe(stream); - - stream.on("close", () => resolve(undefined)); - archive.finalize(); - }); -} diff --git a/src/presets/bun/preset.ts b/src/presets/bun/preset.ts index ed6250b3cd..4878e33430 100644 --- a/src/presets/bun/preset.ts +++ b/src/presets/bun/preset.ts @@ -1,18 +1,17 @@ -import { defineNitroPreset } from "nitropack/kit"; +import { defineNitroPreset } from "../_utils/preset.ts"; const bun = defineNitroPreset( { - extends: "node-server", - entry: "./runtime/bun", + entry: "./bun/runtime/bun", + serveStatic: true, // https://bun.sh/docs/runtime/modules#resolution - exportConditions: ["bun", "worker", "node", "import", "default"], + exportConditions: ["bun"], commands: { preview: "bun run ./server/index.mjs", }, }, { name: "bun" as const, - url: import.meta.url, } ); diff --git a/src/presets/bun/runtime/bun.ts b/src/presets/bun/runtime/bun.ts index d3f0eb05a9..dd7ecd05a8 100644 --- a/src/presets/bun/runtime/bun.ts +++ b/src/presets/bun/runtime/bun.ts @@ -1,46 +1,50 @@ -import "#nitro-internal-pollyfills"; -import { useNitroApp } from "nitropack/runtime"; -import { startScheduleRunner } from "nitropack/runtime/internal"; - +import "#nitro/virtual/polyfills"; +import type { ServerRequest } from "srvx"; +import { serve } from "srvx/bun"; import wsAdapter from "crossws/adapters/bun"; +import { useNitroApp } from "nitro/app"; +import { startScheduleRunner } from "#nitro/runtime/task"; +import { trapUnhandledErrors } from "#nitro/runtime/error/hooks"; +import { resolveWebsocketHooks } from "#nitro/runtime/app"; + +const _parsedPort = Number.parseInt(process.env.NITRO_PORT ?? process.env.PORT ?? ""); +const port = Number.isNaN(_parsedPort) ? 3000 : _parsedPort; +const host = process.env.NITRO_HOST || process.env.HOST; +const cert = process.env.NITRO_SSL_CERT; +const key = process.env.NITRO_SSL_KEY; +// const socketPath = process.env.NITRO_UNIX_SOCKET; // TODO + const nitroApp = useNitroApp(); -const ws = import.meta._websocket - ? wsAdapter(nitroApp.h3App.websocket) - : undefined; - -// @ts-expect-error -const server = Bun.serve({ - port: process.env.NITRO_PORT || process.env.PORT || 3000, - websocket: import.meta._websocket ? ws!.websocket : (undefined as any), - async fetch(req: Request, server: any) { - // https://crossws.unjs.io/adapters/bun - if (import.meta._websocket && req.headers.get("upgrade") === "websocket") { - return ws!.handleUpgrade(req, server); - } +let _fetch = nitroApp.fetch; - const url = new URL(req.url); +const ws = import.meta._websocket ? wsAdapter({ resolve: resolveWebsocketHooks }) : undefined; - let body; - if (req.body) { - body = await req.arrayBuffer(); +if (import.meta._websocket) { + _fetch = (req: ServerRequest) => { + if (req.headers.get("upgrade") === "websocket") { + return ws!.handleUpgrade(req, req.runtime!.bun!.server) as Promise; } + return nitroApp.fetch(req); + }; +} - return nitroApp.localFetch(url.pathname + url.search, { - host: url.hostname, - protocol: url.protocol, - headers: req.headers, - method: req.method, - redirect: req.redirect, - body, - }); +const server = serve({ + port, + hostname: host, + tls: cert && key ? { cert, key } : undefined, + fetch: _fetch, + bun: { + websocket: import.meta._websocket ? ws?.websocket : undefined, }, }); -console.log(`Listening on http://localhost:${server.port}...`); +trapUnhandledErrors(); // Scheduled tasks if (import.meta._tasks) { - startScheduleRunner(); + startScheduleRunner({ waitUntil: server.waitUntil }); } + +export default {}; diff --git a/src/presets/cleavr/preset.ts b/src/presets/cleavr/preset.ts index 75dbbea3f3..ac2fb51adb 100644 --- a/src/presets/cleavr/preset.ts +++ b/src/presets/cleavr/preset.ts @@ -1,13 +1,13 @@ -import { defineNitroPreset } from "nitropack/kit"; +import { defineNitroPreset } from "../_utils/preset.ts"; const cleavr = defineNitroPreset( { extends: "node-server", + serveStatic: true, }, { name: "cleavr" as const, stdName: "cleavr", - url: import.meta.url, } ); diff --git a/src/presets/cloudflare/dev.ts b/src/presets/cloudflare/dev.ts new file mode 100644 index 0000000000..156b6c1d0d --- /dev/null +++ b/src/presets/cloudflare/dev.ts @@ -0,0 +1,81 @@ +import { resolve } from "node:path"; +import { promises as fs } from "node:fs"; +import type { Nitro } from "nitro/types"; +import { findFile } from "pkg-types"; +import { resolveModulePath } from "exsolve"; +import { presetsDir } from "nitro/meta"; + +export async function cloudflareDevModule(nitro: Nitro) { + if (!nitro.options.dev) { + return; // Production doesn't need this + } + + nitro.options.unenv.push({ + meta: { + name: "nitro:cloudflare-dev", + }, + alias: { + "cloudflare:workers": resolve(presetsDir, "cloudflare/runtime/shims/workers.dev.mjs"), + }, + }); + + // Try to resolve wrangler + const wranglerPath = await resolveModulePath("wrangler", { + from: nitro.options.rootDir, + try: true, + }); + if (!wranglerPath) { + nitro.logger.warn( + "Wrangler is not installed. Please install it using `npx nypm i wrangler` to enable dev emulation." + ); + return; + } + + const config = { + // compatibility with legacy nitro-cloudflare-dev module + ...(nitro.options as any).cloudflareDev, + ...nitro.options.cloudflare?.dev, + } as NonNullable["dev"]>; + + // Find wrangler.json > wrangler.jsonc > wrangler.toml + let configPath = config.configPath; + if (!configPath) { + configPath = await findFile(["wrangler.json", "wrangler.jsonc", "wrangler.toml"], { + startingFrom: nitro.options.rootDir, + }).catch(() => undefined); + } + + // Resolve the persist dir + const persistDir = resolve(nitro.options.rootDir, config.persistDir || ".wrangler/state/v3"); + + // Add `.wrangler/state/v3` to `.gitignore` + const gitIgnorePath = await findFile(".gitignore", { + startingFrom: nitro.options.rootDir, + }).catch(() => undefined); + + // let addedToGitIgnore = false; + if (gitIgnorePath && persistDir === ".wrangler/state/v3") { + const gitIgnore = await fs.readFile(gitIgnorePath, "utf8"); + if (!gitIgnore.includes(".wrangler/state/v3")) { + await fs.writeFile(gitIgnorePath, gitIgnore + "\n.wrangler/state/v3\n").catch(() => {}); + // addedToGitIgnore = true; + } + } + + // Share config to the runtime + nitro.options.runtimeConfig.wrangler = { + ...nitro.options.runtimeConfig.wrangler, + configPath, + persistDir, + environment: config.environment, + }; + + // Add plugin to inject bindings to dev server + nitro.options.plugins = nitro.options.plugins || []; + nitro.options.plugins.unshift( + resolveModulePath("./cloudflare/runtime/plugin.dev", { + from: presetsDir, + extensions: [".mjs", ".ts"], + }) + ); +} diff --git a/src/presets/cloudflare/entry-exports.ts b/src/presets/cloudflare/entry-exports.ts new file mode 100644 index 0000000000..e67e4b0d34 --- /dev/null +++ b/src/presets/cloudflare/entry-exports.ts @@ -0,0 +1,37 @@ +import type { Nitro } from "nitro/types"; +import { resolveModulePath } from "exsolve"; +import { prettyPath } from "../../utils/fs.ts"; + +const RESOLVE_EXTENSIONS = [".ts", ".js", ".mts", ".mjs"]; + +export async function setupEntryExports(nitro: Nitro) { + const exportsEntry = resolveExportsEntry(nitro); + if (!exportsEntry) return; + + const originalEntry = nitro.options.entry; + + const virtualEntryId = (nitro.options.entry = "#nitro/virtual/cloudflare-server-entry"); + nitro.options.virtual[virtualEntryId] = /* ts */ ` + export * from "${exportsEntry}"; + export * from "${originalEntry}"; + export { default } from "${originalEntry}"; + `; +} + +function resolveExportsEntry(nitro: Nitro) { + const entry = resolveModulePath(nitro.options.cloudflare?.exports || "./exports.cloudflare.ts", { + from: nitro.options.rootDir, + extensions: RESOLVE_EXTENSIONS, + try: true, + }); + + if (!entry && nitro.options.cloudflare?.exports) { + nitro.logger.warn( + `Your custom Cloudflare entrypoint \`${prettyPath(nitro.options.cloudflare.exports)}\` file does not exist.` + ); + } else if (entry && !nitro.options.cloudflare?.exports) { + nitro.logger.info(`Detected \`${prettyPath(entry)}\` as Cloudflare entrypoint.`); + } + + return entry; +} diff --git a/src/presets/cloudflare/preset-legacy.ts b/src/presets/cloudflare/preset-legacy.ts deleted file mode 100644 index 19b0745e1c..0000000000 --- a/src/presets/cloudflare/preset-legacy.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { defineNitroPreset } from "nitropack/kit"; -import { writeFile } from "nitropack/kit"; -import type { Nitro } from "nitropack/types"; -import { resolve } from "pathe"; - -export type { CloudflareOptions as PresetOptions } from "./types"; - -const cloudflare = defineNitroPreset( - { - extends: "base-worker", - entry: "./runtime/cloudflare-worker", - exportConditions: ["workerd"], - commands: { - preview: "npx wrangler dev ./server/index.mjs --site ./public", - deploy: "npx wrangler deploy", - }, - wasm: { - lazy: true, - }, - hooks: { - async compiled(nitro: Nitro) { - await writeFile( - resolve(nitro.options.output.dir, "package.json"), - JSON.stringify({ private: true, main: "./server/index.mjs" }, null, 2) - ); - await writeFile( - resolve(nitro.options.output.dir, "package-lock.json"), - JSON.stringify({ lockfileVersion: 1 }, null, 2) - ); - }, - }, - }, - { - name: "cloudflare-worker" as const, - aliases: ["cloudflare"] as const, - url: import.meta.url, - } -); - -const cloudflareModuleLegacy = defineNitroPreset( - { - extends: "base-worker", - entry: "./runtime/cloudflare-module-legacy", - exportConditions: ["workerd"], - commands: { - preview: "npx wrangler dev ./server/index.mjs --site ./public", - deploy: "npx wrangler deploy", - }, - rollupConfig: { - external: "__STATIC_CONTENT_MANIFEST", - output: { - format: "esm", - exports: "named", - inlineDynamicImports: false, - }, - }, - wasm: { - lazy: false, - esmImport: true, - }, - hooks: { - async compiled(nitro: Nitro) { - await writeFile( - resolve(nitro.options.output.dir, "package.json"), - JSON.stringify({ private: true, main: "./server/index.mjs" }, null, 2) - ); - await writeFile( - resolve(nitro.options.output.dir, "package-lock.json"), - JSON.stringify({ lockfileVersion: 1 }, null, 2) - ); - }, - }, - }, - { - name: "cloudflare-module-legacy" as const, - aliases: ["cloudflare-module"] as const, - url: import.meta.url, - } -); - -export default [cloudflare, cloudflareModuleLegacy]; diff --git a/src/presets/cloudflare/preset.ts b/src/presets/cloudflare/preset.ts index 64f0897f1a..218d025080 100644 --- a/src/presets/cloudflare/preset.ts +++ b/src/presets/cloudflare/preset.ts @@ -1,25 +1,26 @@ -import { defineNitroPreset } from "nitropack/kit"; -import { writeFile } from "nitropack/kit"; -import type { Nitro } from "nitropack/types"; +import { defineNitroPreset } from "../_utils/preset.ts"; +import { writeFile } from "../_utils/fs.ts"; +import type { Nitro } from "nitro/types"; import { resolve } from "pathe"; -import { unenvCfExternals } from "../_unenv/preset-workerd"; +import { unenvCfExternals } from "./unenv/preset.ts"; import { enableNodeCompat, writeWranglerConfig, writeCFRoutes, - writeCFPagesHeaders, + writeCFHeaders, writeCFPagesRedirects, -} from "./utils"; +} from "./utils.ts"; +import { cloudflareDevModule } from "./dev.ts"; +import { setupEntryExports } from "./entry-exports.ts"; -import cfLegacyPresets from "./preset-legacy"; - -export type { CloudflareOptions as PresetOptions } from "./types"; +export type { CloudflareOptions as PresetOptions } from "./types.ts"; const cloudflarePages = defineNitroPreset( { - extends: "cloudflare", - entry: "./runtime/cloudflare-pages", + extends: "base-worker", + entry: "./cloudflare/runtime/cloudflare-pages", exportConditions: ["workerd"], + minify: false, commands: { preview: "npx wrangler --cwd ./ pages dev", deploy: "npx wrangler --cwd ./ pages deploy", @@ -29,7 +30,6 @@ const cloudflarePages = defineNitroPreset( publicDir: "{{ output.dir }}/{{ baseURL }}", serverDir: "{{ output.dir }}/_worker.js", }, - unenv: [unenvCfExternals], alias: { // Hotfix: Cloudflare appends /index.html if mime is not found and things like ico are not in standard lite.js! // https://github.com/nitrojs/nitro/pull/933 @@ -48,12 +48,14 @@ const cloudflarePages = defineNitroPreset( }, hooks: { "build:before": async (nitro) => { + nitro.options.unenv.push(unenvCfExternals); await enableNodeCompat(nitro); + await setupEntryExports(nitro); }, async compiled(nitro: Nitro) { await writeWranglerConfig(nitro, "pages"); await writeCFRoutes(nitro); - await writeCFPagesHeaders(nitro); + await writeCFHeaders(nitro, "output"); await writeCFPagesRedirects(nitro); }, }, @@ -61,7 +63,6 @@ const cloudflarePages = defineNitroPreset( { name: "cloudflare-pages" as const, stdName: "cloudflare_pages", - url: import.meta.url, } ); @@ -78,7 +79,7 @@ const cloudflarePagesStatic = defineNitroPreset( }, hooks: { async compiled(nitro: Nitro) { - await writeCFPagesHeaders(nitro); + await writeCFHeaders(nitro, "output"); await writeCFPagesRedirects(nitro); }, }, @@ -86,21 +87,37 @@ const cloudflarePagesStatic = defineNitroPreset( { name: "cloudflare-pages-static" as const, stdName: "cloudflare_pages", - url: import.meta.url, + static: true, } ); +export const cloudflareDev = defineNitroPreset( + { + extends: "nitro-dev", + modules: [cloudflareDevModule], + }, + { + name: "cloudflare-dev" as const, + aliases: ["cloudflare-module", "cloudflare-durable", "cloudflare-pages"], + compatibilityDate: "2025-07-13", + dev: true, + } +); + const cloudflareModule = defineNitroPreset( { extends: "base-worker", - entry: "./runtime/cloudflare-module", + entry: "./cloudflare/runtime/cloudflare-module", + output: { + publicDir: "{{ output.dir }}/public/{{ baseURL }}", + }, exportConditions: ["workerd"], + minify: false, commands: { preview: "npx wrangler --cwd ./ dev", deploy: "npx wrangler --cwd ./ deploy", }, - unenv: [unenvCfExternals], rollupConfig: { output: { format: "esm", @@ -114,10 +131,13 @@ const cloudflareModule = defineNitroPreset( }, hooks: { "build:before": async (nitro) => { + nitro.options.unenv.push(unenvCfExternals); await enableNodeCompat(nitro); + await setupEntryExports(nitro); }, async compiled(nitro: Nitro) { await writeWranglerConfig(nitro, "module"); + await writeCFHeaders(nitro, "public"); await writeFile( resolve(nitro.options.output.dir, "package.json"), @@ -132,27 +152,24 @@ const cloudflareModule = defineNitroPreset( }, { name: "cloudflare-module" as const, - compatibilityDate: "2024-09-19", - url: import.meta.url, + stdName: "cloudflare_workers", } ); const cloudflareDurable = defineNitroPreset( { extends: "cloudflare-module", - entry: "./runtime/cloudflare-durable", + entry: "./cloudflare/runtime/cloudflare-durable", }, { name: "cloudflare-durable" as const, - compatibilityDate: "2024-09-19", - url: import.meta.url, } ); export default [ - ...cfLegacyPresets, cloudflarePages, cloudflarePagesStatic, cloudflareModule, cloudflareDurable, + cloudflareDev, ]; diff --git a/src/presets/cloudflare/runtime/_module-handler.ts b/src/presets/cloudflare/runtime/_module-handler.ts index 6ab7dd785c..8d7eeefb07 100644 --- a/src/presets/cloudflare/runtime/_module-handler.ts +++ b/src/presets/cloudflare/runtime/_module-handler.ts @@ -1,8 +1,9 @@ -import "#nitro-internal-pollyfills"; +import "#nitro/virtual/polyfills"; import type * as CF from "@cloudflare/workers-types"; -import type { ExportedHandler } from "@cloudflare/workers-types"; -import { useNitroApp } from "nitropack/runtime"; -import { requestHasBody, runCronTasks } from "nitropack/runtime/internal"; +import type { ServerRequest, ServerRuntimeContext } from "srvx"; + +import { runCronTasks } from "#nitro/runtime/task"; +import { useNitroApp, useNitroHooks } from "nitro/app"; type MaybePromise = T | Promise; @@ -16,9 +17,13 @@ export function createHandler(hooks: { ) => MaybePromise; }) { const nitroApp = useNitroApp(); + const nitroHooks = useNitroHooks(); - return >{ + return { async fetch(request, env, context) { + (globalThis as any).__env__ = env; + augmentReq(request as any, { env: env as any, context }); + const ctxExt = {}; const url = new URL(request.url); @@ -30,17 +35,17 @@ export function createHandler(hooks: { } } - return fetchHandler(request, env, context, url, nitroApp, ctxExt); + return (await nitroApp.fetch(request)) as any; }, scheduled(controller, env, context) { (globalThis as any).__env__ = env; context.waitUntil( - nitroApp.hooks.callHook("cloudflare:scheduled", { + nitroHooks.callHook("cloudflare:scheduled", { controller, env, context, - }) + }) || Promise.resolve() ); if (import.meta._tasks) { context.waitUntil( @@ -60,83 +65,60 @@ export function createHandler(hooks: { email(message, env, context) { (globalThis as any).__env__ = env; context.waitUntil( - nitroApp.hooks.callHook("cloudflare:email", { - message, - event: message, // backward compat + nitroHooks.callHook("cloudflare:email", { + message: message as any, + event: message as any, // backward compat env, context, - }) + }) || Promise.resolve() ); }, queue(batch, env, context) { (globalThis as any).__env__ = env; context.waitUntil( - nitroApp.hooks.callHook("cloudflare:queue", { + nitroHooks.callHook("cloudflare:queue", { batch, event: batch, env, context, - }) + }) || Promise.resolve() ); }, tail(traces, env, context) { (globalThis as any).__env__ = env; context.waitUntil( - nitroApp.hooks.callHook("cloudflare:tail", { + nitroHooks.callHook("cloudflare:tail", { traces, env, context, - }) + }) || Promise.resolve() ); }, trace(traces, env, context) { (globalThis as any).__env__ = env; context.waitUntil( - nitroApp.hooks.callHook("cloudflare:trace", { + nitroHooks.callHook("cloudflare:trace", { traces, env, context, - }) + }) || Promise.resolve() ); }, - }; + } satisfies ExportedHandler; } -export async function fetchHandler( - request: Request | CF.Request, - env: unknown, - context: CF.ExecutionContext | DurableObjectState, - url: URL = new URL(request.url), - nitroApp = useNitroApp(), - ctxExt: any +export function augmentReq( + cfReq: Request | CF.Request, + ctx: NonNullable ) { - let body; - if (requestHasBody(request as unknown as Request)) { - body = Buffer.from(await request.arrayBuffer()); - } + const req = cfReq as ServerRequest; - // Expose latest env to the global context - (globalThis as any).__env__ = env; + req.ip = cfReq.headers.get("cf-connecting-ip") || undefined; - return nitroApp.localFetch(url.pathname + url.search, { - context: { - cf: (request as any).cf, - waitUntil: (promise: Promise) => context.waitUntil(promise), - cloudflare: { - request, - env, - context, - url, - ...ctxExt, - }, - }, - host: url.hostname, - protocol: url.protocol, - method: request.method, - headers: request.headers as unknown as Headers, - body, - }) as unknown as Promise; + req.runtime ??= { name: "cloudflare" }; + req.runtime.cloudflare = { ...req.runtime.cloudflare, ...ctx }; + req.waitUntil = ctx.context?.waitUntil.bind(ctx.context); } diff --git a/src/presets/cloudflare/runtime/cloudflare-durable.ts b/src/presets/cloudflare/runtime/cloudflare-durable.ts index 548b6ca03c..bcb9962770 100644 --- a/src/presets/cloudflare/runtime/cloudflare-durable.ts +++ b/src/presets/cloudflare/runtime/cloudflare-durable.ts @@ -1,10 +1,12 @@ -import "#nitro-internal-pollyfills"; +import "#nitro/virtual/polyfills"; import type * as CF from "@cloudflare/workers-types"; import { DurableObject } from "cloudflare:workers"; -import wsAdapter from "crossws/adapters/cloudflare-durable"; -import { useNitroApp } from "nitropack/runtime"; -import { isPublicAssetURL } from "#nitro-internal-virtual/public-assets"; -import { createHandler, fetchHandler } from "./_module-handler"; +import wsAdapter from "crossws/adapters/cloudflare"; +import { createHandler, augmentReq } from "./_module-handler.ts"; + +import { useNitroApp, useNitroHooks } from "nitro/app"; +import { isPublicAssetURL } from "#nitro/virtual/public-assets"; +import { resolveWebsocketHooks } from "#nitro/runtime/app"; const DURABLE_BINDING = "$DurableObject"; const DURABLE_INSTANCE = "server"; @@ -15,13 +17,12 @@ interface Env { } const nitroApp = useNitroApp(); +const nitroHooks = useNitroHooks(); const getDurableStub = (env: Env) => { const binding = env[DURABLE_BINDING]; if (!binding) { - throw new Error( - `Durable Object binding "${DURABLE_BINDING}" not available.` - ); + throw new Error(`Durable Object binding "${DURABLE_BINDING}" not available.`); } const id = binding.idFromName(DURABLE_INSTANCE); return binding.get(id); @@ -29,7 +30,7 @@ const getDurableStub = (env: Env) => { const ws = import.meta._websocket ? wsAdapter({ - ...nitroApp.h3App.websocket, + resolve: resolveWebsocketHooks, instanceName: DURABLE_INSTANCE, bindingName: DURABLE_BINDING, }) @@ -39,18 +40,15 @@ export default createHandler({ fetch(request, env, context, url, ctxExt) { // Static assets fallback (optional binding) if (env.ASSETS && isPublicAssetURL(url.pathname)) { - return env.ASSETS.fetch(request); + return env.ASSETS.fetch(request as any); } // Expose stub fetch to the context - ctxExt.durableFetch = (req = request) => getDurableStub(env).fetch(req); + ctxExt.durableFetch = (req = request) => getDurableStub(env).fetch(req as any); // Websocket upgrade // https://crossws.unjs.io/adapters/cloudflare#durable-objects - if ( - import.meta._websocket && - request.headers.get("upgrade") === "websocket" - ) { + if (import.meta._websocket && request.headers.get("upgrade") === "websocket") { return ws!.handleUpgrade(request, env, context); } }, @@ -60,10 +58,10 @@ export class $DurableObject extends DurableObject { constructor(state: DurableObjectState, env: Record) { super(state, env); state.waitUntil( - nitroApp.hooks.callHook("cloudflare:durable:init", this, { + nitroHooks.callHook("cloudflare:durable:init", this, { state, env, - }) + }) || Promise.resolve() ); if (import.meta._websocket) { ws!.handleDurableInit(this, state, env); @@ -71,29 +69,23 @@ export class $DurableObject extends DurableObject { } override fetch(request: Request) { - if ( - import.meta._websocket && - request.headers.get("upgrade") === "websocket" - ) { + augmentReq(request, { + env: this.env, + context: this.ctx as any, + }); + + if (import.meta._websocket && request.headers.get("upgrade") === "websocket") { return ws!.handleDurableUpgrade(this, request); } - // Main handler - const url = new URL(request.url); - return fetchHandler(request, this.env, this.ctx, url, nitroApp, { - durable: this, - }); + + return nitroApp.fetch(request); } override alarm(): void | Promise { - this.ctx.waitUntil( - nitroApp.hooks.callHook("cloudflare:durable:alarm", this) - ); + this.ctx.waitUntil(nitroHooks.callHook("cloudflare:durable:alarm", this) || Promise.resolve()); } - override async webSocketMessage( - client: WebSocket, - message: ArrayBuffer | string - ) { + override async webSocketMessage(client: WebSocket, message: ArrayBuffer | string) { if (import.meta._websocket) { return ws!.handleDurableMessage(this, client, message); } diff --git a/src/presets/cloudflare/runtime/cloudflare-module-legacy.ts b/src/presets/cloudflare/runtime/cloudflare-module-legacy.ts deleted file mode 100644 index 21b2c64e8e..0000000000 --- a/src/presets/cloudflare/runtime/cloudflare-module-legacy.ts +++ /dev/null @@ -1,74 +0,0 @@ -import "#nitro-internal-pollyfills"; -import { - getAssetFromKV, - mapRequestToAsset, -} from "@cloudflare/kv-asset-handler"; -import wsAdapter from "crossws/adapters/cloudflare"; -import { withoutBase } from "ufo"; -import { useNitroApp, useRuntimeConfig } from "nitropack/runtime"; -import { getPublicAssetMeta } from "#nitro-internal-virtual/public-assets"; -import { createHandler } from "./_module-handler"; - -// @ts-ignore Bundled by Wrangler -// See https://github.com/cloudflare/kv-asset-handler#asset_manifest-required-for-es-modules -import manifest from "__STATIC_CONTENT_MANIFEST"; - -const nitroApp = useNitroApp(); - -const ws = import.meta._websocket - ? wsAdapter(nitroApp.h3App.websocket) - : undefined; - -interface Env { - __STATIC_CONTENT?: any; -} - -export default createHandler({ - async fetch(request, env, context) { - // Websocket upgrade - // https://crossws.unjs.io/adapters/cloudflare - if ( - import.meta._websocket && - request.headers.get("upgrade") === "websocket" - ) { - return ws!.handleUpgrade(request as any, env, context); - } - - try { - // https://github.com/cloudflare/kv-asset-handler#es-modules - return await getAssetFromKV( - { - request: request as unknown as Request, - waitUntil(promise) { - return context.waitUntil(promise); - }, - }, - { - cacheControl: assetsCacheControl, - mapRequestToAsset: baseURLModifier, - ASSET_NAMESPACE: env.__STATIC_CONTENT, - ASSET_MANIFEST: JSON.parse(manifest), - } - ); - } catch { - // Ignore - } - }, -}); - -function assetsCacheControl(_request: Request) { - const url = new URL(_request.url); - const meta = getPublicAssetMeta(url.pathname); - if (meta.maxAge) { - return { - browserTTL: meta.maxAge, - edgeTTL: meta.maxAge, - }; - } - return {}; -} - -const baseURLModifier = (request: Request) => { - const url = withoutBase(request.url, useRuntimeConfig().app.baseURL); - return mapRequestToAsset(new Request(url, request)); -}; diff --git a/src/presets/cloudflare/runtime/cloudflare-module.ts b/src/presets/cloudflare/runtime/cloudflare-module.ts index 32bc0efd23..b9a107c640 100644 --- a/src/presets/cloudflare/runtime/cloudflare-module.ts +++ b/src/presets/cloudflare/runtime/cloudflare-module.ts @@ -1,34 +1,28 @@ -import "#nitro-internal-pollyfills"; +import "#nitro/virtual/polyfills"; import type { fetch } from "@cloudflare/workers-types"; import wsAdapter from "crossws/adapters/cloudflare"; -import { useNitroApp } from "nitropack/runtime"; -import { isPublicAssetURL } from "#nitro-internal-virtual/public-assets"; -import { createHandler } from "./_module-handler"; -const nitroApp = useNitroApp(); +import { isPublicAssetURL } from "#nitro/virtual/public-assets"; +import { createHandler } from "./_module-handler.ts"; +import { resolveWebsocketHooks } from "#nitro/runtime/app"; -const ws = import.meta._websocket - ? wsAdapter(nitroApp.h3App.websocket) - : undefined; +const ws = import.meta._websocket ? wsAdapter({ resolve: resolveWebsocketHooks }) : undefined; interface Env { ASSETS?: { fetch: typeof fetch }; } export default createHandler({ - fetch(request, env, context, url) { + fetch(cfRequest, env, context, url) { // Static assets fallback (optional binding) if (env.ASSETS && isPublicAssetURL(url.pathname)) { - return env.ASSETS.fetch(request); + return env.ASSETS.fetch(cfRequest as any); } // Websocket upgrade // https://crossws.unjs.io/adapters/cloudflare - if ( - import.meta._websocket && - request.headers.get("upgrade") === "websocket" - ) { - return ws!.handleUpgrade(request as any, env, context); + if (import.meta._websocket && cfRequest.headers.get("upgrade") === "websocket") { + return ws!.handleUpgrade(cfRequest, env, context); } }, }); diff --git a/src/presets/cloudflare/runtime/cloudflare-pages.ts b/src/presets/cloudflare/runtime/cloudflare-pages.ts index 753de02d7d..695f63f117 100644 --- a/src/presets/cloudflare/runtime/cloudflare-pages.ts +++ b/src/presets/cloudflare/runtime/cloudflare-pages.ts @@ -1,8 +1,4 @@ -import "#nitro-internal-pollyfills"; -import { useNitroApp } from "nitropack/runtime"; -import { requestHasBody, runCronTasks } from "nitropack/runtime/internal"; -import { isPublicAssetURL } from "#nitro-internal-virtual/public-assets"; - +import "#nitro/virtual/polyfills"; import type { Request as CFRequest, EventContext, @@ -10,6 +6,13 @@ import type { } from "@cloudflare/workers-types"; import wsAdapter from "crossws/adapters/cloudflare"; +import { useNitroApp } from "nitro/app"; +import { isPublicAssetURL } from "#nitro/virtual/public-assets"; +import { runCronTasks } from "#nitro/runtime/task"; +import { resolveWebsocketHooks } from "#nitro/runtime/app"; + +import { augmentReq } from "./_module-handler.ts"; + /** * Reference: https://developers.cloudflare.com/workers/runtime-apis/fetch-event/#parameters */ @@ -25,58 +28,27 @@ interface CFPagesEnv { const nitroApp = useNitroApp(); -const ws = import.meta._websocket - ? wsAdapter(nitroApp.h3App.websocket) - : undefined; +const ws = import.meta._websocket ? wsAdapter({ resolve: resolveWebsocketHooks }) : undefined; export default { - async fetch( - request: CFRequest, - env: CFPagesEnv, - context: EventContext - ) { + async fetch(cfReq: CFRequest, env: CFPagesEnv, context: EventContext) { + augmentReq(cfReq, { + env, + context: context as any, + }); + // Websocket upgrade // https://crossws.unjs.io/adapters/cloudflare - if ( - import.meta._websocket && - request.headers.get("upgrade") === "websocket" - ) { - return ws!.handleUpgrade( - request as any, - env, - context as unknown as ExecutionContext - ); + if (import.meta._websocket && cfReq.headers.get("upgrade") === "websocket") { + return ws!.handleUpgrade(cfReq, env, context as unknown as ExecutionContext); } - const url = new URL(request.url); + const url = new URL(cfReq.url); if (env.ASSETS /* !miniflare */ && isPublicAssetURL(url.pathname)) { - return env.ASSETS.fetch(request); - } - - let body; - if (requestHasBody(request as unknown as Request)) { - body = Buffer.from(await request.arrayBuffer()); + return env.ASSETS.fetch(cfReq); } - // Expose latest env to the global context - (globalThis as any).__env__ = env; - - return nitroApp.localFetch(url.pathname + url.search, { - context: { - cf: request.cf, - waitUntil: (promise: Promise) => context.waitUntil(promise), - cloudflare: { - request, - env, - context, - }, - }, - host: url.hostname, - protocol: url.protocol, - method: request.method, - headers: request.headers as unknown as Headers, - body, - }); + return nitroApp.fetch(cfReq as any); }, scheduled(event: any, env: CFPagesEnv, context: ExecutionContext) { if (import.meta._tasks) { diff --git a/src/presets/cloudflare/runtime/cloudflare-worker.ts b/src/presets/cloudflare/runtime/cloudflare-worker.ts deleted file mode 100644 index 92293c69d7..0000000000 --- a/src/presets/cloudflare/runtime/cloudflare-worker.ts +++ /dev/null @@ -1,81 +0,0 @@ -import "#nitro-internal-pollyfills"; -import { useNitroApp, useRuntimeConfig } from "nitropack/runtime"; -import { requestHasBody } from "nitropack/runtime/internal"; -import { getPublicAssetMeta } from "#nitro-internal-virtual/public-assets"; - -import { - getAssetFromKV, - mapRequestToAsset, -} from "@cloudflare/kv-asset-handler"; -import wsAdapter from "crossws/adapters/cloudflare"; -import { withoutBase } from "ufo"; - -addEventListener("fetch", (event: any) => { - event.respondWith(handleEvent(event)); -}); - -const nitroApp = useNitroApp(); - -const ws = import.meta._websocket - ? wsAdapter(nitroApp.h3App.websocket) - : undefined; - -async function handleEvent(event: FetchEvent) { - // Websocket upgrade - // https://crossws.unjs.io/adapters/cloudflare - if ( - import.meta._websocket && - event.request.headers.get("upgrade") === "websocket" - ) { - return ws!.handleUpgrade(event.request as any, {} /* env */, event as any); - } - - try { - return await getAssetFromKV(event, { - cacheControl: assetsCacheControl, - mapRequestToAsset: baseURLModifier, - }); - } catch { - // Ignore - } - - const url = new URL(event.request.url); - let body; - if (requestHasBody(event.request)) { - body = Buffer.from(await event.request.arrayBuffer()); - } - - return nitroApp.localFetch(url.pathname + url.search, { - context: { - // https://developers.cloudflare.com/workers//runtime-apis/request#incomingrequestcfproperties - cf: (event.request as any).cf, - waitUntil: (promise: Promise) => event.waitUntil(promise), - cloudflare: { - event, - }, - }, - host: url.hostname, - protocol: url.protocol, - headers: event.request.headers, - method: event.request.method, - redirect: event.request.redirect, - body, - }); -} - -function assetsCacheControl(_request: Request) { - const url = new URL(_request.url); - const meta = getPublicAssetMeta(url.pathname); - if (meta.maxAge) { - return { - browserTTL: meta.maxAge, - edgeTTL: meta.maxAge, - }; - } - return {}; -} - -const baseURLModifier = (request: Request) => { - const url = withoutBase(request.url, useRuntimeConfig().app.baseURL); - return mapRequestToAsset(new Request(url, request)); -}; diff --git a/src/presets/cloudflare/runtime/plugin.dev.ts b/src/presets/cloudflare/runtime/plugin.dev.ts new file mode 100644 index 0000000000..5d9f51647e --- /dev/null +++ b/src/presets/cloudflare/runtime/plugin.dev.ts @@ -0,0 +1,108 @@ +import type { NitroAppPlugin } from "nitro/types"; +import type { GetPlatformProxyOptions, PlatformProxy } from "wrangler"; + +import { useRuntimeConfig } from "nitro/runtime-config"; + +const proxy = await _getPlatformProxy().catch((error) => { + console.error("Failed to initialize wrangler bindings proxy", error); + return _createStubProxy(); +}); + +(globalThis as any).__env__ = proxy.env; +(globalThis as any).__wait_until__ = proxy.ctx.waitUntil.bind(proxy.ctx); + +const cloudflareDevPlugin: NitroAppPlugin = function (nitroApp) { + nitroApp.hooks.hook("request", async (event) => { + const request = event.req; + + (request as any).runtime ??= { name: "cloudflare" }; + (request as any).runtime.cloudflare = { + ...(request as any).runtime.cloudflare, + env: proxy.env, + context: proxy.ctx, + }; + (request as any).waitUntil = proxy.ctx.waitUntil.bind(proxy.ctx); + (request as any).cf = proxy.cf; + }); + + // https://github.com/pi0/nitro-cloudflare-dev/issues/5 + // https://github.com/unjs/hookable/issues/98 + // @ts-expect-error + nitroApp.hooks._hooks.request.unshift(nitroApp.hooks._hooks.request.pop()); + + // Dispose proxy when Nitro is closed + nitroApp.hooks.hook("close", () => { + return proxy?.dispose(); + }); +}; + +export default cloudflareDevPlugin; + +async function _getPlatformProxy() { + const pkg = "wrangler"; // bypass bundler + const { getPlatformProxy } = (await import(/* @vite-ignore */ pkg).catch(() => { + throw new Error( + "Package `wrangler` not found, please install it with: `npx nypm@latest add -D wrangler`" + ); + })) as typeof import("wrangler"); + + const runtimeConfig: { + wrangler: { + configPath: string; + persistDir: string; + environment?: string; + }; + } = useRuntimeConfig() as any; + + const proxyOptions: GetPlatformProxyOptions = { + configPath: runtimeConfig.wrangler.configPath, + persist: { path: runtimeConfig.wrangler.persistDir }, + }; + // TODO: investigate why + // https://github.com/pi0/nitro-cloudflare-dev/issues/51 + if (runtimeConfig.wrangler.environment) { + proxyOptions.environment = runtimeConfig.wrangler.environment; + } + const proxy = await getPlatformProxy(proxyOptions); + + return proxy; +} + +function _createStubProxy(): PlatformProxy { + return { + env: {}, + cf: {} as any, + ctx: { + waitUntil() {}, + passThroughOnException() {}, + props: {}, + }, + caches: { + open(): Promise<_CacheStub> { + const result = Promise.resolve(new _CacheStub()); + return result; + }, + get default(): _CacheStub { + return new _CacheStub(); + }, + }, + dispose: () => Promise.resolve(), + }; +} + +class _CacheStub { + delete(): Promise { + const result = Promise.resolve(false); + return result; + } + + match() { + const result = Promise.resolve(undefined); + return result; + } + + put(): Promise { + const result = Promise.resolve(); + return result; + } +} diff --git a/src/presets/cloudflare/runtime/shims/workers.dev.mjs b/src/presets/cloudflare/runtime/shims/workers.dev.mjs new file mode 100644 index 0000000000..249f46f70e --- /dev/null +++ b/src/presets/cloudflare/runtime/shims/workers.dev.mjs @@ -0,0 +1,27 @@ +// Shim for "cloudflare:workers" import in dev environment + +// unenv shim respects __env__ +export { env } from "unenv/node/internal/process/env"; + +export async function waitUntil(promise) { + await globalThis.__wait_until__?.(promise); +} + +export function withEnv(newEnv, fn) { + throw new Error("cf.withEnv is not implemented in dev env currently."); +} + +class NotImplemented { + constructor() { + throw new Error("Not implemented in dev env currently."); + } +} + +export class DurableObject extends NotImplemented {} +export class RpcPromise extends NotImplemented {} +export class RpcProperty extends NotImplemented {} +export class RpcStub extends NotImplemented {} +export class RpcTarget extends NotImplemented {} +export class ServiceStub extends NotImplemented {} +export class WorkerEntrypoint extends NotImplemented {} +export class WorkflowEntrypoint extends NotImplemented {} diff --git a/src/presets/cloudflare/types.ts b/src/presets/cloudflare/types.ts index 98d7a936a1..59eb56d1f7 100644 --- a/src/presets/cloudflare/types.ts +++ b/src/presets/cloudflare/types.ts @@ -7,10 +7,7 @@ import type { } from "@cloudflare/workers-types"; import type { DurableObject } from "cloudflare:workers"; -import type { - Config as _Config, - ComputedFields as _ComputedFields, -} from "./wrangler/config"; +import type { Config as _Config, ComputedFields as _ComputedFields } from "./wrangler/config.ts"; export type WranglerConfig = Partial>; @@ -54,6 +51,15 @@ export interface CloudflareOptions { */ nodeCompat?: boolean; + /** + * Options for dev emulation. + */ + dev?: { + configPath?: string; + environment?: string; + persistDir?: string; + }; + pages?: { /** * Nitro will automatically generate a `_routes.json` that controls which files get served statically and @@ -83,11 +89,16 @@ export interface CloudflareOptions { */ defaultRoutes?: boolean; }; + + /** + * Custom Cloudflare exports additional classes such as WorkflowEntrypoint. + */ + exports?: string; } type DurableObjectState = ConstructorParameters[0]; -declare module "nitropack/types" { +declare module "nitro/types" { export interface NitroRuntimeHooks { // https://developers.cloudflare.com/workers/runtime-apis/handlers/scheduled/ "cloudflare:scheduled": (_: { diff --git a/src/presets/cloudflare/unenv/node-compat.ts b/src/presets/cloudflare/unenv/node-compat.ts new file mode 100644 index 0000000000..e428593c13 --- /dev/null +++ b/src/presets/cloudflare/unenv/node-compat.ts @@ -0,0 +1,83 @@ +// Auto generated at 2025-10-05 +// Source: https://platform-node-compat.pi0.workers.dev/ +// Do not edit this file manually + +// prettier-ignore +export const builtnNodeModules = [ + "node:_http_agent", + "node:_http_client", + "node:_http_common", // Missing exports: CRLF, HTTPParser, freeParser, isLenient, parsers, prepareError + "node:_http_incoming", // Missing exports: readStart, readStop + "node:_http_outgoing", + "node:_http_server", + "node:_stream_duplex", + "node:_stream_passthrough", + "node:_stream_readable", + "node:_stream_transform", + "node:_stream_writable", + "node:_tls_common", + "node:_tls_wrap", // Missing exports: Server, createServer + "node:assert", // Missing exports: Assert, CallTracker + "node:assert/strict", // Missing exports: Assert, CallTracker + "node:async_hooks", + "node:buffer", + "node:constants", // Missing exports: O_DIRECT, O_NOATIME, RTLD_DEEPBIND, SIGPOLL, SIGPWR, SIGSTKFLT, defaultCipherList + "node:crypto", // Missing exports: argon2, argon2Sync, decapsulate, encapsulate + "node:diagnostics_channel", + "node:dns", // Missing exports: resolveTlsa + "node:dns/promises", // Missing exports: resolveTlsa + "node:events", // Missing exports: captureRejections, init + "node:fs", // Missing exports: Utf8Stream, mkdtempDisposableSync + "node:fs/promises", // Missing exports: mkdtempDisposable + "node:http", + "node:http2", + "node:https", + "node:module", + "node:net", + "node:os", + "node:path", + "node:path/posix", + "node:path/win32", + "node:process", + "node:querystring", + "node:stream", + "node:stream/consumers", + "node:stream/promises", + "node:stream/web", + "node:string_decoder", + "node:test", // Missing exports: after, afterEach, assert, before, beforeEach, describe, it, only, run, skip, snapshot, suite, test, todo + "node:timers", + "node:timers/promises", + "node:tls", // Missing exports: getCACertificates, setDefaultCACertificates + "node:url", // Missing exports: URLPattern, fileURLToPathBuffer + "node:util", // Missing exports: diff, setTraceSigInt + "node:util/types", + "node:zlib", // Missing exports: ZstdCompress, ZstdDecompress, createZstdCompress, createZstdDecompress, zstdCompress, zstdCompressSync, zstdDecompress, zstdDecompressSync +]; + +// prettier-ignore +export const unsupportedNodeModules = [ + "node:_stream_wrap", + "node:child_process", + "node:cluster", + "node:console", + "node:dgram", + "node:domain", + "node:inspector", + "node:inspector/promises", + "node:perf_hooks", + "node:punycode", + "node:readline", + "node:readline/promises", + "node:repl", + "node:sys", + "node:trace_events", + "node:tty", + "node:v8", + "node:vm", + "node:wasi", + "node:worker_threads", + "node:sea", + "node:sqlite", + "node:test/reporters", +]; diff --git a/src/presets/cloudflare/unenv/preset.ts b/src/presets/cloudflare/unenv/preset.ts new file mode 100644 index 0000000000..4b61ecc0d3 --- /dev/null +++ b/src/presets/cloudflare/unenv/preset.ts @@ -0,0 +1,38 @@ +import type { Preset } from "unenv"; +import * as workerdNodeCompat from "./node-compat.ts"; + +// https://platform-node-compat.pi0.workers.dev/ + +export const unenvCfNodeCompat: Preset = { + meta: { + name: "nitro:cloudflare-node-compat", + }, + external: workerdNodeCompat.builtnNodeModules, + alias: { + ...Object.fromEntries( + workerdNodeCompat.builtnNodeModules.flatMap((m) => [ + [m, m], + [m.replace("node:", ""), m], + ]) + ), + }, + inject: { + global: "unenv/polyfill/globalthis", + process: "node:process", + clearImmediate: ["node:timers", "clearImmediate"], + setImmediate: ["node:timers", "setImmediate"], + Buffer: ["node:buffer", "Buffer"], + }, +}; + +export const unenvCfExternals: Preset = { + meta: { + name: "nitro:cloudflare-externals", + }, + external: [ + "cloudflare:email", + "cloudflare:sockets", + "cloudflare:workers", + "cloudflare:workflows", + ], +}; diff --git a/src/presets/cloudflare/utils.ts b/src/presets/cloudflare/utils.ts index bb3c4e8973..234d21e9eb 100644 --- a/src/presets/cloudflare/utils.ts +++ b/src/presets/cloudflare/utils.ts @@ -1,14 +1,13 @@ -import type { Nitro } from "nitropack/types"; -import type { Plugin } from "rollup"; -import type { WranglerConfig, CloudflarePagesRoutes } from "./types"; +import type { Nitro } from "nitro/types"; +import type { WranglerConfig, CloudflarePagesRoutes } from "./types.ts"; import { existsSync } from "node:fs"; import { readFile } from "node:fs/promises"; import { relative, dirname, extname } from "node:path"; -import { writeFile } from "nitropack/kit"; +import { writeFile } from "../_utils/fs.ts"; import { parseTOML, parseJSONC } from "confbox"; import { readGitConfig, readPackageJSON, findNearestFile } from "pkg-types"; import { defu } from "defu"; -import { globby } from "globby"; +import { glob } from "tinyglobby"; import { join, resolve } from "pathe"; import { joinURL, @@ -17,10 +16,7 @@ import { withTrailingSlash, withoutLeadingSlash, } from "ufo"; -import { - workerdHybridNodeCompatPlugin, - unenvWorkerdWithNodeCompat, -} from "../_unenv/preset-workerd"; +import { unenvCfNodeCompat } from "./unenv/preset.ts"; export async function writeCFRoutes(nitro: Nitro) { const _cfPagesConfig = nitro.options.cloudflare?.pages || {}; @@ -43,23 +39,19 @@ export async function writeCFRoutes(nitro: Nitro) { } // Exclude public assets from hitting the worker - const explicitPublicAssets = nitro.options.publicAssets.filter( - (dir, index, array) => { - if (dir.fallthrough || !dir.baseURL) { - return false; - } + const explicitPublicAssets = nitro.options.publicAssets.filter((dir, index, array) => { + if (dir.fallthrough || !dir.baseURL) { + return false; + } - const normalizedBase = withoutLeadingSlash(dir.baseURL); + const normalizedBase = withoutLeadingSlash(dir.baseURL); - return !array.some( - (otherDir, otherIndex) => - otherIndex !== index && - normalizedBase.startsWith( - withoutLeadingSlash(withTrailingSlash(otherDir.baseURL)) - ) - ); - } - ); + return !array.some( + (otherDir, otherIndex) => + otherIndex !== index && + normalizedBase.startsWith(withoutLeadingSlash(withTrailingSlash(otherDir.baseURL))) + ); + }); // Explicit prefixes routes.exclude!.push( @@ -69,7 +61,7 @@ export async function writeCFRoutes(nitro: Nitro) { ); // Unprefixed assets - const publicAssetFiles = await globby("**", { + const publicAssetFiles = await glob("**", { cwd: nitro.options.output.dir, absolute: false, dot: true, @@ -77,9 +69,7 @@ export async function writeCFRoutes(nitro: Nitro) { "_worker.js", "_worker.js.map", "nitro.json", - ...routes.exclude!.map((path) => - withoutLeadingSlash(path.replace(/\/\*$/, "/**")) - ), + ...routes.exclude!.map((path) => withoutLeadingSlash(path.replace(/\/\*$/, "/**"))), ], }); // Remove index.html or the .html extension to support pages pre-rendering @@ -104,17 +94,18 @@ function comparePaths(a: string, b: string) { return a.split("/").length - b.split("/").length || a.localeCompare(b); } -export async function writeCFPagesHeaders(nitro: Nitro) { - const headersPath = join(nitro.options.output.dir, "_headers"); +export async function writeCFHeaders(nitro: Nitro, outdir: "public" | "output") { + const headersPath = join( + outdir === "public" ? nitro.options.output.publicDir : nitro.options.output.dir, + "_headers" + ); const contents = []; const rules = Object.entries(nitro.options.routeRules).sort( (a, b) => b[0].split(/\/(?!\*)/).length - a[0].split(/\/(?!\*)/).length ); - for (const [path, routeRules] of rules.filter( - ([_, routeRules]) => routeRules.headers - )) { + for (const [path, routeRules] of rules.filter(([_, routeRules]) => routeRules.headers)) { const headers = [ joinURL(nitro.options.baseURL, path.replace("/**", "/*")), ...Object.entries({ ...routeRules.headers }).map( @@ -133,9 +124,7 @@ export async function writeCFPagesHeaders(nitro: Nitro) { ); return; } - nitro.logger.info( - "Adding Nitro fallback to `_headers` to handle all unmatched routes." - ); + nitro.logger.info("Adding Nitro fallback to `_headers` to handle all unmatched routes."); contents.unshift(currentHeaders); } @@ -144,9 +133,7 @@ export async function writeCFPagesHeaders(nitro: Nitro) { export async function writeCFPagesRedirects(nitro: Nitro) { const redirectsPath = join(nitro.options.output.dir, "_redirects"); - const staticFallback = existsSync( - join(nitro.options.output.publicDir, "404.html") - ) + const staticFallback = existsSync(join(nitro.options.output.publicDir, "404.html")) ? `${joinURL(nitro.options.baseURL, "/*")} ${joinURL(nitro.options.baseURL, "/404.html")} 404` : ""; const contents = [staticFallback]; @@ -154,10 +141,8 @@ export async function writeCFPagesRedirects(nitro: Nitro) { (a, b) => a[0].split(/\/(?!\*)/).length - b[0].split(/\/(?!\*)/).length ); - for (const [key, routeRules] of rules.filter( - ([_, routeRules]) => routeRules.redirect - )) { - const code = routeRules.redirect!.statusCode; + for (const [key, routeRules] of rules.filter(([_, routeRules]) => routeRules.redirect)) { + const code = routeRules.redirect!.status; const from = joinURL(nitro.options.baseURL, key.replace("/**", "/*")); const to = hasProtocol(routeRules.redirect!.to, { acceptRelative: true }) ? routeRules.redirect!.to @@ -173,9 +158,7 @@ export async function writeCFPagesRedirects(nitro: Nitro) { ); return; } - nitro.logger.info( - "Adding Nitro fallback to `_redirects` to handle all unmatched routes." - ); + nitro.logger.info("Adding Nitro fallback to `_redirects` to handle all unmatched routes."); contents.unshift(currentRedirects); } @@ -183,35 +166,17 @@ export async function writeCFPagesRedirects(nitro: Nitro) { } export async function enableNodeCompat(nitro: Nitro) { - // Infer nodeCompat from user config - if (nitro.options.cloudflare?.nodeCompat === undefined) { - const { config } = await readWranglerConfig(nitro); - const userCompatibilityFlags = new Set(config?.compatibility_flags || []); - if ( - userCompatibilityFlags.has("nodejs_compat") || - userCompatibilityFlags.has("nodejs_compat_v2") - ) { - nitro.options.cloudflare ??= {}; - nitro.options.cloudflare.nodeCompat = true; - } - } + nitro.options.cloudflare ??= {}; - if (!nitro.options.cloudflare?.nodeCompat) { - if (nitro.options.cloudflare?.nodeCompat === undefined) { - nitro.logger.warn("[cloudflare] Node.js compatibility is not enabled."); - } - return; + nitro.options.cloudflare.deployConfig ??= true; + nitro.options.cloudflare.nodeCompat ??= true; + if (nitro.options.cloudflare.nodeCompat) { + nitro.options.unenv.push(unenvCfNodeCompat); } - - nitro.options.unenv.push(unenvWorkerdWithNodeCompat); - nitro.options.rollupConfig!.plugins ??= []; - (nitro.options.rollupConfig!.plugins as Plugin[]).push( - workerdHybridNodeCompatPlugin - ); } const extensionParsers = { - ".json": JSON.parse, + ".json": parseJSONC, ".jsonc": parseJSONC, ".toml": parseTOML, } as const; @@ -219,18 +184,14 @@ const extensionParsers = { async function readWranglerConfig( nitro: Nitro ): Promise<{ configPath?: string; config?: WranglerConfig }> { - const configPath = await findNearestFile( - ["wrangler.json", "wrangler.jsonc", "wrangler.toml"], - { - startingFrom: nitro.options.rootDir, - } - ).catch(() => undefined); + const configPath = await findNearestFile(["wrangler.json", "wrangler.jsonc", "wrangler.toml"], { + startingFrom: nitro.options.rootDir, + }).catch(() => undefined); if (!configPath) { return {}; } const userConfigText = await readFile(configPath, "utf8"); - const parser = - extensionParsers[extname(configPath) as keyof typeof extensionParsers]; + const parser = extensionParsers[extname(configPath) as keyof typeof extensionParsers]; if (!parser) { /* unreachable */ throw new Error(`Unsupported config file format: ${configPath}`); @@ -240,10 +201,7 @@ async function readWranglerConfig( } // https://developers.cloudflare.com/workers/wrangler/configuration/#generated-wrangler-configuration -export async function writeWranglerConfig( - nitro: Nitro, - cfTarget: "pages" | "module" -) { +export async function writeWranglerConfig(nitro: Nitro, cfTarget: "pages" | "module") { // Skip if not enabled if (!nitro.options.cloudflare?.deployConfig) { return; @@ -261,24 +219,23 @@ export async function writeWranglerConfig( // Compatibility date defaults.compatibility_date = - nitro.options.compatibilityDate.cloudflare || - nitro.options.compatibilityDate.default; + nitro.options.compatibilityDate.cloudflare || nitro.options.compatibilityDate.default; if (cfTarget === "pages") { // Pages - overrides.pages_build_output_dir = relative( - wranglerConfigDir, - nitro.options.output.dir - ); + overrides.pages_build_output_dir = relative(wranglerConfigDir, nitro.options.output.dir); } else { // Modules - overrides.main = relative( - wranglerConfigDir, - join(nitro.options.output.serverDir, "index.mjs") - ); + overrides.main = relative(wranglerConfigDir, join(nitro.options.output.serverDir, "index.mjs")); overrides.assets = { binding: "ASSETS", - directory: relative(wranglerConfigDir, nitro.options.output.publicDir), + directory: relative( + wranglerConfigDir, + resolve( + nitro.options.output.publicDir, + "..".repeat(nitro.options.baseURL.split("/").filter(Boolean).length) + ) + ), }; } @@ -298,57 +255,59 @@ export async function writeWranglerConfig( } // (first argument takes precedence) - const wranglerConfig = defu( - overrides, - ctxConfig, - userConfig, - defaults - ) as WranglerConfig; + const wranglerConfig = defu(overrides, ctxConfig, userConfig, defaults) as WranglerConfig; // Name is required if (!wranglerConfig.name) { wranglerConfig.name = await generateWorkerName(nitro)!; - nitro.logger.info( - `Using auto generated worker name: \`${wranglerConfig.name}\`` - ); + nitro.logger.info(`Using auto generated worker name: \`${wranglerConfig.name}\``); } // Compatibility flags - // prettier-ignore - const compatFlags = new Set(wranglerConfig.compatibility_flags || []) - if (nitro.options.cloudflare?.nodeCompat) { - if ( - compatFlags.has("nodejs_compat_v2") && - compatFlags.has("no_nodejs_compat_v2") - ) { - nitro.logger.warn( - "[cloudflare] Wrangler config `compatibility_flags` contains both `nodejs_compat_v2` and `no_nodejs_compat_v2`. Ignoring `nodejs_compat_v2`." - ); - compatFlags.delete("nodejs_compat_v2"); + wranglerConfig.compatibility_flags ??= []; + if ( + nitro.options.cloudflare?.nodeCompat && + !wranglerConfig.compatibility_flags.includes("nodejs_compat") + ) { + wranglerConfig.compatibility_flags.push("nodejs_compat"); + } + + if (cfTarget === "module") { + // Avoid double bundling + if (wranglerConfig.no_bundle === undefined) { + wranglerConfig.no_bundle = true; } - if (compatFlags.has("nodejs_compat_v2")) { - nitro.logger.warn( - "[cloudflare] Please consider replacing `nodejs_compat_v2` with `nodejs_compat` in your `compatibility_flags` or USE IT AT YOUR OWN RISK as it can cause issues with nitro." - ); - } else { - // Add default compatibility flags - compatFlags.add("nodejs_compat"); - compatFlags.add("no_nodejs_compat_v2"); + + // Scan all server/ chunks + wranglerConfig.rules ??= []; + if (!wranglerConfig.rules.some((rule) => rule.type === "ESModule")) { + wranglerConfig.rules.push({ + type: "ESModule", + globs: ["**/*.mjs", "**/*.js"], + }); + } + } + + // Nitro Tasks cron triggers + if ( + nitro.options.experimental.tasks && + Object.keys(nitro.options.scheduledTasks || {}).length > 0 && + cfTarget !== "pages" + ) { + const schedules = Object.keys(nitro.options.scheduledTasks!); + wranglerConfig.triggers = defu(wranglerConfig.triggers, { crons: [] }); + const existingCrons = new Set(wranglerConfig.triggers!.crons); + for (const schedule of schedules) { + if (!existingCrons.has(schedule)) { + wranglerConfig.triggers!.crons!.push(schedule); + } } } - wranglerConfig.compatibility_flags = [...compatFlags]; // Write wrangler.json - await writeFile( - wranglerConfigPath, - JSON.stringify(wranglerConfig, null, 2), - true - ); + await writeFile(wranglerConfigPath, JSON.stringify(wranglerConfig, null, 2), true); - const configPath = join( - nitro.options.rootDir, - ".wrangler/deploy/config.json" - ); + const configPath = join(nitro.options.rootDir, ".wrangler/deploy/config.json"); await writeFile( configPath, @@ -360,18 +319,15 @@ export async function writeWranglerConfig( } async function generateWorkerName(nitro: Nitro) { - const gitConfig = await readGitConfig(nitro.options.rootDir).catch( - () => undefined - ); + const gitConfig = await readGitConfig(nitro.options.rootDir).catch(() => undefined); const gitRepo = gitConfig?.remote?.origin?.url ?.replace(/\.git$/, "") .match(/[/:]([^/]+\/[^/]+)$/)?.[1]; - const pkgJSON = await readPackageJSON(nitro.options.rootDir).catch( - () => undefined - ); + const pkgJSON = await readPackageJSON(nitro.options.rootDir).catch(() => undefined); const pkgName = pkgJSON?.name; const subpath = relative(nitro.options.workspaceDir, nitro.options.rootDir); return `${gitRepo || pkgName}/${subpath}` + .toLowerCase() .replace(/[^a-zA-Z0-9-]/g, "-") .replace(/-$/, ""); } diff --git a/src/presets/cloudflare/wrangler/_utils.ts b/src/presets/cloudflare/wrangler/_utils.ts index f3289a90e7..f25a827b66 100644 --- a/src/presets/cloudflare/wrangler/_utils.ts +++ b/src/presets/cloudflare/wrangler/_utils.ts @@ -11,6 +11,4 @@ type CamelCase = string extends S ? `${T}${PascalCase}` : S; -export type CamelCaseKey = K extends string - ? Exclude, ""> - : K; +export type CamelCaseKey = K extends string ? Exclude, ""> : K; diff --git a/src/presets/cloudflare/wrangler/config.ts b/src/presets/cloudflare/wrangler/config.ts index ba98b1aa23..902f28c9c3 100644 --- a/src/presets/cloudflare/wrangler/config.ts +++ b/src/presets/cloudflare/wrangler/config.ts @@ -6,8 +6,8 @@ * Source: https://github.com/cloudflare/workers-sdk/blob/main/packages/wrangler/src/config/config.ts */ -import type { Environment, RawEnvironment } from "./environment"; -import type { CamelCaseKey } from "./_utils"; +import type { Environment, RawEnvironment } from "./environment.ts"; +import type { CamelCaseKey } from "./_utils.ts"; /** * This is the static type definition for the configuration object. @@ -30,10 +30,7 @@ import type { CamelCaseKey } from "./_utils"; * - `@breaking`: the deprecation/optionality is a breaking change from Wrangler v1. * - `@todo`: there's more work to be done (with details attached). */ -export type Config = ComputedFields & - ConfigFields & - PagesConfigFields & - Environment; +export type Config = ComputedFields & ConfigFields & PagesConfigFields & Environment; export type RawConfig = Partial> & PagesConfigFields & diff --git a/src/presets/cloudflare/wrangler/environment.ts b/src/presets/cloudflare/wrangler/environment.ts index e442a83ce9..208418ce2d 100644 --- a/src/presets/cloudflare/wrangler/environment.ts +++ b/src/presets/cloudflare/wrangler/environment.ts @@ -12,9 +12,7 @@ * * This could be the top-level default environment, or a specific named environment. */ -export interface Environment - extends EnvironmentInheritable, - EnvironmentNonInheritable {} +export interface Environment extends EnvironmentInheritable, EnvironmentNonInheritable {} type SimpleRoute = string; export type ZoneIdRoute = { @@ -28,11 +26,7 @@ export type ZoneNameRoute = { custom_domain?: boolean; }; export type CustomDomainRoute = { pattern: string; custom_domain: boolean }; -export type Route = - | SimpleRoute - | ZoneIdRoute - | ZoneNameRoute - | CustomDomainRoute; +export type Route = SimpleRoute | ZoneIdRoute | ZoneNameRoute | CustomDomainRoute; /** * Configuration in wrangler for Cloudchamber @@ -40,6 +34,7 @@ export type Route = export type CloudchamberConfig = { image?: string; location?: string; + instance_type?: "dev" | "basic" | "standard"; vcpu?: number; memory?: string; ipv4?: boolean; @@ -51,24 +46,107 @@ export type CloudchamberConfig = { export type ContainerApp = { // TODO: fill out the entire type - /* Name of the application*/ - name: string; - /* Number of application instances */ - instances: number; - /* The scheduling policy of the application, default is regional */ - scheduling_policy?: "regional" | "moon"; - /* Configuration of the container */ - configuration: { - image: string; + /** + * Name of the application + * @optional Defaults to `worker_name-class_name` if not specified. + */ + name?: string; + + /** + * Number of application instances + * @deprecated + * @hidden + */ + instances?: number; + + /** + * Number of maximum application instances. + * @optional + */ + max_instances?: number; + + /** + * The path to a Dockerfile, or an image URI for the Cloudflare registry. + */ + image: string; + + /** + * Build context of the application. + * @optional - defaults to the directory of `image`. + */ + image_build_context?: string; + + /** + * Image variables to be passed along the image at build time. + * @optional + */ + image_vars?: Record; + + /** + * The class name of the Durable Object the container is connected to. + */ + class_name: string; + + /** + * The scheduling policy of the application + * @optional + * @default "default" + */ + scheduling_policy?: "regional" | "moon" | "default"; + + /** + * The instance type to be used for the container. This sets preconfigured options for vcpu and memory + * @optional + */ + instance_type?: "dev" | "basic" | "standard"; + + /** + * @deprecated Use top level `containers` fields instead. + * `configuration.image` should be `image` + * `configuration.disk` should be set via `instance_type` + * @hidden + */ + configuration?: { + image?: string; labels?: { name: string; value: string }[]; secrets?: { name: string; type: "env"; secret: string }[]; + disk?: { size: string }; }; - /* Scheduling constraints */ + + /** + * Scheduling constraints + * @hidden + */ constraints?: { regions?: string[]; cities?: string[]; tier?: number; }; + + /** + * @deprecated use the `class_name` field instead. + * @hidden + */ + durable_objects?: { + namespace_id: string; + }; + + /** + * How a rollout should be done, defining the size of it + * @optional + * @default 25 + * */ + rollout_step_percentage?: number; + + /** + * How a rollout should be created. It supports the following modes: + * - full_auto: The container application will be rolled out fully automatically. + * - none: The container application won't have a roll out or update. + * - manual: The container application will be rollout fully by manually actioning progress steps. + * @optional + * @default "full_auto" + */ + rollout_kind?: "full_auto" | "none" | "full_manual"; }; /** @@ -117,7 +195,7 @@ interface EnvironmentInheritable { * A date in the form yyyy-mm-dd, which will be used to determine * which version of the Workers runtime is used. * - * More details at https://developers.cloudflare.com/workers/platform/compatibility-dates + * More details at https://developers.cloudflare.com/workers/configuration/compatibility-dates * * @inheritable */ @@ -127,7 +205,7 @@ interface EnvironmentInheritable { * A list of flags that enable features from upcoming features of * the Workers runtime, usually used together with compatibility_date. * - * More details at https://developers.cloudflare.com/workers/platform/compatibility-flags + * More details at https://developers.cloudflare.com/workers/configuration/compatibility-flags/ * * @default [] * @inheritable @@ -174,6 +252,7 @@ interface EnvironmentInheritable { * Whether we use ..workers.dev to * test and deploy your Worker. * + * For reference, see https://developers.cloudflare.com/workers/wrangler/configuration/#workersdev * * @default true * @breaking @@ -197,6 +276,8 @@ interface EnvironmentInheritable { * * Only required when workers_dev is false, and there's no scheduled Worker (see `triggers`) * + * For reference, see https://developers.cloudflare.com/workers/wrangler/configuration/#types-of-routes + * * @inheritable */ routes: Route[] | undefined; @@ -254,28 +335,19 @@ interface EnvironmentInheritable { * * More details here https://developers.cloudflare.com/workers/platform/cron-triggers * - * @default {crons:[]} - * @inheritable - */ - triggers: { crons: string[] }; - - /** - * Specifies the Usage Model for your Worker. There are two options - - * [bundled](https://developers.cloudflare.com/workers/platform/limits#bundled-usage-model) and - * [unbound](https://developers.cloudflare.com/workers/platform/limits#unbound-usage-model). - * For newly created Workers, if the Usage Model is omitted - * it will be set to the [default Usage Model set on the account](https://dash.cloudflare.com/?account=workers/default-usage-model). - * For existing Workers, if the Usage Model is omitted, it will be - * set to the Usage Model configured in the dashboard for that Worker. + * For reference, see https://developers.cloudflare.com/workers/wrangler/configuration/#triggers * + * @default {crons: undefined} * @inheritable */ - usage_model: "bundled" | "unbound" | undefined; + triggers: { crons: string[] | undefined }; /** * Specify limits for runtime behavior. * Only supported for the "standard" Usage Model * + * For reference, see https://developers.cloudflare.com/workers/wrangler/configuration/#limits + * * @inheritable */ limits: UserLimits | undefined; @@ -286,6 +358,8 @@ interface EnvironmentInheritable { * to use Text, Data, and CompiledWasm modules, or when you wish to * have a .js file be treated as an ESModule instead of CommonJS. * + * For reference, see https://developers.cloudflare.com/workers/wrangler/configuration/#bundling + * * @inheritable */ rules: Rule[]; @@ -296,6 +370,8 @@ interface EnvironmentInheritable { * Refer to the [custom builds documentation](https://developers.cloudflare.com/workers/cli-wrangler/configuration#build) * for more details. * + * For reference, see https://developers.cloudflare.com/workers/wrangler/configuration/#custom-builds + * * @default {watch_dir:"./src"} */ build: { @@ -305,11 +381,6 @@ interface EnvironmentInheritable { cwd?: string; /** The directory to watch for changes while using wrangler dev, defaults to the current working directory */ watch_dir?: string | string[]; - /** - * Deprecated field previously used to configure the build and upload of the script. - * @deprecated - */ - upload?: DeprecatedUpload; }; /** @@ -325,10 +396,14 @@ interface EnvironmentInheritable { minify: boolean | undefined; /** - * Add polyfills for node builtin modules and globals + * Set the `name` property to the original name for functions and classes renamed during minification. + * + * See https://esbuild.github.io/api/#keep-names + * + * @default true * @inheritable */ - node_compat: boolean | undefined; + keep_names: boolean | undefined; /** * Designates this Worker as an internal-only "first-party" Worker. @@ -337,14 +412,6 @@ interface EnvironmentInheritable { */ first_party_worker: boolean | undefined; - /** - * TODO: remove this as it has been deprecated. - * - * This is just here for now because the `route` commands use it. - * So we need to include it in this type so it is available. - */ - zone_id?: string; - /** * List of bindings that you will send to logfwdr * @@ -374,6 +441,9 @@ interface EnvironmentInheritable { /** * Include source maps when uploading this worker. + * + * For reference, see https://developers.cloudflare.com/workers/wrangler/configuration/#source-maps + * * @inheritable */ upload_source_maps: boolean | undefined; @@ -392,6 +462,8 @@ interface EnvironmentInheritable { * * More details at https://developers.cloudflare.com/workers/frameworks/ * + * For reference, see https://developers.cloudflare.com/workers/wrangler/configuration/#assets + * * @inheritable */ assets: Assets | undefined; @@ -399,9 +471,19 @@ interface EnvironmentInheritable { /** * Specify the observability behavior of the Worker. * + * For reference, see https://developers.cloudflare.com/workers/wrangler/configuration/#observability + * * @inheritable */ observability: Observability | undefined; + + /** + * Specify the compliance region mode of the Worker. + * + * Although if the user does not specify a compliance region, the default is `public`, + * it can be set to `undefined` in configuration to delegate to the CLOUDFLARE_COMPLIANCE_REGION environment variable. + */ + compliance_region: "public" | "fedramp_high" | undefined; } export type DurableObjectBindings = { @@ -424,6 +506,8 @@ export type WorkflowBinding = { class_name: string; /** The script where the Workflow is defined (if it's external to this Worker) */ script_name?: string; + /** Whether the Workflow should be remote or not (only available under `--x-remote-bindings`) */ + experimental_remote?: boolean; }; /** @@ -450,6 +534,8 @@ export interface EnvironmentNonInheritable { * NOTE: This field is not automatically inherited from the top level environment, * and so must be specified in every named environment. * + * For reference, see https://developers.cloudflare.com/workers/wrangler/configuration/#environment-variables + * * @default {} * @nonInheritable */ @@ -464,6 +550,8 @@ export interface EnvironmentNonInheritable { * NOTE: This field is not automatically inherited from the top level environment, * and so must be specified in every named environment. * + * For reference, see https://developers.cloudflare.com/workers/wrangler/configuration/#durable-objects + * * @default {bindings:[]} * @nonInheritable */ @@ -495,19 +583,14 @@ export interface EnvironmentNonInheritable { /** * Container related configuration + * + * NOTE: This field is not automatically inherited from the top level environment, + * and so must be specified in every named environment. + * + * @default [] + * @nonInheritable */ - containers: { - /** - * Container app configuration - * - * NOTE: This field is not automatically inherited from the top level environment, - * and so must be specified in every named environment. - * - * @default {} - * @nonInheritable - */ - app: ContainerApp[]; - }; + containers?: ContainerApp[]; /** * These specify any Workers KV Namespaces you want to @@ -519,6 +602,8 @@ export interface EnvironmentNonInheritable { * NOTE: This field is not automatically inherited from the top level environment, * and so must be specified in every named environment. * + * For reference, see https://developers.cloudflare.com/workers/wrangler/configuration/#kv-namespaces + * * @default [] * @nonInheritable */ @@ -529,6 +614,8 @@ export interface EnvironmentNonInheritable { id?: string; /** The ID of the KV namespace used during `wrangler dev` */ preview_id?: string; + /** Whether the KV namespace should be remote or not (only available under `--x-remote-bindings`) */ + experimental_remote?: boolean; }[]; /** @@ -537,6 +624,8 @@ export interface EnvironmentNonInheritable { * NOTE: This field is not automatically inherited from the top level environment, * and so must be specified in every named environment. * + * For reference, see https://developers.cloudflare.com/workers/wrangler/configuration/#email-bindings + * * @default [] * @nonInheritable */ @@ -555,6 +644,8 @@ export interface EnvironmentNonInheritable { * NOTE: This field is not automatically inherited from the top level environment, * and so must be specified in every named environment. * + * For reference, see https://developers.cloudflare.com/workers/wrangler/configuration/#queues + * * @default {consumers:[],producers:[]} * @nonInheritable */ @@ -569,6 +660,9 @@ export interface EnvironmentNonInheritable { /** The number of seconds to wait before delivering a message */ delivery_delay?: number; + + /** Whether the Queue producer should be remote or not (only available under `--x-remote-bindings`) */ + experimental_remote?: boolean; }[]; /** Consumer configuration */ @@ -608,6 +702,8 @@ export interface EnvironmentNonInheritable { * NOTE: This field is not automatically inherited from the top level environment, * and so must be specified in every named environment. * + * For reference, see https://developers.cloudflare.com/workers/wrangler/configuration/#r2-buckets + * * @default [] * @nonInheritable */ @@ -620,6 +716,8 @@ export interface EnvironmentNonInheritable { preview_bucket_name?: string; /** The jurisdiction that the bucket exists in. Default if not present. */ jurisdiction?: string; + /** Whether the R2 bucket should be remote or not (only available under `--x-remote-bindings`) */ + experimental_remote?: boolean; }[]; /** @@ -628,6 +726,8 @@ export interface EnvironmentNonInheritable { * NOTE: This field is not automatically inherited from the top level environment, * and so must be specified in every named environment. * + * For reference, see https://developers.cloudflare.com/workers/wrangler/configuration/#d1-databases + * * @default [] * @nonInheritable */ @@ -646,6 +746,8 @@ export interface EnvironmentNonInheritable { migrations_dir?: string; /** Internal use only. */ database_internal_env?: string; + /** Whether the D1 database should be remote or not (only available under `--x-remote-bindings`) */ + experimental_remote?: boolean; }[]; /** @@ -654,6 +756,8 @@ export interface EnvironmentNonInheritable { * NOTE: This field is not automatically inherited from the top level environment, * and so must be specified in every named environment. * + * For reference, see https://developers.cloudflare.com/workers/wrangler/configuration/#vectorize-indexes + * * @default [] * @nonInheritable */ @@ -662,6 +766,8 @@ export interface EnvironmentNonInheritable { binding: string; /** The name of the index. */ index_name: string; + /** Whether the Vectorize index should be remote or not (only available under `--x-remote-bindings`) */ + experimental_remote?: boolean; }[]; /** @@ -670,6 +776,8 @@ export interface EnvironmentNonInheritable { * NOTE: This field is not automatically inherited from the top level environment, * and so must be specified in every named environment. * + * For reference, see https://developers.cloudflare.com/workers/wrangler/configuration/#hyperdrive + * * @default [] * @nonInheritable */ @@ -688,6 +796,8 @@ export interface EnvironmentNonInheritable { * NOTE: This field is not automatically inherited from the top level environment, * and so must be specified in every named environment. * + * For reference, see https://developers.cloudflare.com/workers/wrangler/configuration/#service-bindings + * * @default [] * @nonInheritable */ @@ -701,6 +811,10 @@ export interface EnvironmentNonInheritable { environment?: string; /** Optionally, the entrypoint (named export) of the service to bind to. */ entrypoint?: string; + /** Optional properties that will be made available to the service via ctx.props. */ + props?: Record; + /** Whether the service binding should be remote or not (only available under `--x-remote-bindings`) */ + experimental_remote?: boolean; }[] | undefined; @@ -710,6 +824,8 @@ export interface EnvironmentNonInheritable { * NOTE: This field is not automatically inherited from the top level environment, * and so must be specified in every named environment. * + * For reference, see https://developers.cloudflare.com/workers/wrangler/configuration/#analytics-engine-datasets + * * @default [] * @nonInheritable */ @@ -726,12 +842,16 @@ export interface EnvironmentNonInheritable { * NOTE: This field is not automatically inherited from the top level environment, * and so must be specified in every named environment. * + * For reference, see https://developers.cloudflare.com/workers/wrangler/configuration/#browser-rendering + * * @default {} * @nonInheritable */ browser: | { binding: string; + /** Whether the Browser binding should be remote or not (only available under `--x-remote-bindings`) */ + experimental_remote?: boolean; } | undefined; @@ -741,6 +861,8 @@ export interface EnvironmentNonInheritable { * NOTE: This field is not automatically inherited from the top level environment, * and so must be specified in every named environment. * + * For reference, see https://developers.cloudflare.com/workers/wrangler/configuration/#workers-ai + * * @default {} * @nonInheritable */ @@ -748,6 +870,27 @@ export interface EnvironmentNonInheritable { | { binding: string; staging?: boolean; + /** Whether the AI binding should be remote or not (only available under `--x-remote-bindings`) */ + experimental_remote?: boolean; + } + | undefined; + + /** + * Binding to Cloudflare Images + * + * NOTE: This field is not automatically inherited from the top level environment, + * and so must be specified in every named environment. + * + * For reference, see https://developers.cloudflare.com/workers/wrangler/configuration/#images + * + * @default {} + * @nonInheritable + */ + images: + | { + binding: string; + /** Whether the Images binding should be remote or not (only available under `--x-remote-bindings`) */ + experimental_remote?: boolean; } | undefined; @@ -811,6 +954,8 @@ export interface EnvironmentNonInheritable { * NOTE: This field is not automatically inherited from the top level environment, * and so must be specified in every named environment. * + * For reference, see https://developers.cloudflare.com/workers/wrangler/configuration/#mtls-certificates + * * @default [] * @nonInheritable */ @@ -819,6 +964,8 @@ export interface EnvironmentNonInheritable { binding: string; /** The uuid of the uploaded mTLS certificate */ certificate_id: string; + /** Whether the mtls fetcher should be remote or not (only available under `--x-remote-bindings`) */ + experimental_remote?: boolean; }[]; /** @@ -838,6 +985,8 @@ export interface EnvironmentNonInheritable { * NOTE: This field is not automatically inherited from the top level environment, * and so must be specified in every named environment. * + * For reference, see https://developers.cloudflare.com/workers/wrangler/configuration/#dispatch-namespace-bindings-workers-for-platforms + * * @default [] * @nonInheritable */ @@ -848,6 +997,8 @@ export interface EnvironmentNonInheritable { namespace: string; /** Details about the outbound Worker which will handle outbound requests from your namespace */ outbound?: DispatchNamespaceOutbound; + /** Whether the Dispatch Namespace should be remote or not (only available under `--x-remote-bindings`) */ + experimental_remote?: boolean; }[]; /** @@ -866,75 +1017,43 @@ export interface EnvironmentNonInheritable { /** Name of the Pipeline to bind */ pipeline: string; }[]; -} -/** - * The environment configuration properties that have been deprecated. - */ -interface EnvironmentDeprecated { /** - * The zone ID of the zone you want to deploy to. You can find this - * in your domain page on the dashboard. + * Specifies Secret Store bindings that are bound to this Worker environment. * - * @deprecated This is unnecessary since we can deduce this from routes directly. - */ - zone_id?: string; - - /** - * Legacy way of defining KVNamespaces that is no longer supported. - * - * @deprecated DO NOT USE. This was a legacy bug from Wrangler v1, that we do not want to support. - */ - "kv-namespaces"?: string; - - /** - * A list of services that your Worker should be bound to. + * NOTE: This field is not automatically inherited from the top level environment, + * and so must be specified in every named environment. * * @default [] - * @deprecated DO NOT USE. We'd added this to test the new service binding system, but the proper way to test experimental features is to use `unsafe.bindings` configuration. + * @nonInheritable */ - experimental_services?: { - /** The binding name used to refer to the Service */ - name: string; - /** The name of the Service being bound */ - service: string; - /** The Service's environment */ - environment: string; - }[]; -} + secrets_store_secrets: { + /** The binding name used to refer to the bound service. */ + binding: string; -/** - * Deprecated upload configuration. - */ -export interface DeprecatedUpload { - /** - * The format of the Worker script. - * - * @deprecated We infer the format automatically now. - */ - format?: "modules" | "service-worker"; + /** Id of the secret store */ + store_id: string; - /** - * The directory you wish to upload your Worker from, - * relative to the Wrangler configuration file. - * - * Defaults to the directory containing the Wrangler configuration file. - * - * @deprecated - */ - dir?: string; + /** Name of the secret */ + secret_name: string; + }[]; /** - * The path to the Worker script, relative to `upload.dir`. + * **DO NOT USE**. Hello World Binding Config to serve as an explanatory example. + * + * NOTE: This field is not automatically inherited from the top level environment, + * and so must be specified in every named environment. * - * @deprecated This will be replaced by a command line argument. + * @default [] + * @nonInheritable */ - main?: string; + unsafe_hello_world: { + /** The binding name used to refer to the bound service. */ + binding: string; - /** - * @deprecated This is now defined at the top level `rules` field. - */ - rules?: Environment["rules"]; + /** Whether the timer is enabled */ + enable_timer?: boolean; + }[]; } /** @@ -943,7 +1062,7 @@ export interface DeprecatedUpload { * All the properties are optional, and will be replaced with defaults in the configuration that * is used in the rest of the codebase. */ -export type RawEnvironment = Partial & EnvironmentDeprecated; +export type RawEnvironment = Partial; /** * A bundling resolver rule, defining the modules type for paths that match the specified globs. @@ -964,8 +1083,7 @@ export type ConfigModuleRuleType = | "Text" | "Data" | "PythonModule" - | "PythonRequirement" - | "NodeJsCompatModule"; + | "PythonRequirement"; export type TailConsumer = { /** The name of the service tail events will be forwarded to. */ @@ -994,21 +1112,15 @@ export type Assets = { /** Name of `env` binding property in the User Worker. */ binding?: string; /** How to handle HTML requests. */ - html_handling?: - | "auto-trailing-slash" - | "force-trailing-slash" - | "drop-trailing-slash" - | "none"; + html_handling?: "auto-trailing-slash" | "force-trailing-slash" | "drop-trailing-slash" | "none"; /** How to handle requests that do not match an asset. */ not_found_handling?: "single-page-application" | "404-page" | "none"; /** - * If true, route every request to the User Worker, whether or not it matches an asset. - * If false, then respond to requests that match an asset with that asset directly. - * */ - run_worker_first?: boolean; - - /** Deprecated; Inverse of run_worker_first. Should use run_worker_first instead */ - experimental_serve_directly?: boolean; + * Matches will be routed to the User Worker, and matches to negative rules will go to the Asset Worker. + * + * Can also be `true`, indicating that every request should be routed to the User Worker. + */ + run_worker_first?: string[] | boolean; }; export interface Observability { @@ -1024,3 +1136,14 @@ export interface Observability { invocation_logs?: boolean; }; } + +export type DockerConfiguration = { + /** Socket used by miniflare to communicate with Docker */ + socketPath: string; +}; + +export type ContainerEngine = + | { + localDocker: DockerConfiguration; + } + | string; diff --git a/src/presets/deno/preset-legacy.ts b/src/presets/deno/preset-legacy.ts deleted file mode 100644 index 1c2b10fcac..0000000000 --- a/src/presets/deno/preset-legacy.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { builtinModules } from "node:module"; -import MagicString from "magic-string"; -import { findStaticImports } from "mlly"; -import { defineNitroPreset } from "nitropack/kit"; -import { writeFile } from "nitropack/kit"; -import { isAbsolute, resolve } from "pathe"; - -// nitro/src/rollup/plugin/import-meta.ts -const ImportMetaRe = /import\.meta|globalThis._importMeta_/; - -export const denoServerLegacy = defineNitroPreset( - { - extends: "node-server", - entry: "./runtime/deno-server", - exportConditions: ["deno"], - commands: { - preview: "deno task --config ./deno.json start", - }, - unenv: { - inject: { - global: ["unenv/polyfill/globalthis-global", "default"], - Buffer: ["node:buffer", "Buffer"], - setTimeout: ["node:timers", "setTimeout"], - clearTimeout: ["node:timers", "clearTimeout"], - setInterval: ["node:timers", "setInterval"], - clearInterval: ["node:timers", "clearInterval"], - setImmediate: ["node:timers", "setImmediate"], - clearImmediate: ["node:timers", "clearImmediate"], - // process: ["node:process", "default"], - }, - }, - rollupConfig: { - output: { - hoistTransitiveImports: false, - }, - plugins: [ - { - name: "rollup-plugin-node-deno", - resolveId(id) { - id = id.replace("node:", ""); - if (builtinModules.includes(id)) { - return { - id: `node:${id}`, - moduleSideEffects: false, - external: true, - }; - } - if (isHTTPImport(id)) { - return { - id, - external: true, - }; - } - }, - renderChunk(code) { - const s = new MagicString(code); - const imports = findStaticImports(code); - for (const i of imports) { - if ( - !i.specifier.startsWith(".") && - !isAbsolute(i.specifier) && - !isHTTPImport(i.specifier) && - !i.specifier.startsWith("npm:") - ) { - const specifier = i.specifier.replace("node:", ""); - s.replace( - i.code, - i.code.replace( - new RegExp(`(?['"])${i.specifier}\\k`), - JSON.stringify( - builtinModules.includes(specifier) - ? "node:" + specifier - : "npm:" + specifier - ) - ) - ); - } - } - if (s.hasChanged()) { - return { - code: s.toString(), - map: s.generateMap({ includeContent: true }), - }; - } - }, - }, - { - name: "inject-process", - renderChunk: { - order: "post", - handler(code, chunk) { - if ( - !chunk.isEntry && - (!ImportMetaRe.test(code) || code.includes("ROLLUP_NO_REPLACE")) - ) { - return; - } - - const s = new MagicString(code); - s.prepend( - "import __process__ from 'node:process';globalThis.process=globalThis.process||__process__;" - ); - - return { - code: s.toString(), - map: s.generateMap({ includeContent: true }), - }; - }, - }, - }, - ], - }, - hooks: { - async compiled(nitro) { - // https://deno.com/manual@v1.34.3/getting_started/configuration_file - const denoJSON = { - tasks: { - start: - "deno run --allow-net --allow-read --allow-write --allow-env --unstable-byonm ./server/index.mjs", - }, - }; - await writeFile( - resolve(nitro.options.output.dir, "deno.json"), - JSON.stringify(denoJSON, null, 2) - ); - }, - }, - }, - { - name: "deno-server-legacy" as const, - aliases: ["deno-server"], - url: import.meta.url, - } -); - -const HTTP_IMPORT_RE = /^(https?:)?\/\//; - -function isHTTPImport(id: string) { - return HTTP_IMPORT_RE.test(id); -} diff --git a/src/presets/deno/preset.ts b/src/presets/deno/preset.ts index 03155f55b5..2b0c0cb140 100644 --- a/src/presets/deno/preset.ts +++ b/src/presets/deno/preset.ts @@ -1,23 +1,25 @@ -import { defineNitroPreset } from "nitropack/kit"; -import { writeFile } from "nitropack/kit"; +import { defineNitroPreset } from "../_utils/preset.ts"; +import { writeFile } from "../_utils/fs.ts"; import { resolve } from "pathe"; -import { unenvDenoPreset } from "../_unenv/preset-deno"; - -import { denoServerLegacy } from "./preset-legacy"; +import { unenvDeno } from "./unenv/preset.ts"; +import { builtinModules } from "node:module"; const denoDeploy = defineNitroPreset( { - entry: "./runtime/deno-deploy", + entry: "./deno/runtime/deno-deploy", + manifest: { + // https://docs.deno.com/deploy/reference/env_vars_and_contexts/#predefined-environment-variables + // https://docs.deno.com/deploy/classic/environment-variables/#default-environment-variables + deploymentId: process.env.DENO_DEPLOYMENT_ID, + }, exportConditions: ["deno"], node: false, - noExternals: true, serveStatic: "deno", commands: { preview: "", - deploy: - "cd ./ && deployctl deploy --project= server/index.ts", + deploy: "cd ./ && deno run -A jsr:@deno/deployctl deploy server/index.ts", }, - unenv: unenvDenoPreset, + unenv: unenvDeno, rollupConfig: { preserveEntrySignatures: false, external: (id) => id.startsWith("https://") || id.startsWith("node:"), @@ -30,21 +32,20 @@ const denoDeploy = defineNitroPreset( }, { name: "deno-deploy" as const, - aliases: ["deno"] as const, - url: import.meta.url, } ); const denoServer = defineNitroPreset( { - extends: "node-server", - entry: "./runtime/deno-server", + entry: "./deno/runtime/deno-server", + serveStatic: true, exportConditions: ["deno"], commands: { - preview: "deno task --config ./deno.json start", + preview: "deno -A ./server/index.mjs", }, rollupConfig: { - external: (id) => id.startsWith("https://"), + external: (id) => + id.startsWith("https://") || id.startsWith("node:") || builtinModules.includes(id), output: { hoistTransitiveImports: false, }, @@ -54,8 +55,7 @@ const denoServer = defineNitroPreset( // https://docs.deno.com/runtime/fundamentals/configuration/ const denoJSON = { tasks: { - start: - "deno run --allow-net --allow-read --allow-write --allow-env --unstable-byonm --unstable-node-globals ./server/index.mjs", + start: "deno run -A ./server/index.mjs", }, }; await writeFile( @@ -66,10 +66,9 @@ const denoServer = defineNitroPreset( }, }, { + aliases: ["deno"], name: "deno-server" as const, - compatibilityDate: "2025-01-30", - url: import.meta.url, } ); -export default [denoServerLegacy, denoDeploy, denoServer] as const; +export default [denoDeploy, denoServer] as const; diff --git a/src/presets/deno/runtime/_deno-env-polyfill.ts b/src/presets/deno/runtime/_deno-env-polyfill.ts deleted file mode 100644 index a11725e20e..0000000000 --- a/src/presets/deno/runtime/_deno-env-polyfill.ts +++ /dev/null @@ -1 +0,0 @@ -Object.assign(process.env, Deno.env.toObject()); diff --git a/src/presets/deno/runtime/deno-deploy.ts b/src/presets/deno/runtime/deno-deploy.ts index 84e19816af..f9c2f48d00 100644 --- a/src/presets/deno/runtime/deno-deploy.ts +++ b/src/presets/deno/runtime/deno-deploy.ts @@ -1,53 +1,31 @@ -import "#nitro-internal-pollyfills"; -import { useNitroApp } from "nitropack/runtime"; - +import "#nitro/virtual/polyfills"; +import type { ServerRequest } from "srvx"; import type { Deno as _Deno } from "@deno/types"; import wsAdapter from "crossws/adapters/deno"; -const nitroApp = useNitroApp(); - -const ws = import.meta._websocket - ? wsAdapter(nitroApp.h3App.websocket) - : undefined; - -Deno.serve((request: Request, info: _Deno.ServeHandlerInfo) => { - // https://crossws.unjs.io/adapters/deno - if ( - import.meta._websocket && - request.headers.get("upgrade") === "websocket" - ) { - return ws!.handleUpgrade(request, info); - } - return handleRequest(request, info); -}); +import { useNitroApp } from "nitro/app"; +import { resolveWebsocketHooks } from "#nitro/runtime/app"; -async function handleRequest(request: Request, info: _Deno.ServeHandlerInfo) { - const url = new URL(request.url); +declare global { + var Deno: typeof _Deno; +} - const headers = new Headers(request.headers); +const nitroApp = useNitroApp(); - // Add client IP address to headers - // (rightmost is most trustable) - headers.append("x-forwarded-for", info.remoteAddr.hostname); +const ws = import.meta._websocket ? wsAdapter({ resolve: resolveWebsocketHooks }) : undefined; - // There is currently no way to know if the request was made over HTTP or HTTPS - // Deno deploy force redirects to HTTPS so we assume HTTPS by default - if (!headers.has("x-forwarded-proto")) { - headers.set("x-forwarded-proto", "https"); - } +// TODO: Migrate to srvx to provide request IP +Deno.serve((denoReq: Request, info: _Deno.ServeHandlerInfo) => { + // srvx compatibility + const req = denoReq as unknown as ServerRequest; + req.runtime ??= { name: "deno" }; + req.runtime.deno ??= { info } as any; + // TODO: Support remoteAddr - // https://deno.land/api?s=Body - let body; - if (request.body) { - body = await request.arrayBuffer(); + // https://crossws.unjs.io/adapters/deno + if (import.meta._websocket && req.headers.get("upgrade") === "websocket") { + return ws!.handleUpgrade(req, info); } - return nitroApp.localFetch(url.pathname + url.search, { - host: url.hostname, - protocol: url.protocol, - headers, - method: request.method, - redirect: request.redirect, - body, - }); -} + return nitroApp.fetch(req); +}); diff --git a/src/presets/deno/runtime/deno-server.ts b/src/presets/deno/runtime/deno-server.ts index 31a50f9aa7..33744b23a0 100644 --- a/src/presets/deno/runtime/deno-server.ts +++ b/src/presets/deno/runtime/deno-server.ts @@ -1,92 +1,47 @@ -import "#nitro-internal-pollyfills"; -import "./_deno-env-polyfill"; -import { useNitroApp } from "nitropack/runtime"; -import { useRuntimeConfig } from "nitropack/runtime"; -import { startScheduleRunner } from "nitropack/runtime/internal"; - -import type { Deno as _Deno } from "@deno/types"; +import "#nitro/virtual/polyfills"; +import type { ServerRequest } from "srvx"; +import { serve } from "srvx/deno"; import wsAdapter from "crossws/adapters/deno"; -import destr from "destr"; - -// TODO: Declare conflict with crossws -declare global { - const Deno: typeof import("@deno/types").Deno; -} -const nitroApp = useNitroApp(); +import { useNitroApp } from "nitro/app"; +import { startScheduleRunner } from "#nitro/runtime/task"; +import { trapUnhandledErrors } from "#nitro/runtime/error/hooks"; +import { resolveWebsocketHooks } from "#nitro/runtime/app"; -if (Deno.env.get("DEBUG")) { - addEventListener("unhandledrejection", (event: any) => - console.error("[unhandledRejection]", event.reason) - ); - addEventListener("error", (event: any) => - console.error("[uncaughtException]", event.error) - ); -} else { - addEventListener("unhandledrejection", (err: any) => - console.error("[unhandledRejection] " + err) - ); - addEventListener("error", (event: any) => - console.error("[uncaughtException] " + event.error) - ); -} +const _parsedPort = Number.parseInt(process.env.NITRO_PORT ?? process.env.PORT ?? ""); +const port = Number.isNaN(_parsedPort) ? 3000 : _parsedPort; -// https://deno.land/api@v1.42.4?s=Deno.serve -const serveOptions: _Deno.ServeOptions & Partial<_Deno.ServeTlsOptions> = { - key: Deno.env.get("NITRO_SSL_KEY"), - cert: Deno.env.get("NITRO_SSL_CERT"), - port: destr(Deno.env.get("NITRO_PORT") || Deno.env.get("PORT")) || 3000, - hostname: Deno.env.get("NITRO_HOST") || Deno.env.get("HOST"), - onListen: (opts) => { - const baseURL = (useRuntimeConfig().app.baseURL || "").replace(/\/$/, ""); - const url = `${opts.hostname}:${opts.port}${baseURL}`; - console.log(`Listening ${url}`); - }, -}; +const host = process.env.NITRO_HOST || process.env.HOST; +const cert = process.env.NITRO_SSL_CERT; +const key = process.env.NITRO_SSL_KEY; +// const socketPath = process.env.NITRO_UNIX_SOCKET; // TODO -// https://github.com/nitrojs/nitro/pull/2373 -if (!serveOptions.key || !serveOptions.cert) { - delete serveOptions.key; - delete serveOptions.cert; -} - -Deno.serve(serveOptions, handler); - -// Websocket support -const ws = import.meta._websocket - ? wsAdapter(nitroApp.h3App.websocket) - : undefined; +const nitroApp = useNitroApp(); -async function handler(request: Request, info: any) { - // https://crossws.unjs.io/adapters/deno - if ( - import.meta._websocket && - request.headers.get("upgrade") === "websocket" - ) { - return ws!.handleUpgrade(request, info); - } +let _fetch = nitroApp.fetch; - const url = new URL(request.url); +if (import.meta._websocket) { + const { handleUpgrade } = wsAdapter({ resolve: resolveWebsocketHooks }); + _fetch = (req: ServerRequest) => { + if (req.headers.get("upgrade") === "websocket") { + return handleUpgrade(req, req.runtime!.deno!.info); + } + return nitroApp.fetch(req); + }; +} - // https://deno.land/api?s=Body - let body; - if (request.body) { - body = await request.arrayBuffer(); - } +const server = serve({ + port, + hostname: host, + tls: cert && key ? { cert, key } : undefined, + fetch: _fetch, +}); - return nitroApp.localFetch(url.pathname + url.search, { - host: url.hostname, - protocol: url.protocol, - headers: request.headers, - method: request.method, - redirect: request.redirect, - body, - }); -} +trapUnhandledErrors(); // Scheduled tasks if (import.meta._tasks) { - startScheduleRunner(); + startScheduleRunner({ waitUntil: server.waitUntil }); } export default {}; diff --git a/src/presets/deno/unenv/node-compat.ts b/src/presets/deno/unenv/node-compat.ts new file mode 100644 index 0000000000..13aab27f07 --- /dev/null +++ b/src/presets/deno/unenv/node-compat.ts @@ -0,0 +1,83 @@ +// Auto generated at 2025-10-05 +// Source: https://platform-node-compat.deno.dev/ +// Do not edit this file manually + +// prettier-ignore +export const builtnNodeModules = [ + "node:_http_agent", + "node:_http_common", // Missing exports: freeParser, isLenient, parsers, prepareError + "node:_http_outgoing", + "node:_http_server", // Missing exports: Server, ServerResponse, httpServerPreClose, kConnectionsCheckingInterval, kServerResponse, setupConnectionsTracking, storeHTTPOptions + "node:_stream_duplex", // Missing exports: from, fromWeb, toWeb + "node:_stream_passthrough", + "node:_stream_readable", // Missing exports: ReadableState, from, fromWeb, toWeb, wrap + "node:_stream_transform", + "node:_stream_writable", // Missing exports: WritableState, fromWeb, toWeb + "node:_tls_common", // Missing exports: SecureContext, translatePeerCertificate + "node:_tls_wrap", + "node:assert", // Missing exports: Assert, CallTracker, partialDeepStrictEqual + "node:assert/strict", // Missing exports: Assert, CallTracker, partialDeepStrictEqual + "node:async_hooks", + "node:buffer", // Missing exports: File, resolveObjectURL + "node:child_process", + "node:cluster", + "node:console", // Missing exports: context, createTask + "node:constants", // Missing exports: O_DIRECT, O_NOATIME, defaultCipherList + "node:crypto", // Missing exports: argon2, argon2Sync, decapsulate, encapsulate + "node:dgram", + "node:diagnostics_channel", // Missing exports: Channel + "node:dns", // Missing exports: getDefaultResultOrder, lookupService, resolveTlsa + "node:dns/promises", // Missing exports: getDefaultResultOrder, lookupService, resolveTlsa + "node:domain", + "node:events", // Missing exports: captureRejections, getMaxListeners, init, usingDomains + "node:fs", // Missing exports: FileReadStream, FileWriteStream, Utf8Stream, fchmod, fchmodSync, fchown, fchownSync, glob, globSync, lchmod, lchmodSync, lchown, lchownSync, mkdtempDisposableSync, openAsBlob + "node:fs/promises", // Missing exports: glob, lchmod, lchown, lutimes, mkdtempDisposable, statfs + "node:http", // Missing exports: CloseEvent, MessageEvent, WebSocket, setMaxIdleHTTPParsers + "node:http2", // Missing exports: performServerHandshake + "node:https", + "node:inspector", // Missing exports: NetworkResources + "node:inspector/promises", // Missing exports: NetworkResources + "node:module", // Missing exports: SourceMap, constants, enableCompileCache, findPackageJSON, flushCompileCache, getCompileCacheDir, getSourceMapsSupport, registerHooks, runMain, setSourceMapsSupport, stripTypeScriptTypes, syncBuiltinESMExports + "node:net", + "node:os", + "node:path", // Missing exports: matchesGlob + "node:path/posix", // Missing exports: matchesGlob + "node:path/win32", // Missing exports: matchesGlob + "node:perf_hooks", // Missing exports: Performance, PerformanceMark, PerformanceMeasure, PerformanceObserverEntryList, PerformanceResourceTiming, createHistogram + "node:process", // Missing exports: availableMemory, binding, config, constrainedMemory, debugPort, domain, execve, exitCode, features, finalization, getActiveResourcesInfo, getgroups, hasUncaughtExceptionCaptureCallback, initgroups, loadEnvFile, moduleLoadList, openStdin, ppid, reallyExit, ref, release, report, resourceUsage, setSourceMapsEnabled, setUncaughtExceptionCaptureCallback, setegid, seteuid, setgid, setgroups, setuid, sourceMapsEnabled, threadCpuUsage, title, unref, uptime + "node:punycode", + "node:querystring", + "node:readline", + "node:readline/promises", + "node:repl", // Missing exports: Recoverable, isValidSyntax, writer + "node:sqlite", // Missing exports: Session, StatementSync, backup + "node:stream", // Missing exports: destroy, promises + "node:stream/consumers", + "node:stream/promises", + "node:stream/web", + "node:string_decoder", + "node:sys", // Missing exports: MIMEParams, MIMEType, diff, getCallSite, getSystemErrorMap, getSystemErrorMessage, parseEnv, setTraceSigInt, transferableAbortController, transferableAbortSignal + "node:test", // Missing exports: assert, only, skip, snapshot, todo + "node:timers", + "node:timers/promises", + "node:tls", // Missing exports: SecureContext, convertALPNProtocols, getCACertificates, setDefaultCACertificates + "node:trace_events", + "node:tty", + "node:url", // Missing exports: URLPattern, fileURLToPathBuffer + "node:util", // Missing exports: MIMEParams, MIMEType, diff, getCallSite, getSystemErrorMap, getSystemErrorMessage, parseEnv, setTraceSigInt, transferableAbortController, transferableAbortSignal + "node:util/types", // Missing exports: isExternal + "node:v8", // Missing exports: GCProfiler, getCppHeapStatistics, isStringOneByteRepresentation, promiseHooks, queryObjects, setHeapSnapshotNearHeapLimit, startupSnapshot + "node:vm", + "node:wasi", + "node:worker_threads", // Missing exports: isInternalThread, isMarkedAsUntransferable, locks, markAsUncloneable, postMessageToThread, threadName + "node:zlib", // Missing exports: ZstdCompress, ZstdDecompress, createZstdCompress, createZstdDecompress, zstdCompress, zstdCompressSync, zstdDecompress, zstdDecompressSync +]; + +// prettier-ignore +export const unsupportedNodeModules = [ + "node:_http_client", + "node:_http_incoming", + "node:_stream_wrap", + "node:sea", + "node:test/reporters", +]; diff --git a/src/presets/deno/unenv/preset.ts b/src/presets/deno/unenv/preset.ts new file mode 100644 index 0000000000..35fa4ba9c8 --- /dev/null +++ b/src/presets/deno/unenv/preset.ts @@ -0,0 +1,27 @@ +import type { Preset } from "unenv"; +import * as denoCompat from "./node-compat.ts"; + +// https://platform-node-compat.deno.dev/ +// https://platform-node-compat.netlify.app/ + +export const unenvDeno: Preset = { + meta: { + name: "nitro:deno", + }, + external: denoCompat.builtnNodeModules.map((m) => `node:${m}`), + alias: { + ...Object.fromEntries( + denoCompat.builtnNodeModules.flatMap((m) => [ + [m, m], + [m.replace("node:", ""), m], + ]) + ), + }, + inject: { + global: "unenv/polyfill/globalthis", + process: "node:process", + clearImmediate: ["node:timers", "clearImmediate"], + setImmediate: ["node:timers", "setImmediate"], + Buffer: ["node:buffer", "Buffer"], + }, +}; diff --git a/src/presets/digitalocean/preset.ts b/src/presets/digitalocean/preset.ts index 5d96755f58..a62bd38fc8 100644 --- a/src/presets/digitalocean/preset.ts +++ b/src/presets/digitalocean/preset.ts @@ -1,12 +1,12 @@ -import { defineNitroPreset } from "nitropack/kit"; +import { defineNitroPreset } from "../_utils/preset.ts"; const digitalOcean = defineNitroPreset( { extends: "node-server", + serveStatic: true, }, { name: "digital-ocean" as const, - url: import.meta.url, } ); diff --git a/src/presets/edgio/preset.ts b/src/presets/edgio/preset.ts deleted file mode 100644 index c44dbc9ac0..0000000000 --- a/src/presets/edgio/preset.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { promises as fsp } from "node:fs"; -import { defineNitroPreset } from "nitropack/kit"; -import { dirname, resolve } from "pathe"; -import type { PackageJson } from "pkg-types"; - -const edgio = defineNitroPreset( - { - extends: "node-server", - commands: { - deploy: "cd ./ && npm run deploy", - preview: "cd ./ && npm run preview", - }, - hooks: { - async compiled(nitro) { - /** - * Output directory structure: - * | .edgio (generated by Edgio CLI) - * | edgio/prod.js - * | public/* - * | server/* - * | edgio.config.js - * | package.json - * | routes.js - */ - - // Write edgio.config.js - await writeFile( - resolve(nitro.options.output.dir, "edgio.config.js"), - `module.exports = ${JSON.stringify( - { - connector: "./edgio", - routes: "./routes.js", - backends: {}, - includeFiles: { - "server/**": true, - }, - }, - null, - 2 - )}` - ); - - // Write routes.js - await writeFile( - resolve(nitro.options.output.dir, "routes.js"), - ` -import { Router } from '@edgio/core/router' -import { isProductionBuild } from '@edgio/core/environment' - -const router = new Router() - -if (isProductionBuild()) { - router.static('public') -} - -router.fallback(({ renderWithApp }) => { renderWithApp() }) - -export default router - `.trim() - ); - - // Write edgio/prod.js - await writeFile( - resolve(nitro.options.output.dir, "edgio/prod.js"), - ` -module.exports = async function entry (port) { - process.env.PORT = process.env.NITRO_PORT = port.toString() - console.log('Starting Edgio server on port', port) - await import('../server/index.mjs') - console.log('Edgio server started') -} - `.trim() - ); - - // Write and prepare package.json for deployment - await writeFile( - resolve(nitro.options.output.dir, "package.json"), - JSON.stringify( - { - name: "nitropack-edgio-output", - version: "1.0.0", - private: true, - scripts: { - build: "npm i && edgio build", - deploy: "npm i && edgio deploy", - start: "npm i && edgio run --production", - preview: "npm i && edgio build && edgio run --production", - }, - devDependencies: { - "@edgio/cli": "^6", - "@edgio/core": "^6", - }, - }, - null, - 2 - ) - ); - await writeFile( - resolve(nitro.options.output.dir, "package-lock.json"), - "" - ); - }, - }, - }, - { - name: "edgio" as const, - aliases: ["layer0"] as const, - url: import.meta.url, - } -); - -export default [edgio] as const; - -async function writeFile(path: string, contents: string) { - await fsp.mkdir(dirname(path), { recursive: true }); - await fsp.writeFile(path, contents, "utf8"); -} diff --git a/src/presets/firebase/preset.ts b/src/presets/firebase/preset.ts index 38c9c04fcb..17d777ae36 100644 --- a/src/presets/firebase/preset.ts +++ b/src/presets/firebase/preset.ts @@ -1,81 +1,11 @@ -import { defineNitroPreset, writeFile } from "nitropack/kit"; -import { version as nitroVersion } from "nitropack/meta"; -import { basename, join, relative } from "pathe"; -import type { Plugin } from "rollup"; -import { genSafeVariableName } from "knitwork"; +import { defineNitroPreset } from "../_utils/preset.ts"; +import { writeFile } from "../_utils/fs.ts"; +import { version as nitroVersion } from "nitro/meta"; +import { join, relative } from "pathe"; import { stringifyYAML } from "confbox"; -import { updatePackageJSON, writeFirebaseConfig } from "./utils"; -import type { - AppHostingOptions, - AppHostingOutputBundleConfig, - FirebaseFunctionsOptions, -} from "./types"; +import type { AppHostingOutputBundleConfig } from "./types.ts"; -export type { FirebaseOptions as PresetOptions } from "./types"; - -const firebase = defineNitroPreset( - { - entry: `./runtime/firebase-gen-{{ firebase.gen }}`, - commands: { - deploy: "npx firebase-tools deploy", - }, - firebase: { - // we need this defined here so it's picked up by the template in firebase's entry - gen: (Number.parseInt(process.env.NITRO_FIREBASE_GEN || "") || - "default") as any, - }, - hooks: { - async compiled(nitro) { - await writeFirebaseConfig(nitro); - await updatePackageJSON(nitro); - }, - "rollup:before": (nitro, rollupConfig) => { - const _gen = (nitro.options.firebase as FirebaseFunctionsOptions) - ?.gen as unknown; - if (!_gen || _gen === "default") { - nitro.logger.warn( - "Neither `firebase.gen` or `NITRO_FIREBASE_GEN` is set. Nitro will default to Cloud Functions 1st generation. It is recommended to set this to the latest generation (currently `2`). Set the version to remove this warning. See https://nitro.build/deploy/providers/firebase for more information." - ); - // Using the gen 1 makes this preset backwards compatible for people already using it - nitro.options.firebase = { gen: 1 }; - } - nitro.options.appConfig.nitro = nitro.options.appConfig.nitro || {}; - nitro.options.appConfig.nitro.firebase = nitro.options.firebase; - - const { serverFunctionName } = nitro.options - .firebase as FirebaseFunctionsOptions; - if ( - serverFunctionName && - serverFunctionName !== genSafeVariableName(serverFunctionName) - ) { - throw new Error( - `\`firebase.serverFunctionName\` must be a valid JS variable name: \`${serverFunctionName}\`` - ); - } - - // Replace __firebaseServerFunctionName__ to actual name in entries - (rollupConfig.plugins as Plugin[]).unshift({ - name: "nitro:firebase", - transform: (code, id) => { - if (basename(id).startsWith("firebase-gen-")) { - return { - code: code.replace( - /__firebaseServerFunctionName__/g, - serverFunctionName || "server" - ), - map: null, - }; - } - }, - } satisfies Plugin); - }, - }, - }, - { - name: "firebase" as const, - url: import.meta.url, - } -); +export type { FirebaseOptions as PresetOptions } from "./types.ts"; const firebaseAppHosting = defineNitroPreset( { @@ -90,19 +20,17 @@ const firebaseAppHosting = defineNitroPreset( version: "v1", runConfig: { runCommand: `node ${relative(nitro.options.rootDir, serverEntry)}`, - ...(nitro.options.firebase as AppHostingOptions)?.appHosting, + ...nitro.options.firebase?.appHosting, }, metadata: { - framework: nitro.options.framework.name || "nitropack", + framework: nitro.options.framework.name || "nitro", frameworkVersion: nitro.options.framework.version || "2.x", - adapterPackageName: "nitropack", + adapterPackageName: "nitro", adapterVersion: nitroVersion, }, outputFiles: { serverApp: { - include: [ - relative(nitro.options.rootDir, nitro.options.output.dir), - ], + include: [relative(nitro.options.rootDir, nitro.options.output.dir)], }, }, } satisfies AppHostingOutputBundleConfig), @@ -114,8 +42,7 @@ const firebaseAppHosting = defineNitroPreset( { name: "firebase-app-hosting" as const, stdName: "firebase_app_hosting", - url: import.meta.url, } ); -export default [firebase, firebaseAppHosting] as const; +export default [firebaseAppHosting] as const; diff --git a/src/presets/firebase/runtime/firebase-gen-1.ts b/src/presets/firebase/runtime/firebase-gen-1.ts deleted file mode 100644 index 0b95edbdfe..0000000000 --- a/src/presets/firebase/runtime/firebase-gen-1.ts +++ /dev/null @@ -1,15 +0,0 @@ -import "#nitro-internal-pollyfills"; -import { useNitroApp } from "nitropack/runtime"; -import { useAppConfig } from "nitropack/runtime"; - -import functions from "firebase-functions"; -import { toNodeListener } from "h3"; - -const nitroApp = useNitroApp(); - -const firebaseConfig = useAppConfig().nitro.firebase; - -export const __firebaseServerFunctionName__ = functions - .region(firebaseConfig.region ?? functions.RESET_VALUE) - .runWith(firebaseConfig.runtimeOptions ?? functions.RESET_VALUE) - .https.onRequest(toNodeListener(nitroApp.h3App)); diff --git a/src/presets/firebase/runtime/firebase-gen-2.ts b/src/presets/firebase/runtime/firebase-gen-2.ts deleted file mode 100644 index 1babf921bc..0000000000 --- a/src/presets/firebase/runtime/firebase-gen-2.ts +++ /dev/null @@ -1,19 +0,0 @@ -import "#nitro-internal-pollyfills"; -import { useNitroApp } from "nitropack/runtime"; -import { useAppConfig } from "nitropack/runtime"; - -import { onRequest } from "firebase-functions/v2/https"; -import { toNodeListener } from "h3"; - -const nitroApp = useNitroApp(); - -const firebaseConfig = useAppConfig().nitro.firebase; - -export const __firebaseServerFunctionName__ = onRequest( - { - // Must be set to public to allow all public requests by default - invoker: "public", - ...firebaseConfig.httpsOptions, - }, - toNodeListener(nitroApp.h3App) -); diff --git a/src/presets/firebase/runtime/firebase-gen-default.ts b/src/presets/firebase/runtime/firebase-gen-default.ts deleted file mode 100644 index 4b5765c612..0000000000 --- a/src/presets/firebase/runtime/firebase-gen-default.ts +++ /dev/null @@ -1,2 +0,0 @@ -// We need this file to detect if the user is not passing a `gen` property -export { __firebaseServerFunctionName__ } from "./firebase-gen-1"; diff --git a/src/presets/firebase/types.ts b/src/presets/firebase/types.ts index b4d9dfdd4a..8151d59d93 100644 --- a/src/presets/firebase/types.ts +++ b/src/presets/firebase/types.ts @@ -1,55 +1,4 @@ -import type { RuntimeOptions, region } from "firebase-functions"; -import type { HttpsOptions } from "firebase-functions/v2/https"; - -export type FirebaseOptions = FirebaseFunctionsOptions | AppHostingOptions; - -// ---- Firebase Functions ---- - -export type FirebaseFunctionsOptions = - | FirebaseOptionsGen1 - | FirebaseOptionsGen2; - -export interface FirebaseOptionsBase { - gen: 1 | 2; - /** - * Firebase functions node runtime version. - * @see https://cloud.google.com/functions/docs/runtime-support - * @see https://cloud.google.com/functions/docs/concepts/nodejs-runtime - */ - nodeVersion?: "22" | "20" | "18" | "16"; - /** - * When deploying multiple apps within the same Firebase project - * you must give your server a unique name in order to avoid overwriting your functions. - * - * @default "server" - */ - serverFunctionName?: string; -} - -export interface FirebaseOptionsGen1 extends FirebaseOptionsBase { - gen: 1; - /** - * Firebase functions 1st generation region passed to `functions.region()`. - */ - region?: Parameters[0]; - /** - * Firebase functions 1st generation runtime options passed to `functions.runWith()`. - */ - runtimeOptions?: RuntimeOptions; -} - -export interface FirebaseOptionsGen2 extends FirebaseOptionsBase { - gen: 2; - /** - * Firebase functions 2nd generation https options passed to `onRequest`. - * @see https://firebase.google.com/docs/reference/functions/2nd-gen/node/firebase-functions.https.httpsoptions - */ - httpsOptions?: HttpsOptions; -} - -// ---- Firebase App Hosting ---- - -export interface AppHostingOptions { +export interface FirebaseOptions { appHosting: Partial; } diff --git a/src/presets/firebase/utils.ts b/src/presets/firebase/utils.ts deleted file mode 100644 index 9e1501051e..0000000000 --- a/src/presets/firebase/utils.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { existsSync } from "node:fs"; -import { writeFile } from "nitropack/kit"; -import type { Nitro } from "nitropack/types"; -import { join, relative } from "pathe"; -import { readPackageJSON, writePackageJSON } from "pkg-types"; -import type { FirebaseFunctionsOptions } from "./types"; - -export async function writeFirebaseConfig(nitro: Nitro) { - const firebaseConfigPath = join(nitro.options.rootDir, "firebase.json"); - if (existsSync(firebaseConfigPath)) { - return; - } - const firebaseConfig = { - functions: { - source: relative(nitro.options.rootDir, nitro.options.output.serverDir), - }, - hosting: [ - { - site: "", - public: relative(nitro.options.rootDir, nitro.options.output.publicDir), - cleanUrls: true, - rewrites: [ - { - source: "**", - function: "server", - }, - ], - }, - ], - }; - await writeFile(firebaseConfigPath, JSON.stringify(firebaseConfig, null, 2)); -} - -export async function updatePackageJSON(nitro: Nitro) { - const packageJSONPath = join(nitro.options.output.serverDir, "package.json"); - const packageJSON = await readPackageJSON(packageJSONPath); - await writePackageJSON(packageJSONPath, { - ...packageJSON, - main: "index.mjs", - dependencies: Object.fromEntries( - Object.entries({ - // Default to "latest" normally they should be overridden with user versions - "firebase-admin": "latest", - "firebase-functions": "latest", - ...packageJSON.dependencies, - }) - .filter((e) => e[0] !== "fsevents") - .sort(([a], [b]) => a.localeCompare(b)) - ), - engines: { - // https://cloud.google.com/functions/docs/concepts/nodejs-runtime - node: - (nitro.options.firebase as FirebaseFunctionsOptions)?.nodeVersion || - "20", - }, - }); -} diff --git a/src/presets/flightcontrol/preset.ts b/src/presets/flightcontrol/preset.ts index 72f78478d5..b3b2598ed9 100644 --- a/src/presets/flightcontrol/preset.ts +++ b/src/presets/flightcontrol/preset.ts @@ -1,12 +1,12 @@ -import { defineNitroPreset } from "nitropack/kit"; +import { defineNitroPreset } from "../_utils/preset.ts"; const flightControl = defineNitroPreset( { extends: "node-server", + serveStatic: true, }, { name: "flight-control" as const, - url: import.meta.url, } ); diff --git a/src/presets/genezio/preset.ts b/src/presets/genezio/preset.ts index 316e39e5d9..eee100d047 100644 --- a/src/presets/genezio/preset.ts +++ b/src/presets/genezio/preset.ts @@ -1,4 +1,4 @@ -import { defineNitroPreset } from "nitropack/kit"; +import { defineNitroPreset } from "../_utils/preset.ts"; const genezio = defineNitroPreset( { @@ -6,7 +6,6 @@ const genezio = defineNitroPreset( }, { name: "genezio" as const, - url: import.meta.url, } ); export default [genezio] as const; diff --git a/src/presets/heroku/preset.ts b/src/presets/heroku/preset.ts index 0dd1346fb0..f4146b013f 100644 --- a/src/presets/heroku/preset.ts +++ b/src/presets/heroku/preset.ts @@ -1,12 +1,12 @@ -import { defineNitroPreset } from "nitropack/kit"; +import { defineNitroPreset } from "../_utils/preset.ts"; const heroku = defineNitroPreset( { extends: "node-server", + serveStatic: true, }, { name: "heroku" as const, - url: import.meta.url, } ); diff --git a/src/presets/iis/preset.ts b/src/presets/iis/preset.ts index ef883cba3d..a0c23c46a5 100644 --- a/src/presets/iis/preset.ts +++ b/src/presets/iis/preset.ts @@ -1,10 +1,11 @@ -import { defineNitroPreset } from "nitropack/kit"; -import type { Nitro } from "nitropack/types"; -import { writeIISFiles, writeIISNodeFiles } from "./utils"; +import { defineNitroPreset } from "../_utils/preset.ts"; +import type { Nitro } from "nitro/types"; +import { writeIISFiles, writeIISNodeFiles } from "./utils.ts"; const iisHandler = defineNitroPreset( { extends: "node-server", + serveStatic: true, hooks: { async compiled(nitro: Nitro) { await writeIISFiles(nitro); @@ -13,14 +14,13 @@ const iisHandler = defineNitroPreset( }, { name: "iis-handler" as const, - aliases: ["iis"] as const, - url: import.meta.url, } ); const iisNode = defineNitroPreset( { extends: "node-server", + serveStatic: true, hooks: { async compiled(nitro: Nitro) { await writeIISNodeFiles(nitro); @@ -29,7 +29,6 @@ const iisNode = defineNitroPreset( }, { name: "iis-node" as const, - url: import.meta.url, } ); diff --git a/src/presets/iis/utils.ts b/src/presets/iis/utils.ts index 28ecb015d8..b634e6d3de 100644 --- a/src/presets/iis/utils.ts +++ b/src/presets/iis/utils.ts @@ -1,22 +1,16 @@ import { existsSync } from "node:fs"; import { readFile } from "node:fs/promises"; import { defu } from "defu"; -import { writeFile } from "nitropack/kit"; -import type { Nitro } from "nitropack/types"; +import { writeFile } from "../_utils/fs.ts"; +import type { Nitro } from "nitro/types"; import { resolve } from "pathe"; export async function writeIISFiles(nitro: Nitro) { - await writeFile( - resolve(nitro.options.output.dir, "web.config"), - await iisXmlTemplate(nitro) - ); + await writeFile(resolve(nitro.options.output.dir, "web.config"), await iisXmlTemplate(nitro)); } export async function writeIISNodeFiles(nitro: Nitro) { - await writeFile( - resolve(nitro.options.output.dir, "web.config"), - await iisnodeXmlTemplate(nitro) - ); + await writeFile(resolve(nitro.options.output.dir, "web.config"), await iisnodeXmlTemplate(nitro)); await writeFile( resolve(nitro.options.output.dir, "index.js"), @@ -99,10 +93,8 @@ async function iisnodeXmlTemplate(nitro: Nitro) { `; if (existsSync(path)) { const fileString = await readFile(path, "utf8"); - const originalWebConfig: Record = - await parseXmlDoc(originalString); - const fileWebConfig: Record = - await parseXmlDoc(fileString); + const originalWebConfig: Record = await parseXmlDoc(originalString); + const fileWebConfig: Record = await parseXmlDoc(fileString); if (nitro.options.iis?.mergeConfig && !nitro.options.iis.overrideConfig) { return buildNewXmlDoc(defu(fileWebConfig, originalWebConfig)); @@ -133,10 +125,8 @@ async function iisXmlTemplate(nitro: Nitro) { `; if (existsSync(path)) { const fileString = await readFile(path, "utf8"); - const originalWebConfig: Record = - await parseXmlDoc(originalString); - const fileWebConfig: Record = - await parseXmlDoc(fileString); + const originalWebConfig: Record = await parseXmlDoc(originalString); + const fileWebConfig: Record = await parseXmlDoc(fileString); if (nitro.options.iis?.mergeConfig && !nitro.options.iis.overrideConfig) { return buildNewXmlDoc(defu(fileWebConfig, originalWebConfig)); @@ -163,9 +153,7 @@ async function parseXmlDoc(xml: string): Promise> { return parsedRecord; } -async function buildNewXmlDoc( - xmlObj: Record -): Promise { +async function buildNewXmlDoc(xmlObj: Record): Promise { const { Builder } = await import("xml2js"); const builder = new Builder(); return builder.buildObject({ ...xmlObj }); diff --git a/src/presets/index.mjs b/src/presets/index.mjs deleted file mode 100644 index 7a3730a23a..0000000000 --- a/src/presets/index.mjs +++ /dev/null @@ -1 +0,0 @@ -export { resolvePreset } from "./_resolve"; diff --git a/src/presets/index.ts b/src/presets/index.ts index 662f17341a..9abaec3935 100644 --- a/src/presets/index.ts +++ b/src/presets/index.ts @@ -1,3 +1,3 @@ -export { resolvePreset } from "./_resolve"; +export { resolvePreset } from "./_resolve.ts"; -export type { PresetOptions, PresetName, PresetNameInput } from "./_types.gen"; +export type { PresetOptions, PresetName, PresetNameInput } from "./_types.gen.ts"; diff --git a/src/presets/koyeb/preset.ts b/src/presets/koyeb/preset.ts index 000194927e..4350947709 100644 --- a/src/presets/koyeb/preset.ts +++ b/src/presets/koyeb/preset.ts @@ -1,12 +1,12 @@ -import { defineNitroPreset } from "nitropack/kit"; +import { defineNitroPreset } from "../_utils/preset.ts"; const koyeb = defineNitroPreset( { extends: "node-server", + serveStatic: true, }, { name: "koyeb" as const, - url: import.meta.url, } ); diff --git a/src/presets/netlify/legacy/preset.ts b/src/presets/netlify/legacy/preset.ts deleted file mode 100644 index cdffee32f3..0000000000 --- a/src/presets/netlify/legacy/preset.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { promises as fsp } from "node:fs"; -import { defineNitroPreset } from "nitropack/kit"; -import type { Nitro } from "nitropack/types"; -import { dirname, join } from "pathe"; -import { deprecateSWR, writeHeaders, writeRedirects } from "./utils"; - -// Netlify functions -const netlify = defineNitroPreset( - { - extends: "aws-lambda", - entry: "./runtime/netlify", - output: { - dir: "{{ rootDir }}/.netlify/functions-internal", - publicDir: "{{ rootDir }}/dist", - }, - rollupConfig: { - output: { - entryFileNames: "server.mjs", - }, - }, - hooks: { - "rollup:before": (nitro: Nitro) => { - deprecateSWR(nitro); - }, - async compiled(nitro: Nitro) { - await writeHeaders(nitro); - await writeRedirects(nitro, "/.netlify/functions/server"); - - if (nitro.options.netlify) { - const configPath = join( - nitro.options.output.dir, - "../deploy/v1/config.json" - ); - await fsp.mkdir(dirname(configPath), { recursive: true }); - await fsp.writeFile( - configPath, - JSON.stringify(nitro.options.netlify), - "utf8" - ); - } - - const functionConfig = { - config: { nodeModuleFormat: "esm" }, - version: 1, - }; - const functionConfigPath = join( - nitro.options.output.serverDir, - "server.json" - ); - await fsp.writeFile(functionConfigPath, JSON.stringify(functionConfig)); - }, - }, - }, - { - name: "netlify-legacy" as const, - aliases: ["netlify"], - url: import.meta.url, - } -); - -// Netlify builder -const netlifyBuilder = defineNitroPreset( - { - extends: "netlify", - entry: "./runtime/netlify-builder", - hooks: { - "rollup:before": (nitro: Nitro) => { - deprecateSWR(nitro); - }, - }, - }, - { - name: "netlify-builder" as const, - url: import.meta.url, - } -); - -// Netlify edge -const netlifyEdge = defineNitroPreset( - { - extends: "base-worker", - entry: "./runtime/netlify-edge", - exportConditions: ["netlify"], - output: { - serverDir: "{{ rootDir }}/.netlify/edge-functions/server", - publicDir: "{{ rootDir }}/dist", - }, - rollupConfig: { - output: { - entryFileNames: "server.js", - format: "esm", - }, - }, - hooks: { - "rollup:before": (nitro: Nitro) => { - deprecateSWR(nitro); - }, - async compiled(nitro: Nitro) { - await writeHeaders(nitro); - await writeRedirects(nitro); - - // https://docs.netlify.com/edge-functions/create-integration/ - const manifest = { - version: 1, - functions: [ - { - path: "/*", - name: "nitro server handler", - function: "server", - generator: `${nitro.options.framework.name}@${nitro.options.framework.version}`, - }, - ], - }; - const manifestPath = join( - nitro.options.rootDir, - ".netlify/edge-functions/manifest.json" - ); - await fsp.mkdir(dirname(manifestPath), { recursive: true }); - await fsp.writeFile(manifestPath, JSON.stringify(manifest, null, 2)); - }, - }, - }, - { - name: "netlify-edge" as const, - url: import.meta.url, - } -); - -const netlifyStatic = defineNitroPreset( - { - extends: "static", - output: { - dir: "{{ rootDir }}/dist", - publicDir: "{{ rootDir }}/dist", - }, - commands: { - preview: "npx serve ./", - }, - hooks: { - "rollup:before": (nitro: Nitro) => { - deprecateSWR(nitro); - }, - async compiled(nitro: Nitro) { - await writeHeaders(nitro); - await writeRedirects(nitro); - }, - }, - }, - { - name: "netlify-static" as const, - url: import.meta.url, - static: true, - } -); - -export default [netlify, netlifyBuilder, netlifyEdge, netlifyStatic] as const; diff --git a/src/presets/netlify/legacy/runtime/_deno-env-polyfill.ts b/src/presets/netlify/legacy/runtime/_deno-env-polyfill.ts deleted file mode 100644 index a11725e20e..0000000000 --- a/src/presets/netlify/legacy/runtime/_deno-env-polyfill.ts +++ /dev/null @@ -1 +0,0 @@ -Object.assign(process.env, Deno.env.toObject()); diff --git a/src/presets/netlify/legacy/runtime/netlify-builder.ts b/src/presets/netlify/legacy/runtime/netlify-builder.ts deleted file mode 100644 index f8abeb52df..0000000000 --- a/src/presets/netlify/legacy/runtime/netlify-builder.ts +++ /dev/null @@ -1,6 +0,0 @@ -import "#nitro-internal-pollyfills"; - -import { builder } from "@netlify/functions"; -import { lambda } from "./netlify-lambda"; - -export const handler = builder(lambda); diff --git a/src/presets/netlify/legacy/runtime/netlify-edge.ts b/src/presets/netlify/legacy/runtime/netlify-edge.ts deleted file mode 100644 index e4a8611b5a..0000000000 --- a/src/presets/netlify/legacy/runtime/netlify-edge.ts +++ /dev/null @@ -1,34 +0,0 @@ -import "#nitro-internal-pollyfills"; -import "./_deno-env-polyfill"; - -import { useNitroApp } from "nitropack/runtime"; -import { isPublicAssetURL } from "#nitro-internal-virtual/public-assets"; - -const nitroApp = useNitroApp(); - -// https://docs.netlify.com/edge-functions/api/ -export default async function netlifyEdge(request: Request, _context: any) { - const url = new URL(request.url); - - if (isPublicAssetURL(url.pathname)) { - return; - } - - if (!request.headers.has("x-forwarded-proto") && url.protocol === "https:") { - request.headers.set("x-forwarded-proto", "https"); - } - - let body; - if (request.body) { - body = await request.arrayBuffer(); - } - - return nitroApp.localFetch(url.pathname + url.search, { - host: url.hostname, - protocol: url.protocol, - headers: request.headers, - method: request.method, - redirect: request.redirect, - body, - }); -} diff --git a/src/presets/netlify/legacy/runtime/netlify-lambda.ts b/src/presets/netlify/legacy/runtime/netlify-lambda.ts deleted file mode 100644 index ddc4c059d5..0000000000 --- a/src/presets/netlify/legacy/runtime/netlify-lambda.ts +++ /dev/null @@ -1,58 +0,0 @@ -import "#nitro-internal-pollyfills"; -import { useNitroApp } from "nitropack/runtime"; -import { - normalizeCookieHeader, - normalizeLambdaIncomingHeaders, - normalizeLambdaOutgoingBody, - normalizeLambdaOutgoingHeaders, -} from "nitropack/runtime/internal"; - -import type { - HandlerContext, - HandlerEvent, - HandlerResponse, -} from "@netlify/functions"; -import { withQuery } from "ufo"; - -const nitroApp = useNitroApp(); - -// Netlify functions uses lambda v1 https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html#http-api-develop-integrations-lambda.v2 -export async function lambda( - event: HandlerEvent, - context: HandlerContext -): Promise { - const query = { - ...event.queryStringParameters, - ...event.multiValueQueryStringParameters, - }; - const url = withQuery(event.path, query); - const method = event.httpMethod || "get"; - - const r = await nitroApp.localCall({ - event, - url, - context, - headers: normalizeLambdaIncomingHeaders(event.headers) as Record< - string, - string | string[] - >, - method, - query, - body: event.isBase64Encoded - ? Buffer.from(event.body || "", "base64") - : event.body, - }); - - const cookies = normalizeCookieHeader(String(r.headers["set-cookie"])); - const awsBody = await normalizeLambdaOutgoingBody(r.body, r.headers); - - return { - statusCode: r.status, - headers: normalizeLambdaOutgoingHeaders(r.headers, true), - body: awsBody.body, - isBase64Encoded: awsBody.type === "binary", - ...(cookies.length > 0 && { - multiValueHeaders: { "set-cookie": cookies }, - }), - }; -} diff --git a/src/presets/netlify/legacy/runtime/netlify.ts b/src/presets/netlify/legacy/runtime/netlify.ts deleted file mode 100644 index a1980fc9ae..0000000000 --- a/src/presets/netlify/legacy/runtime/netlify.ts +++ /dev/null @@ -1,28 +0,0 @@ -import "#nitro-internal-pollyfills"; -import type { Handler } from "@netlify/functions"; -import { getRouteRulesForPath } from "nitropack/runtime/internal"; -import { withQuery } from "ufo"; -import { lambda } from "./netlify-lambda"; - -export const handler: Handler = async function handler(event, context) { - const query = { - ...event.queryStringParameters, - ...event.multiValueQueryStringParameters, - }; - const url = withQuery(event.path, query); - const routeRules = getRouteRulesForPath(url); - - if (routeRules.isr) { - const builder = await import("@netlify/functions").then( - (r) => r.builder || (r as any).default.builder - ); - const ttl = typeof routeRules.isr === "number" ? routeRules.isr : false; - const builderHandler = ttl - ? (((event, context) => - lambda(event, context).then((r) => ({ ...r, ttl }))) as Handler) - : lambda; - return builder(builderHandler)(event, context) as any; - } - - return lambda(event, context); -}; diff --git a/src/presets/netlify/legacy/utils.ts b/src/presets/netlify/legacy/utils.ts deleted file mode 100644 index d5f3cc0e44..0000000000 --- a/src/presets/netlify/legacy/utils.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { existsSync, promises as fsp } from "node:fs"; -import type { Nitro, PublicAssetDir } from "nitropack/types"; -import { join } from "pathe"; -import { joinURL } from "ufo"; -import { isTest } from "std-env"; - -export function generateCatchAllRedirects( - publicAssets: PublicAssetDir[], - catchAllPath?: string -): string { - if (!catchAllPath) return ""; - - return [ - // e.g.: /static/* /static/:splat 200 - // Because of Netlify CDN shadowing - // (https://docs.netlify.com/routing/redirects/rewrites-proxies/#shadowing), - // this config avoids function invocations for all static paths, even 404s. - ...getStaticPaths(publicAssets).map( - (path) => `${path} ${path.replace("/*", "/:splat")} 200` - ), - `/* ${catchAllPath} 200`, - ].join("\n"); -} - -export async function writeRedirects(nitro: Nitro, catchAllPath?: string) { - const redirectsPath = join(nitro.options.output.publicDir, "_redirects"); - const staticFallback = existsSync( - join(nitro.options.output.publicDir, "404.html") - ) - ? "/* /404.html 404" - : ""; - let contents = nitro.options.static - ? staticFallback - : generateCatchAllRedirects(nitro.options.publicAssets, catchAllPath); - - const rules = Object.entries(nitro.options.routeRules).sort( - (a, b) => a[0].split(/\/(?!\*)/).length - b[0].split(/\/(?!\*)/).length - ); - - if (!nitro.options.static) { - // Rewrite static ISR paths to builder functions - for (const [key, value] of rules.filter( - ([_, value]) => value.isr !== undefined - )) { - contents = value.isr - ? `${key.replace("/**", "/*")}\t/.netlify/builders/server 200\n` + - contents - : `${key.replace("/**", "/*")}\t/.netlify/functions/server 200\n` + - contents; - } - } - - for (const [key, routeRules] of rules.filter( - ([_, routeRules]) => routeRules.redirect - )) { - let code = routeRules.redirect!.statusCode; - // TODO: Remove map when netlify support 307/308 - if (code === 307) { - code = 302; - } - if (code === 308) { - code = 301; - } - contents = - `${key.replace("/**", "/*")}\t${routeRules.redirect!.to.replace( - "/**", - "/:splat" - )}\t${code}\n` + contents; - } - - if (existsSync(redirectsPath)) { - const currentRedirects = await fsp.readFile(redirectsPath, "utf8"); - if (/^\/\* /m.test(currentRedirects)) { - nitro.logger.info( - "Not adding Nitro fallback to `_redirects` (as an existing fallback was found)." - ); - return; - } - nitro.logger.info( - "Adding Nitro fallback to `_redirects` to handle all unmatched routes." - ); - contents = currentRedirects + "\n" + contents; - } - - await fsp.writeFile(redirectsPath, contents); -} - -export async function writeHeaders(nitro: Nitro) { - const headersPath = join(nitro.options.output.publicDir, "_headers"); - let contents = ""; - - const rules = Object.entries(nitro.options.routeRules).sort( - (a, b) => b[0].split(/\/(?!\*)/).length - a[0].split(/\/(?!\*)/).length - ); - - for (const [path, routeRules] of rules.filter( - ([_, routeRules]) => routeRules.headers - )) { - const headers = [ - path.replace("/**", "/*"), - ...Object.entries({ ...routeRules.headers }).map( - ([header, value]) => ` ${header}: ${value}` - ), - ].join("\n"); - - contents += headers + "\n"; - } - - if (existsSync(headersPath)) { - const currentHeaders = await fsp.readFile(headersPath, "utf8"); - if (/^\/\* /m.test(currentHeaders)) { - nitro.logger.info( - "Not adding Nitro fallback to `_headers` (as an existing fallback was found)." - ); - return; - } - nitro.logger.info( - "Adding Nitro fallback to `_headers` to handle all unmatched routes." - ); - contents = currentHeaders + "\n" + contents; - } - - await fsp.writeFile(headersPath, contents); -} - -export function getStaticPaths(publicAssets: PublicAssetDir[]): string[] { - return publicAssets - .filter( - (dir) => dir.fallthrough !== true && dir.baseURL && dir.baseURL !== "/" - ) - .map((dir) => joinURL("/", dir.baseURL!, "*")); -} - -export function deprecateSWR(nitro: Nitro) { - if (nitro.options.future.nativeSWR) { - return; - } - let hasLegacyOptions = false; - for (const [_key, value] of Object.entries(nitro.options.routeRules)) { - if (_hasProp(value, "isr")) { - continue; - } - if (value.cache === false) { - value.isr = false; - } - if (_hasProp(value, "static")) { - value.isr = !(value as { static: boolean }).static; - hasLegacyOptions = true; - } - if (value?.cache && _hasProp(value.cache, "swr")) { - value.isr = value.cache.swr; - hasLegacyOptions = true; - } - } - if (hasLegacyOptions && !isTest) { - nitro.logger.warn( - "Nitro now uses `isr` option to configure ISR behavior on Netlify. Backwards-compatible support for `static` and `swr` support with Builder Functions will be removed in the future versions. Set `future.nativeSWR: true` nitro config disable this warning." - ); - } -} - -function _hasProp(obj: any, prop: string) { - return obj && typeof obj === "object" && prop in obj; -} diff --git a/src/presets/netlify/preset.ts b/src/presets/netlify/preset.ts index 1efe3fcaff..849a7fb7cd 100644 --- a/src/presets/netlify/preset.ts +++ b/src/presets/netlify/preset.ts @@ -1,27 +1,36 @@ import { promises as fsp } from "node:fs"; -import { defineNitroPreset } from "nitropack/kit"; -import type { Nitro } from "nitropack/types"; +import { defineNitroPreset } from "../_utils/preset.ts"; +import type { Nitro } from "nitro/types"; +import type { Config, Manifest } from "@netlify/edge-functions"; import { dirname, join } from "pathe"; -import { unenvDenoPreset } from "../_unenv/preset-deno"; -import netlifyLegacyPresets from "./legacy/preset"; +import { unenvDeno } from "../deno/unenv/preset.ts"; import { generateNetlifyFunction, getGeneratorString, getStaticPaths, writeHeaders, writeRedirects, -} from "./utils"; +} from "./utils.ts"; -export type { NetlifyOptions as PresetOptions } from "./types"; +export type { NetlifyOptions as PresetOptions } from "./types.ts"; // Netlify functions const netlify = defineNitroPreset( { - entry: "./runtime/netlify", + entry: "./netlify/runtime/netlify", + manifest: { + deploymentId: process.env.DEPLOY_ID, + }, output: { dir: "{{ rootDir }}/.netlify/functions-internal", publicDir: "{{ rootDir }}/dist/{{ baseURL }}", }, + prerender: { + // Prevents an unnecessary redirect from /page/ to /page when accessing prerendered content. + // Reference: https://answers.netlify.com/t/support-guide-how-can-i-alter-trailing-slash-behaviour-in-my-urls-will-enabling-pretty-urls-help/31191 + // Reference: https://nitro.build/config#prerender + autoSubfolderIndex: false, + }, rollupConfig: { output: { entryFileNames: "main.mjs", @@ -37,17 +46,15 @@ const netlify = defineNitroPreset( generateNetlifyFunction(nitro) ); - if (nitro.options.netlify) { - const configPath = join( - nitro.options.output.dir, - "../deploy/v1/config.json" - ); + if (nitro.options.netlify?.images) { + nitro.options.netlify.config ||= {}; + nitro.options.netlify.config.images ||= nitro.options.netlify?.images; + } + + if (Object.keys(nitro.options.netlify?.config || {}).length > 0) { + const configPath = join(nitro.options.output.dir, "../deploy/v1/config.json"); await fsp.mkdir(dirname(configPath), { recursive: true }); - await fsp.writeFile( - configPath, - JSON.stringify(nitro.options.netlify), - "utf8" - ); + await fsp.writeFile(configPath, JSON.stringify(nitro.options.netlify?.config), "utf8"); } }, }, @@ -55,8 +62,6 @@ const netlify = defineNitroPreset( { name: "netlify" as const, stdName: "netlify", - url: import.meta.url, - compatibilityDate: "2024-05-07", } ); @@ -64,26 +69,35 @@ const netlify = defineNitroPreset( const netlifyEdge = defineNitroPreset( { extends: "base-worker", - entry: "./runtime/netlify-edge", + entry: "./netlify/runtime/netlify-edge", + manifest: { + deploymentId: process.env.DEPLOY_ID, + }, exportConditions: ["netlify"], output: { serverDir: "{{ rootDir }}/.netlify/edge-functions/server", publicDir: "{{ rootDir }}/dist/{{ baseURL }}", }, + prerender: { + // Prevents an unnecessary redirect from /page/ to /page when accessing prerendered content. + // Reference: https://answers.netlify.com/t/support-guide-how-can-i-alter-trailing-slash-behaviour-in-my-urls-will-enabling-pretty-urls-help/31191 + // Reference: https://nitro.build/config#prerender + autoSubfolderIndex: false, + }, rollupConfig: { output: { entryFileNames: "server.js", format: "esm", }, }, - unenv: unenvDenoPreset, + unenv: unenvDeno, hooks: { async compiled(nitro: Nitro) { await writeHeaders(nitro); await writeRedirects(nitro); // https://docs.netlify.com/edge-functions/create-integration/ - const manifest = { + const manifest: Manifest = { version: 1, functions: [ { @@ -91,17 +105,14 @@ const netlifyEdge = defineNitroPreset( excludedPath: getStaticPaths( nitro.options.publicAssets, nitro.options.baseURL - ), + ) as Config["excludedPath"], name: "edge server handler", function: "server", generator: getGeneratorString(nitro), }, ], }; - const manifestPath = join( - nitro.options.rootDir, - ".netlify/edge-functions/manifest.json" - ); + const manifestPath = join(nitro.options.rootDir, ".netlify/edge-functions/manifest.json"); await fsp.mkdir(dirname(manifestPath), { recursive: true }); await fsp.writeFile(manifestPath, JSON.stringify(manifest, null, 2)); }, @@ -109,18 +120,25 @@ const netlifyEdge = defineNitroPreset( }, { name: "netlify-edge" as const, - url: import.meta.url, - compatibilityDate: "2024-05-07", } ); const netlifyStatic = defineNitroPreset( { extends: "static", + manifest: { + deploymentId: process.env.DEPLOY_ID, + }, output: { dir: "{{ rootDir }}/dist", publicDir: "{{ rootDir }}/dist/{{ baseURL }}", }, + prerender: { + // Prevents an unnecessary redirect from /page/ to /page when accessing prerendered content. + // Reference: https://answers.netlify.com/t/support-guide-how-can-i-alter-trailing-slash-behaviour-in-my-urls-will-enabling-pretty-urls-help/31191 + // Reference: https://nitro.build/config#prerender + autoSubfolderIndex: false, + }, commands: { preview: "npx serve ./", }, @@ -135,14 +153,7 @@ const netlifyStatic = defineNitroPreset( name: "netlify-static" as const, stdName: "netlify", static: true, - url: import.meta.url, - compatibilityDate: "2024-05-07", } ); -export default [ - ...netlifyLegacyPresets, - netlify, - netlifyEdge, - netlifyStatic, -] as const; +export default [netlify, netlifyEdge, netlifyStatic] as const; diff --git a/src/presets/netlify/runtime/netlify-edge.ts b/src/presets/netlify/runtime/netlify-edge.ts index 09d85b2c8a..c93d46e498 100644 --- a/src/presets/netlify/runtime/netlify-edge.ts +++ b/src/presets/netlify/runtime/netlify-edge.ts @@ -1,33 +1,28 @@ -import "#nitro-internal-pollyfills"; -import { useNitroApp } from "nitropack/runtime"; -import { isPublicAssetURL } from "#nitro-internal-virtual/public-assets"; +import "#nitro/virtual/polyfills"; +import { useNitroApp } from "nitro/app"; +import { isPublicAssetURL } from "#nitro/virtual/public-assets"; import type { Context } from "@netlify/edge-functions"; +import type { ServerRequest } from "srvx"; const nitroApp = useNitroApp(); // https://docs.netlify.com/edge-functions/api/ -export default async function netlifyEdge(request: Request, _context: Context) { - const url = new URL(request.url); +export default async function netlifyEdge(netlifyReq: Request, context: Context) { + // srvx compatibility + const req = netlifyReq as unknown as ServerRequest; + req.ip = context.ip; + req.runtime ??= { name: "netlify-edge" }; + req.runtime.netlify ??= { context } as any; + + const url = new URL(req.url); if (isPublicAssetURL(url.pathname)) { return; } - if (!request.headers.has("x-forwarded-proto") && url.protocol === "https:") { - request.headers.set("x-forwarded-proto", "https"); - } - - let body; - if (request.body) { - body = await request.arrayBuffer(); + if (!req.headers.has("x-forwarded-proto") && url.protocol === "https:") { + req.headers.set("x-forwarded-proto", "https"); } - return nitroApp.localFetch(url.pathname + url.search, { - host: url.hostname, - protocol: url.protocol, - headers: request.headers, - method: request.method, - redirect: request.redirect, - body, - }); + return nitroApp.fetch(req); } diff --git a/src/presets/netlify/runtime/netlify.ts b/src/presets/netlify/runtime/netlify.ts index c740facbc6..de60d213b3 100644 --- a/src/presets/netlify/runtime/netlify.ts +++ b/src/presets/netlify/runtime/netlify.ts @@ -1,70 +1,32 @@ -import "#nitro-internal-pollyfills"; -import { useNitroApp } from "nitropack/runtime"; -import { - getRouteRulesForPath, - joinHeaders, - normalizeCookieHeader, -} from "nitropack/runtime/internal"; +import "#nitro/virtual/polyfills"; +import { useNitroApp } from "nitro/app"; +import type { ServerRequest } from "srvx"; const nitroApp = useNitroApp(); -const handler = async (req: Request): Promise => { - const url = new URL(req.url); - const relativeUrl = `${url.pathname}${url.search}`; - const r = await nitroApp.localCall({ - url: relativeUrl, - headers: req.headers, - method: req.method, - body: req.body, - }); - - const headers = normalizeResponseHeaders({ - ...getCacheHeaders(url.pathname), - ...r.headers, - }); - - return new Response(r.body, { - status: r.status, - headers, - }); -}; - -export default handler; - -// --- internal utils --- - const ONE_YEAR_IN_SECONDS = 365 * 24 * 60 * 60; -type NitroResponseHeaders = Awaited< - ReturnType<(typeof nitroApp)["localCall"]> ->["headers"]; +const handler = async (req: ServerRequest): Promise => { + req.runtime ??= { name: "netlify" }; + req.ip ??= req.headers.get("x-nf-client-connection-ip") || undefined; -function normalizeResponseHeaders(headers: NitroResponseHeaders): Headers { - const outgoingHeaders = new Headers(); - for (const [name, header] of Object.entries(headers)) { - if (name === "set-cookie") { - for (const cookie of normalizeCookieHeader(header)) { - outgoingHeaders.append("set-cookie", cookie); - } - } else if (header !== undefined) { - outgoingHeaders.set(name, joinHeaders(header)); - } - } - return outgoingHeaders; -} + const response = await nitroApp.fetch(req); -function getCacheHeaders(url: string): Record { - const { isr } = getRouteRulesForPath(url); + const isr = (req.context?.routeRules || {})?.isr?.options; if (isr) { const maxAge = typeof isr === "number" ? isr : ONE_YEAR_IN_SECONDS; const revalidateDirective = - typeof isr === "number" - ? `stale-while-revalidate=${ONE_YEAR_IN_SECONDS}` - : "must-revalidate"; - return { - "Cache-Control": "public, max-age=0, must-revalidate", - "Netlify-CDN-Cache-Control": `public, max-age=${maxAge}, ${revalidateDirective}, durable`, - }; + typeof isr === "number" ? `stale-while-revalidate=${ONE_YEAR_IN_SECONDS}` : "must-revalidate"; + if (!response.headers.has("Cache-Control")) { + response.headers.set("Cache-Control", "public, max-age=0, must-revalidate"); + } + response.headers.set( + "Netlify-CDN-Cache-Control", + `public, max-age=${maxAge}, ${revalidateDirective}, durable` + ); } - return {}; -} + + return response; +}; + +export default handler; diff --git a/src/presets/netlify/types.ts b/src/presets/netlify/types.ts index 9554a50fe4..cf72f79a8b 100644 --- a/src/presets/netlify/types.ts +++ b/src/presets/netlify/types.ts @@ -1,12 +1,84 @@ -/** - * Netlify options - */ +// https://docs.netlify.com/build/frameworks/frameworks-api/ + export interface NetlifyOptions { - images?: { - /** - * Permitted remote image sources. Array of regex strings. - * @see https://docs.netlify.com/image-cdn/overview/#remote-path - */ - remote_images?: string[]; - }; + /** @deprecated Use `config.images` */ + images?: NetlifyImagesConfig; + config?: NetlifyConfigJson; + // skewProtection?: NetlifySkewProtectionJson; + // edgeFunctionsImportMap?: NetlifyImportMapJson; + // blobsMetadata?: Record; +} + +export interface NetlifyConfigJson { + edge_functions?: NetlifyEdgeFunctionDeclaration[]; + functions?: NetlifyFunctionsConfig | NetlifyFunctionsConfigByPattern; + headers?: NetlifyHeaderRule[]; + images?: NetlifyImagesConfig; + redirects?: NetlifyRedirectRule[]; + "redirects!"?: NetlifyRedirectRule[]; +} + +interface NetlifyEdgeFunctionDeclaration { + function: string; + path?: string; + pattern?: string; + excludedPath?: string; + excludedPattern?: string; + cache?: string; + [key: string]: unknown; +} + +interface NetlifyFunctionsConfig extends NetlifyFunctionInlineConfig { + directory?: string; +} + +export type NetlifyFunctionsConfigByPattern = Record; + +interface NetlifyFunctionInlineConfig { + included_files?: string[]; + [key: string]: unknown; +} + +interface NetlifyHeaderRule { + for: string; + values: Record; + [key: string]: unknown; +} + +interface NetlifyImagesConfig { + remote_images?: string[]; + [key: string]: unknown; +} + +interface NetlifyRedirectRule { + from: string; + to: string; + status?: number; + force?: boolean; + conditions?: Record; + query?: Record; + [key: string]: unknown; +} + +export interface NetlifySkewProtectionJson { + patterns: string[]; + sources: NetlifySkewProtectionSource[]; + [key: string]: unknown; +} + +interface NetlifySkewProtectionSource { + type: "cookie" | "header" | "query"; + name: string; + [key: string]: unknown; +} + +export interface NetlifyImportMapJson { + imports?: Record; + scopes?: Record>; + [key: string]: unknown; +} + +export interface NetlifyBlobMetadata { + headers?: Record; + [key: string]: unknown; } diff --git a/src/presets/netlify/utils.ts b/src/presets/netlify/utils.ts index 778ff90a5d..d04c0348be 100644 --- a/src/presets/netlify/utils.ts +++ b/src/presets/netlify/utils.ts @@ -1,5 +1,5 @@ import { existsSync, promises as fsp } from "node:fs"; -import type { Nitro, PublicAssetDir } from "nitropack/types"; +import type { Nitro, PublicAssetDir } from "nitro/types"; import { join } from "pathe"; import { joinURL } from "ufo"; @@ -8,9 +8,7 @@ export async function writeRedirects(nitro: Nitro) { let contents = ""; if (nitro.options.static) { - const staticFallback = existsSync( - join(nitro.options.output.publicDir, "404.html") - ) + const staticFallback = existsSync(join(nitro.options.output.publicDir, "404.html")) ? "/* /404.html 404" : ""; contents += staticFallback; @@ -20,10 +18,8 @@ export async function writeRedirects(nitro: Nitro) { (a, b) => a[0].split(/\/(?!\*)/).length - b[0].split(/\/(?!\*)/).length ); - for (const [key, routeRules] of rules.filter( - ([_, routeRules]) => routeRules.redirect - )) { - let code = routeRules.redirect!.statusCode; + for (const [key, routeRules] of rules.filter(([_, routeRules]) => routeRules.redirect)) { + let code = routeRules.redirect!.status; // TODO: Remove map when netlify support 307/308 if (code === 307) { code = 302; @@ -46,9 +42,7 @@ export async function writeRedirects(nitro: Nitro) { ); return; } - nitro.logger.info( - "Adding Nitro fallback to `_redirects` to handle all unmatched routes." - ); + nitro.logger.info("Adding Nitro fallback to `_redirects` to handle all unmatched routes."); contents = currentRedirects + "\n" + contents; } @@ -63,9 +57,7 @@ export async function writeHeaders(nitro: Nitro) { (a, b) => b[0].split(/\/(?!\*)/).length - a[0].split(/\/(?!\*)/).length ); - for (const [path, routeRules] of rules.filter( - ([_, routeRules]) => routeRules.headers - )) { + for (const [path, routeRules] of rules.filter(([_, routeRules]) => routeRules.headers)) { const headers = [ path.replace("/**", "/*"), ...Object.entries({ ...routeRules.headers }).map( @@ -84,19 +76,14 @@ export async function writeHeaders(nitro: Nitro) { ); return; } - nitro.logger.info( - "Adding Nitro fallback to `_headers` to handle all unmatched routes." - ); + nitro.logger.info("Adding Nitro fallback to `_headers` to handle all unmatched routes."); contents = currentHeaders + "\n" + contents; } await fsp.writeFile(headersPath, contents); } -export function getStaticPaths( - publicAssets: PublicAssetDir[], - baseURL: string -): string[] { +export function getStaticPaths(publicAssets: PublicAssetDir[], baseURL: string): string[] { return [ "/.netlify/*", // TODO: should this be also be prefixed with baseURL? ...publicAssets diff --git a/src/presets/node/cluster.ts b/src/presets/node/cluster.ts new file mode 100644 index 0000000000..55bd13687f --- /dev/null +++ b/src/presets/node/cluster.ts @@ -0,0 +1,47 @@ +import { resolve } from "pathe"; +import { writeFile } from "../../utils/fs.ts"; +import { defineNitroPreset } from "../_utils/preset.ts"; + +export const nodeCluster = defineNitroPreset( + { + extends: "node-server", + serveStatic: true, + entry: "./node/runtime/node-cluster", + rollupConfig: { + output: { + entryFileNames: "worker.mjs", + }, + }, + hooks: { + async compiled(nitro) { + await writeFile(resolve(nitro.options.output.serverDir, "index.mjs"), nodeClusterEntry()); + }, + }, + }, + { + name: "node-cluster" as const, + } +); + +function nodeClusterEntry() { + return /* js */ ` +import cluster from "node:cluster"; +import os from "node:os"; + +if (cluster.isPrimary) { + const numberOfWorkers = + Number.parseInt(process.env.NITRO_CLUSTER_WORKERS || "") || + (os.cpus().length > 0 ? os.cpus().length : 1); + for (let i = 0; i < numberOfWorkers; i++) { + cluster.fork({ + WORKER_ID: i + 1, + }); + } +} else { + import("./worker.mjs").catch((error) => { + console.error(error); + process.exit(1); + }); +} +`; +} diff --git a/src/presets/node/preset.ts b/src/presets/node/preset.ts index cd20afd44a..ebccd1354c 100644 --- a/src/presets/node/preset.ts +++ b/src/presets/node/preset.ts @@ -1,22 +1,9 @@ -import { defineNitroPreset } from "nitropack/kit"; -import { normalize } from "pathe"; -import { resolveModulePath } from "exsolve"; - -const node = defineNitroPreset( - { - entry: "./runtime/node-listener", - }, - { - name: "node-listener" as const, - aliases: ["node"] as const, - url: import.meta.url, - } -); +import { defineNitroPreset } from "../_utils/preset.ts"; +import { nodeCluster } from "./cluster.ts"; const nodeServer = defineNitroPreset( { - extends: "node", - entry: "./runtime/node-server", + entry: "./node/runtime/node-server", serveStatic: true, commands: { preview: "node ./server/index.mjs", @@ -24,50 +11,17 @@ const nodeServer = defineNitroPreset( }, { name: "node-server" as const, - url: import.meta.url, + aliases: ["node"], } ); -const nodeCluster = defineNitroPreset( +const nodeMiddleware = defineNitroPreset( { - extends: "node-server", - entry: "./runtime/node-cluster", - hooks: { - "rollup:before"(_nitro, rollupConfig) { - const manualChunks = rollupConfig.output?.manualChunks; - if (manualChunks && typeof manualChunks === "function") { - const serverEntry = resolveModulePath("./runtime/node-server", { - from: import.meta.url, - extensions: [".mjs", ".ts"], - }); - rollupConfig.output.manualChunks = (id, meta) => { - if (id.includes("node-server") && normalize(id) === serverEntry) { - return "nitro/node-worker"; - } - return manualChunks(id, meta); - }; - } - }, - }, - }, - { - name: "node-cluster" as const, - url: import.meta.url, - } -); - -const cli = defineNitroPreset( - { - extends: "node", - entry: "./runtime/cli", - commands: { - preview: "Run with node ./server/index.mjs [route]", - }, + entry: "./node/runtime/node-middleware", }, { - name: "cli" as const, - url: import.meta.url, + name: "node-middleware" as const, } ); -export default [node, nodeServer, nodeCluster, cli] as const; +export default [nodeServer, nodeCluster, nodeMiddleware] as const; diff --git a/src/presets/node/runtime/cli.ts b/src/presets/node/runtime/cli.ts deleted file mode 100644 index e87f836436..0000000000 --- a/src/presets/node/runtime/cli.ts +++ /dev/null @@ -1,30 +0,0 @@ -import "#nitro-internal-pollyfills"; -import { useNitroApp } from "nitropack/runtime"; -import { normalize } from "pathe"; - -const nitroApp = useNitroApp(); - -async function cli() { - const url = process.argv[2] || "/"; - const debug = (label: string, ...args: any[]) => - console.debug(`> ${label}:`, ...args); - const r = await nitroApp.localCall({ url }); - - debug("URL", url); - debug("StatusCode", r.status); - debug("StatusMessage", r.statusText); - // @ts-ignore - for (const header of Object.entries(r.headers)) { - debug(header[0], header[1]); - } - console.log("\n", r.body?.toString()); -} - -if (process.argv.some((arg) => import.meta.url.includes(normalize(arg)))) { - // eslint-disable-next-line unicorn/prefer-top-level-await - cli().catch((error) => { - console.error(error); - // eslint-disable-next-line unicorn/no-process-exit - process.exit(1); - }); -} diff --git a/src/presets/node/runtime/node-cluster.ts b/src/presets/node/runtime/node-cluster.ts index a6b5fce329..e9bc592c21 100644 --- a/src/presets/node/runtime/node-cluster.ts +++ b/src/presets/node/runtime/node-cluster.ts @@ -1,77 +1,55 @@ +import "#nitro/virtual/polyfills"; import cluster from "node:cluster"; -import os from "node:os"; -import { - getGracefulShutdownConfig, - trapUnhandledNodeErrors, -} from "nitropack/runtime/internal"; +import { NodeRequest, serve } from "srvx/node"; +import wsAdapter from "crossws/adapters/node"; -function runMaster() { - const numberOfWorkers = - Number.parseInt(process.env.NITRO_CLUSTER_WORKERS || "") || - (os.cpus().length > 0 ? os.cpus().length : 1); +import { useNitroApp } from "nitro/app"; +import { startScheduleRunner } from "#nitro/runtime/task"; +import { trapUnhandledErrors } from "#nitro/runtime/error/hooks"; +import { resolveWebsocketHooks } from "#nitro/runtime/app"; - for (let i = 0; i < numberOfWorkers; i++) { - cluster.fork(); - } +const _parsedPort = Number.parseInt(process.env.NITRO_PORT ?? process.env.PORT ?? ""); +const port = Number.isNaN(_parsedPort) ? 3000 : _parsedPort; - // Restore worker on exit - let isShuttingDown = false; - cluster.on("exit", () => { - if (!isShuttingDown) { - cluster.fork(); - } - }); - - // Graceful shutdown - const shutdownConfig = getGracefulShutdownConfig(); - if (!shutdownConfig.disabled) { - async function onShutdown() { - if (isShuttingDown) { - return; - } - isShuttingDown = true; - await new Promise((resolve) => { - const timeout = setTimeout(() => { - console.warn("Timeout reached for graceful shutdown. Forcing exit."); - resolve(); - }, shutdownConfig.timeout); +const host = process.env.NITRO_HOST || process.env.HOST; +const cert = process.env.NITRO_SSL_CERT; +const key = process.env.NITRO_SSL_KEY; +// const socketPath = process.env.NITRO_UNIX_SOCKET; // TODO - cluster.on("exit", () => { - if ( - Object.values(cluster.workers || {}).every((w) => !w || w.isDead()) - ) { - clearTimeout(timeout); - resolve(); - } else { - // Wait for other workers to die... - } - }); - }); - - if (shutdownConfig.forceExit) { - // eslint-disable-next-line unicorn/no-process-exit - process.exit(0); - } - } - for (const signal of shutdownConfig.signals) { - process.once(signal, onShutdown); - } - } +const clusterId = cluster.isWorker && process.env.WORKER_ID; +if (clusterId) { + console.log(`Worker #${clusterId} started`); } -function runWorker() { - import("./node-server").catch((error) => { - console.error(error); - // eslint-disable-next-line unicorn/no-process-exit - process.exit(1); +const nitroApp = useNitroApp(); + +const server = serve({ + port, + hostname: host, + tls: cert && key ? { cert, key } : undefined, + node: { exclusive: false }, + silent: clusterId ? clusterId !== "1" : undefined, + fetch: nitroApp.fetch, +}); + +if (import.meta._websocket) { + const { handleUpgrade } = wsAdapter({ resolve: resolveWebsocketHooks }); + server.node!.server!.on("upgrade", (req, socket, head) => { + handleUpgrade( + req, + socket, + head, + // @ts-expect-error (upgrade is not typed) + new NodeRequest({ req, upgrade: { socket, head } }) + ); }); } -// Trap unhandled errors -trapUnhandledNodeErrors(); +trapUnhandledErrors(); -if (cluster.isPrimary) { - runMaster(); -} else { - runWorker(); +// Scheduled tasks +if (import.meta._tasks) { + startScheduleRunner({ waitUntil: server.waitUntil }); } + +export default {}; diff --git a/src/presets/node/runtime/node-listener.ts b/src/presets/node/runtime/node-listener.ts deleted file mode 100644 index 5b0b30ee52..0000000000 --- a/src/presets/node/runtime/node-listener.ts +++ /dev/null @@ -1,27 +0,0 @@ -import "#nitro-internal-pollyfills"; -import { toNodeListener } from "h3"; -import { useNitroApp } from "nitropack/runtime"; -import { - startScheduleRunner, - trapUnhandledNodeErrors, -} from "nitropack/runtime/internal"; - -const nitroApp = useNitroApp(); - -export const listener = toNodeListener(nitroApp.h3App); - -/** @experimental */ -export const websocket = import.meta._websocket - ? nitroApp.h3App.websocket - : undefined; - -/** @deprecated use new `listener` export instead */ -export const handler = listener; - -// Trap unhandled errors -trapUnhandledNodeErrors(); - -// Scheduled tasks -if (import.meta._tasks) { - startScheduleRunner(); -} diff --git a/src/presets/node/runtime/node-middleware.ts b/src/presets/node/runtime/node-middleware.ts new file mode 100644 index 0000000000..8be7bcbed1 --- /dev/null +++ b/src/presets/node/runtime/node-middleware.ts @@ -0,0 +1,20 @@ +import "#nitro/virtual/polyfills"; +import { toNodeHandler } from "srvx/node"; +import wsAdapter from "crossws/adapters/node"; + +import { useNitroApp } from "nitro/app"; +import { startScheduleRunner } from "#nitro/runtime/task"; +import { resolveWebsocketHooks } from "#nitro/runtime/app"; + +const nitroApp = useNitroApp(); + +export const middleware = toNodeHandler(nitroApp.fetch); + +const ws = import.meta._websocket ? wsAdapter({ resolve: resolveWebsocketHooks }) : undefined; + +export const handleUpgrade = ws?.handleUpgrade; + +// Scheduled tasks +if (import.meta._tasks) { + startScheduleRunner(); +} diff --git a/src/presets/node/runtime/node-server.ts b/src/presets/node/runtime/node-server.ts index a8737bda74..0d44928b15 100644 --- a/src/presets/node/runtime/node-server.ts +++ b/src/presets/node/runtime/node-server.ts @@ -1,71 +1,47 @@ -import "#nitro-internal-pollyfills"; -import { Server as HttpServer } from "node:http"; -import { Server as HttpsServer } from "node:https"; -import type { AddressInfo } from "node:net"; +import "#nitro/virtual/polyfills"; +import { NodeRequest, serve } from "srvx/node"; import wsAdapter from "crossws/adapters/node"; -import destr from "destr"; -import { toNodeListener } from "h3"; -import { useNitroApp, useRuntimeConfig } from "nitropack/runtime"; -import { - setupGracefulShutdown, - startScheduleRunner, - trapUnhandledNodeErrors, -} from "nitropack/runtime/internal"; -const cert = process.env.NITRO_SSL_CERT; -const key = process.env.NITRO_SSL_KEY; +import { useNitroApp } from "nitro/app"; +import { startScheduleRunner } from "#nitro/runtime/task"; +import { trapUnhandledErrors } from "#nitro/runtime/error/hooks"; +import { resolveWebsocketHooks } from "#nitro/runtime/app"; -const nitroApp = useNitroApp(); +const _parsedPort = Number.parseInt(process.env.NITRO_PORT ?? process.env.PORT ?? ""); +const port = Number.isNaN(_parsedPort) ? 3000 : _parsedPort; -const server = - cert && key - ? new HttpsServer({ key, cert }, toNodeListener(nitroApp.h3App)) - : new HttpServer(toNodeListener(nitroApp.h3App)); - -const port = (destr(process.env.NITRO_PORT || process.env.PORT) || - 3000) as number; const host = process.env.NITRO_HOST || process.env.HOST; +const cert = process.env.NITRO_SSL_CERT; +const key = process.env.NITRO_SSL_KEY; +// const socketPath = process.env.NITRO_UNIX_SOCKET; // TODO -const path = process.env.NITRO_UNIX_SOCKET; +const nitroApp = useNitroApp(); -// @ts-ignore -const listener = server.listen(path ? { path } : { port, host }, (err) => { - if (err) { - console.error(err); - // eslint-disable-next-line unicorn/no-process-exit - process.exit(1); - } - const protocol = cert && key ? "https" : "http"; - const addressInfo = listener.address() as AddressInfo; - if (typeof addressInfo === "string") { - console.log(`Listening on unix socket ${addressInfo}`); - return; - } - const baseURL = (useRuntimeConfig().app.baseURL || "").replace(/\/$/, ""); - const url = `${protocol}://${ - addressInfo.family === "IPv6" - ? `[${addressInfo.address}]` - : addressInfo.address - }:${addressInfo.port}${baseURL}`; - console.log(`Listening on ${url}`); +const server = serve({ + port, + hostname: host, + tls: cert && key ? { cert, key } : undefined, + fetch: nitroApp.fetch, }); -// Trap unhandled errors -trapUnhandledNodeErrors(); - -// Graceful shutdown -setupGracefulShutdown(listener, nitroApp); - -// Websocket support -// https://crossws.unjs.io/adapters/node if (import.meta._websocket) { - const { handleUpgrade } = wsAdapter(nitroApp.h3App.websocket); - server.on("upgrade", handleUpgrade); + const { handleUpgrade } = wsAdapter({ resolve: resolveWebsocketHooks }); + server.node!.server!.on("upgrade", (req, socket, head) => { + handleUpgrade( + req, + socket, + head, + // @ts-expect-error (upgrade is not typed) + new NodeRequest({ req, upgrade: { socket, head } }) + ); + }); } +trapUnhandledErrors(); + // Scheduled tasks if (import.meta._tasks) { - startScheduleRunner(); + startScheduleRunner({ waitUntil: server.waitUntil }); } export default {}; diff --git a/src/presets/platform.sh/preset.ts b/src/presets/platform.sh/preset.ts index 6311eed3da..e9a2e229f2 100644 --- a/src/presets/platform.sh/preset.ts +++ b/src/presets/platform.sh/preset.ts @@ -1,12 +1,12 @@ -import { defineNitroPreset } from "nitropack/kit"; +import { defineNitroPreset } from "../_utils/preset.ts"; const platformSh = defineNitroPreset( { extends: "node-server", + serveStatic: true, }, { name: "platform-sh" as const, - url: import.meta.url, } ); diff --git a/src/presets/render.com/preset.ts b/src/presets/render.com/preset.ts index 6a268428c1..3c1ee399b8 100644 --- a/src/presets/render.com/preset.ts +++ b/src/presets/render.com/preset.ts @@ -1,12 +1,12 @@ -import { defineNitroPreset } from "nitropack/kit"; +import { defineNitroPreset } from "../_utils/preset.ts"; const renderCom = defineNitroPreset( { extends: "node-server", + serveStatic: true, }, { name: "render-com" as const, - url: import.meta.url, } ); diff --git a/src/presets/standard/preset.ts b/src/presets/standard/preset.ts new file mode 100644 index 0000000000..b72b2d5009 --- /dev/null +++ b/src/presets/standard/preset.ts @@ -0,0 +1,26 @@ +import { defineNitroPreset } from "../_utils/preset.ts"; + +const standard = defineNitroPreset( + { + entry: "./standard/runtime/server", + serveStatic: false, + output: { + publicDir: "{{ output.dir }}/public/{{ baseURL }}", + }, + commands: { + preview: "npx srvx --prod ./", + }, + alias: { + srvx: "srvx/generic", + "srvx/bun": "srvx/bun", + "srvx/deno": "srvx/deno", + "srvx/node": "srvx/node", + "srvx/generic": "srvx/generic", + }, + }, + { + name: "standard" as const, + } +); + +export default [standard] as const; diff --git a/src/presets/standard/runtime/server.ts b/src/presets/standard/runtime/server.ts new file mode 100644 index 0000000000..a67e6bb575 --- /dev/null +++ b/src/presets/standard/runtime/server.ts @@ -0,0 +1,8 @@ +import "#nitro/virtual/polyfills"; +import { useNitroApp } from "nitro/app"; + +const nitroApp = useNitroApp(); + +export default { + fetch: nitroApp.fetch, +}; diff --git a/src/presets/stormkit/preset.ts b/src/presets/stormkit/preset.ts index 086d488399..f0ca9e4cc6 100644 --- a/src/presets/stormkit/preset.ts +++ b/src/presets/stormkit/preset.ts @@ -1,8 +1,8 @@ -import { defineNitroPreset } from "nitropack/kit"; +import { defineNitroPreset } from "../_utils/preset.ts"; const stormkit = defineNitroPreset( { - entry: "./runtime/stormkit", + entry: "./stormkit/runtime/stormkit", output: { dir: "{{ rootDir }}/.stormkit", publicDir: "{{ rootDir }}/.stormkit/public/{{ baseURL }}", @@ -11,7 +11,6 @@ const stormkit = defineNitroPreset( { name: "stormkit" as const, stdName: "stormkit", - url: import.meta.url, } ); diff --git a/src/presets/stormkit/runtime/stormkit.ts b/src/presets/stormkit/runtime/stormkit.ts index fe10b898e6..f4d42bea67 100644 --- a/src/presets/stormkit/runtime/stormkit.ts +++ b/src/presets/stormkit/runtime/stormkit.ts @@ -1,8 +1,9 @@ -import "#nitro-internal-pollyfills"; -import { useNitroApp } from "nitropack/runtime"; -import { normalizeLambdaOutgoingBody } from "nitropack/runtime/internal"; +import "#nitro/virtual/polyfills"; +import { useNitroApp } from "nitro/app"; +import { awsResponseBody } from "../../aws-lambda/runtime/_utils.ts"; import type { Handler } from "aws-lambda"; +import type { ServerRequest } from "srvx"; type StormkitEvent = { url: string; // e.g. /my/path, /my/path?with=query @@ -25,37 +26,30 @@ type StormkitResponse = { const nitroApp = useNitroApp(); -export const handler: Handler = - async function (event, context) { - const response = await nitroApp.localCall({ - event, - url: event.url, - context, - headers: event.headers, - method: event.method || "GET", - query: event.query, - body: event.body, - }); - - const awsBody = await normalizeLambdaOutgoingBody( - response.body, - response.headers - ); - - return { - statusCode: response.status, - headers: normalizeOutgoingHeaders(response.headers), - [awsBody.type === "text" ? "body" : "buffer"]: awsBody.body, - }; - }; - -function normalizeOutgoingHeaders( - headers: Record -): Record { +export const handler: Handler = async function (event, context) { + const req = new Request(event.url, { + method: event.method || "GET", + headers: event.headers, + body: event.body, + }) as ServerRequest; + + // srvx compatibility + req.runtime ??= { name: "stormkit" }; + req.runtime.stormkit ??= { event, context } as any; + + const response = await nitroApp.fetch(req); + + const { body, isBase64Encoded } = await awsResponseBody(response); + + return { + statusCode: response.status, + headers: normalizeOutgoingHeaders(response.headers), + [isBase64Encoded ? "buffer" : "body"]: body, + } satisfies StormkitResponse; +}; + +function normalizeOutgoingHeaders(headers: Headers): Record { return Object.fromEntries( - Object.entries(headers).map(([k, v]) => [ - k, - Array.isArray(v) ? v.join(",") : String(v), - ]) + Object.entries(headers).map(([k, v]) => [k, Array.isArray(v) ? v.join(",") : String(v)]) ); } diff --git a/src/presets/vercel/preset.ts b/src/presets/vercel/preset.ts index 3302a68162..a24420f44b 100644 --- a/src/presets/vercel/preset.ts +++ b/src/presets/vercel/preset.ts @@ -1,31 +1,71 @@ -import { defineNitroPreset } from "nitropack/kit"; -import type { Nitro } from "nitropack/types"; +import { defineNitroPreset } from "../_utils/preset.ts"; +import type { Nitro } from "nitro/types"; +import { presetsDir } from "nitro/meta"; +import { join } from "pathe"; import { deprecateSWR, - generateEdgeFunctionFiles, generateFunctionFiles, generateStaticFiles, -} from "./utils"; -import { builtnNodeModules } from "../_unenv/node-compat/vercel"; + resolveVercelRuntime, +} from "./utils.ts"; -export type { VercelOptions as PresetOptions } from "./types"; +export type { VercelOptions as PresetOptions } from "./types.ts"; // https://vercel.com/docs/build-output-api/v3 const vercel = defineNitroPreset( { - extends: "node", - entry: "./runtime/vercel", + entry: "./vercel/runtime/vercel.{format}", + manifest: { + deploymentId: process.env.VERCEL_DEPLOYMENT_ID, + }, + vercel: { + skewProtection: !!process.env.VERCEL_SKEW_PROTECTION_ENABLED, + cronHandlerRoute: "/_vercel/cron", + }, output: { dir: "{{ rootDir }}/.vercel/output", - serverDir: "{{ output.dir }}/functions/__nitro.func", + serverDir: "{{ output.dir }}/functions/__server.func", publicDir: "{{ output.dir }}/static/{{ baseURL }}", }, commands: { - deploy: "", - preview: "", + preview: "npx srvx --static ../../static ./functions/__server.func/index.mjs", + deploy: "npx vercel deploy --prebuilt", }, hooks: { + "build:before": async (nitro: Nitro) => { + const logger = nitro.logger.withTag("vercel"); + + // Runtime + const runtime = await resolveVercelRuntime(nitro); + if (runtime.startsWith("bun") && !nitro.options.exportConditions!.includes("bun")) { + nitro.options.exportConditions!.push("bun"); + } + logger.info(`Using \`${runtime}\` runtime.`); + + // Entry handler format + let serverFormat = nitro.options.vercel?.entryFormat; + if (!serverFormat) { + const hasNodeHandler = nitro.routing.routes.routes + .flatMap((r) => r.data) + .some((h) => h.format === "node"); + serverFormat = hasNodeHandler ? "node" : "web"; + } + logger.info(`Using \`${serverFormat}\` entry format.`); + nitro.options.entry = nitro.options.entry.replace("{format}", serverFormat); + + // Cron tasks handler + if ( + nitro.options.experimental.tasks && + Object.keys(nitro.options.scheduledTasks || {}).length > 0 + ) { + nitro.options.handlers.push({ + route: nitro.options.vercel!.cronHandlerRoute || "/_vercel/cron", + lazy: true, + handler: join(presetsDir, "vercel/runtime/cron-handler"), + }); + } + }, "rollup:before": (nitro: Nitro) => { deprecateSWR(nitro); }, @@ -37,62 +77,18 @@ const vercel = defineNitroPreset( { name: "vercel" as const, stdName: "vercel", - url: import.meta.url, - } -); - -const vercelEdge = defineNitroPreset( - { - extends: "base-worker", - entry: "./runtime/vercel-edge", - exportConditions: ["edge-light"], - output: { - dir: "{{ rootDir }}/.vercel/output", - serverDir: "{{ output.dir }}/functions/__nitro.func", - publicDir: "{{ output.dir }}/static/{{ baseURL }}", - }, - commands: { - deploy: "", - preview: "", - }, - unenv: { - external: builtnNodeModules.flatMap((m) => `node:${m}`), - alias: { - ...Object.fromEntries( - builtnNodeModules.flatMap((m) => [ - [m, `node:${m}`], - [`node:${m}`, `node:${m}`], - ]) - ), - }, - }, - rollupConfig: { - output: { - format: "module", - }, - }, - wasm: { - lazy: true, - esmImport: false, - }, - hooks: { - "rollup:before": (nitro: Nitro) => { - deprecateSWR(nitro); - }, - async compiled(nitro: Nitro) { - await generateEdgeFunctionFiles(nitro); - }, - }, - }, - { - name: "vercel-edge" as const, - url: import.meta.url, } ); const vercelStatic = defineNitroPreset( { extends: "static", + manifest: { + deploymentId: process.env.VERCEL_DEPLOYMENT_ID, + }, + vercel: { + skewProtection: !!process.env.VERCEL_SKEW_PROTECTION_ENABLED, + }, output: { dir: "{{ rootDir }}/.vercel/output", publicDir: "{{ output.dir }}/static/{{ baseURL }}", @@ -113,8 +109,7 @@ const vercelStatic = defineNitroPreset( name: "vercel-static" as const, stdName: "vercel", static: true, - url: import.meta.url, } ); -export default [vercel, vercelEdge, vercelStatic] as const; +export default [vercel, vercelStatic] as const; diff --git a/src/presets/vercel/runtime/cron-handler.ts b/src/presets/vercel/runtime/cron-handler.ts new file mode 100644 index 0000000000..2d4acf0129 --- /dev/null +++ b/src/presets/vercel/runtime/cron-handler.ts @@ -0,0 +1,31 @@ +import { timingSafeEqual } from "node:crypto"; +import { defineHandler, HTTPError } from "nitro/h3"; +import { runCronTasks } from "#nitro/runtime/task"; + +export default defineHandler(async (event) => { + // Validate CRON_SECRET if set - https://vercel.com/docs/cron-jobs/manage-cron-jobs#securing-cron-jobs + const cronSecret = process.env.CRON_SECRET; + if (cronSecret) { + const authHeader = event.req.headers.get("authorization") || ""; + const expected = `Bearer ${cronSecret}`; + const a = Buffer.from(authHeader); + const b = Buffer.from(expected); + if (a.length !== b.length || !timingSafeEqual(a, b)) { + throw new HTTPError("Unauthorized", { status: 401 }); + } + } + + const cron = event.req.headers.get("x-vercel-cron-schedule"); + if (!cron) { + throw new HTTPError("Missing x-vercel-cron-schedule header", { status: 400 }); + } + + await runCronTasks(cron, { + context: { waitUntil: event.req.waitUntil }, + payload: { + scheduledTime: Date.now(), + }, + }); + + return { success: true }; +}); diff --git a/src/presets/vercel/runtime/isr.ts b/src/presets/vercel/runtime/isr.ts new file mode 100644 index 0000000000..10c5c0f7ca --- /dev/null +++ b/src/presets/vercel/runtime/isr.ts @@ -0,0 +1,23 @@ +export const ISR_URL_PARAM = "__isr_route"; + +export function isrRouteRewrite( + reqUrl: string, + xNowRouteMatches: string | null +): [pathname: string, search: string] | undefined { + if (xNowRouteMatches) { + const isrURL = new URLSearchParams(xNowRouteMatches).get(ISR_URL_PARAM); + if (isrURL) { + return [decodeURIComponent(isrURL), ""]; + } + } else { + const queryIndex = reqUrl.indexOf("?"); + if (queryIndex !== -1) { + const params = new URLSearchParams(reqUrl.slice(queryIndex + 1)); + const isrURL = params.get(ISR_URL_PARAM); + if (isrURL) { + params.delete(ISR_URL_PARAM); + return [decodeURIComponent(isrURL), params.toString()]; + } + } + } +} diff --git a/src/presets/vercel/runtime/vercel-edge.ts b/src/presets/vercel/runtime/vercel-edge.ts deleted file mode 100644 index 89bcb0c6af..0000000000 --- a/src/presets/vercel/runtime/vercel-edge.ts +++ /dev/null @@ -1,26 +0,0 @@ -import "#nitro-internal-pollyfills"; -import { useNitroApp } from "nitropack/runtime"; - -const nitroApp = useNitroApp(); - -export default async function handleEvent(request: Request, event: any) { - const url = new URL(request.url); - - let body; - if (request.body) { - body = await request.arrayBuffer(); - } - - return nitroApp.localFetch(url.pathname + url.search, { - host: url.hostname, - protocol: url.protocol, - headers: request.headers, - method: request.method, - body, - context: { - vercel: { - event, - }, - }, - }); -} diff --git a/src/presets/vercel/runtime/vercel.node.ts b/src/presets/vercel/runtime/vercel.node.ts new file mode 100644 index 0000000000..3d8f3bd52a --- /dev/null +++ b/src/presets/vercel/runtime/vercel.node.ts @@ -0,0 +1,32 @@ +import "#nitro/virtual/polyfills"; +import type { NodeServerRequest, NodeServerResponse } from "srvx"; +import { toNodeHandler } from "srvx/node"; +import { useNitroApp, getRouteRules } from "nitro/app"; +import { isrRouteRewrite } from "./isr.ts"; + +const nitroApp = useNitroApp(); + +const handler = toNodeHandler(nitroApp.fetch); + +export default function nodeHandler(req: NodeServerRequest, res: NodeServerResponse) { + // https://vercel.com/docs/headers/request-headers#x-forwarded-for + // srvx node adapter uses req.socket.remoteAddress for req.ip + let ip: string | undefined; + Object.defineProperty(req.socket, "remoteAddress", { + get() { + const h = req.headers["x-forwarded-for"] as string; + return (ip ??= h?.split?.(",").shift()?.trim()); + }, + }); + + // ISR route rewrite + const isrURL = isrRouteRewrite(req.url!, req.headers["x-now-route-matches"] as string); + if (isrURL) { + const { routeRules } = getRouteRules("", isrURL[0]); + if (routeRules?.isr) { + req.url = isrURL[0] + (isrURL[1] ? `?${isrURL[1]}` : ""); + } + } + + return handler(req as any, res as any); +} diff --git a/src/presets/vercel/runtime/vercel.ts b/src/presets/vercel/runtime/vercel.ts deleted file mode 100644 index 0547cf356d..0000000000 --- a/src/presets/vercel/runtime/vercel.ts +++ /dev/null @@ -1,22 +0,0 @@ -import "#nitro-internal-pollyfills"; -import { useNitroApp } from "nitropack/runtime"; - -import { type NodeListener, toNodeListener } from "h3"; -import { parseQuery } from "ufo"; - -const nitroApp = useNitroApp(); - -const handler = toNodeListener(nitroApp.h3App); - -const listener: NodeListener = function (req, res) { - const query = req.headers["x-now-route-matches"] as string; - if (query) { - const { url } = parseQuery(query); - if (url) { - req.url = url as string; - } - } - return handler(req, res); -}; - -export default listener; diff --git a/src/presets/vercel/runtime/vercel.web.ts b/src/presets/vercel/runtime/vercel.web.ts new file mode 100644 index 0000000000..e6486e4868 --- /dev/null +++ b/src/presets/vercel/runtime/vercel.web.ts @@ -0,0 +1,38 @@ +import "#nitro/virtual/polyfills"; +import { useNitroApp, getRouteRules } from "nitro/app"; + +import type { ServerRequest } from "srvx"; +import { isrRouteRewrite } from "./isr.ts"; + +const nitroApp = useNitroApp(); + +export default { + fetch(req: ServerRequest, context: { waitUntil: (promise: Promise) => void }) { + // ISR route rewrite + const isrURL = isrRouteRewrite(req.url, req.headers.get("x-now-route-matches")); + if (isrURL) { + const { routeRules } = getRouteRules("", isrURL[0]); + if (routeRules?.isr) { + req = new Request( + new URL(isrURL[0] + (isrURL[1] ? `?${isrURL[1]}` : ""), req.url).href, + req + ); + } + } + + req.runtime ??= { name: "vercel" }; + req.runtime.vercel = { context }; + + let ip: string | undefined; + Object.defineProperty(req, "ip", { + get() { + const h = req.headers.get("x-forwarded-for"); + return (ip ??= h?.split(",").shift()?.trim()); + }, + }); + + req.waitUntil = context?.waitUntil; + + return nitroApp.fetch(req); + }, +}; diff --git a/src/presets/vercel/types.ts b/src/presets/vercel/types.ts index 388fb64c91..4c8bd608f2 100644 --- a/src/presets/vercel/types.ts +++ b/src/presets/vercel/types.ts @@ -7,18 +7,14 @@ export interface VercelBuildConfigV3 { routes?: ( | { src: string; - headers: { - "cache-control": string; - }; - continue: boolean; + dest?: string; + headers?: Record; + continue?: boolean; + status?: number; } | { handle: string; } - | { - src: string; - dest: string; - } )[]; images?: { sizes: number[]; @@ -47,6 +43,9 @@ export interface VercelBuildConfigV3 { >; cache?: string[]; bypassToken?: string; + framework?: { + version: string; + }; crons?: { path: string; schedule: string; @@ -54,7 +53,8 @@ export interface VercelBuildConfigV3 { } /** - * https://vercel.com/docs/build-output-api/v3/primitives#serverless-function-configuration + * https://vercel.com/docs/build-output-api/primitives#serverless-function-configuration + * https://vercel.com/docs/build-output-api/primitives#node.js-config */ export interface VercelServerlessFunctionConfig { /** @@ -62,11 +62,29 @@ export interface VercelServerlessFunctionConfig { */ memory?: number; + /** + * Specifies the instruction set "architecture" the Vercel Function supports. + * + * Either `x86_64` or `arm64`. The default value is `x86_64` + */ + architecture?: "x86_64" | "arm64"; + /** * Maximum execution duration (in seconds) that will be allowed for the Serverless Function. */ maxDuration?: number; + /** + * Map of additional environment variables that will be available to the Vercel Function, + * in addition to the env vars specified in the Project Settings. + */ + environment?: Record; + + /** + * List of Vercel Regions where the Vercel Function will be deployed to. + */ + regions?: string[]; + /** * True if a custom runtime has support for Lambda runtime wrappers. */ @@ -77,11 +95,29 @@ export interface VercelServerlessFunctionConfig { */ supportsResponseStreaming?: boolean; + /** + * Enables source map generation. + */ + shouldAddSourcemapSupport?: boolean; + + /** + * The runtime to use. Defaults to the auto-detected Node.js version. + */ + runtime?: "nodejs20.x" | "nodejs22.x" | "bun1.x" | (string & {}); + [key: string]: unknown; } export interface VercelOptions { - config: VercelBuildConfigV3; + config?: VercelBuildConfigV3; + + /** + * If you have enabled skew protection in the Vercel dashboard, it will + * be enabled by default. + * + * You can disable the Nitro integration by setting this option to `false`. + */ + skewProtection?: boolean; /** * If you are using `vercel-edge`, you can specify the region(s) for your edge function. @@ -90,6 +126,27 @@ export interface VercelOptions { regions?: string[]; functions?: VercelServerlessFunctionConfig; + + /** + * Handler format to use for Vercel Serverless Functions. + * + * Using `node` format enables compatibility with Node.js specific APIs in your Nitro application (e.g., `req.runtime.node`). + * + * Possible values are: `web` (default) and `node`. + */ + entryFormat?: "web" | "node"; + + /** + * The route path for the Vercel cron handler endpoint. + * + * When `experimental.tasks` and `scheduledTasks` are configured, + * Nitro registers a cron handler at this path that Vercel invokes + * on each scheduled cron trigger. + * + * @default "/_vercel/cron" + * @see https://vercel.com/docs/cron-jobs + */ + cronHandlerRoute?: string; } /** @@ -123,4 +180,11 @@ export type PrerenderFunctionConfig = { * When `true`, the query string will be present on the `request` argument passed to the invoked function. The `allowQuery` filter still applies. */ passQuery?: boolean; + + /** + * (vercel) + * + * When `true`, expose the response body regardless of status code including error status codes. (default `false`) + */ + exposeErrBody?: boolean; }; diff --git a/src/presets/vercel/utils.ts b/src/presets/vercel/utils.ts index 4fd6d9f4f4..02447c8a0e 100644 --- a/src/presets/vercel/utils.ts +++ b/src/presets/vercel/utils.ts @@ -1,29 +1,55 @@ import fsp from "node:fs/promises"; import { defu } from "defu"; -import { writeFile } from "nitropack/kit"; -import type { Nitro } from "nitropack/types"; +import { writeFile } from "../_utils/fs.ts"; +import type { Nitro, NitroRouteRules } from "nitro/types"; import { dirname, relative, resolve } from "pathe"; -import { joinURL, withoutLeadingSlash } from "ufo"; +import { joinURL, withLeadingSlash, withoutLeadingSlash } from "ufo"; import type { PrerenderFunctionConfig, VercelBuildConfigV3, VercelServerlessFunctionConfig, -} from "./types"; +} from "./types.ts"; import { isTest } from "std-env"; +import { ISR_URL_PARAM } from "./runtime/isr.ts"; + +// https://vercel.com/docs/build-output-api/configuration + +// https://vercel.com/docs/functions/runtimes/node-js/node-js-versions +const SUPPORTED_NODE_VERSIONS = [20, 22, 24]; + +// h3 ProxyOptions that Vercel CDN rewrites cannot handle at the edge. +// https://vercel.com/docs/rewrites +const UNSUPPORTED_PROXY_OPTIONS = [ + "headers", // headers added to the outgoing request to the upstream + "forwardHeaders", + "filterHeaders", + "fetchOptions", + "cookieDomainRewrite", + "cookiePathRewrite", + "onResponse", +] as const; + +const FALLBACK_ROUTE = "/__server"; + +const ISR_SUFFIX = "-isr"; // Avoid using . as it can conflict with routing + +const SAFE_FS_CHAR_RE = /[^a-zA-Z0-9_.[\]/]/g; + +function getSystemNodeVersion() { + const systemNodeVersion = Number.parseInt(process.versions.node.split(".")[0]); + + return Number.isNaN(systemNodeVersion) ? 22 : systemNodeVersion; +} export async function generateFunctionFiles(nitro: Nitro) { + const o11Routes = getObservabilityRoutes(nitro); + const buildConfigPath = resolve(nitro.options.output.dir, "config.json"); - const buildConfig = generateBuildConfig(nitro); + const buildConfig = generateBuildConfig(nitro, o11Routes); await writeFile(buildConfigPath, JSON.stringify(buildConfig, null, 2)); - const systemNodeVersion = process.versions.node.split(".")[0]; - const runtimeVersion = `nodejs${systemNodeVersion}.x`; - const functionConfigPath = resolve( - nitro.options.output.serverDir, - ".vc-config.json" - ); + const functionConfigPath = resolve(nitro.options.output.serverDir, ".vc-config.json"); const functionConfig: VercelServerlessFunctionConfig = { - runtime: runtimeVersion, handler: "index.mjs", launcherType: "Nodejs", shouldAddHelpers: false, @@ -38,34 +64,10 @@ export async function generateFunctionFiles(nitro: Nitro) { continue; } - // Normalize route rule - let isrConfig = value.isr; - if (typeof isrConfig === "number") { - isrConfig = { expiration: isrConfig }; - } else if (isrConfig === true) { - isrConfig = { expiration: false }; - } else { - isrConfig = { ...isrConfig }; - } - - // Generate prerender config - const prerenderConfig: PrerenderFunctionConfig = { - expiration: isrConfig.expiration ?? false, - bypassToken: nitro.options.vercel?.config?.bypassToken, - ...isrConfig, - }; - - // Allow query parameter for wildcard routes - if (key.includes("/**") /* wildcard */) { - isrConfig.allowQuery = isrConfig.allowQuery || []; - if (!isrConfig.allowQuery.includes("url")) { - isrConfig.allowQuery.push("url"); - } - } - const funcPrefix = resolve( nitro.options.output.serverDir, - ".." + generateEndpoint(key) + "..", + normalizeRouteDest(key) + ISR_SUFFIX ); await fsp.mkdir(dirname(funcPrefix), { recursive: true }); await fsp.symlink( @@ -73,9 +75,30 @@ export async function generateFunctionFiles(nitro: Nitro) { funcPrefix + ".func", "junction" ); - await writeFile( + await writePrerenderConfig( funcPrefix + ".prerender-config.json", - JSON.stringify(prerenderConfig, null, 2) + value.isr, + nitro.options.vercel?.config?.bypassToken + ); + } + + // Write observability routes + if (o11Routes.length === 0) { + return; + } + const _getRouteRules = (path: string) => + defu({}, ...nitro.routing.routeRules.matchAll("", path).reverse()) as NitroRouteRules; + for (const route of o11Routes) { + const routeRules = _getRouteRules(route.src); + if (routeRules.isr) { + continue; // #3563 + } + const funcPrefix = resolve(nitro.options.output.serverDir, "..", route.dest); + await fsp.mkdir(dirname(funcPrefix), { recursive: true }); + await fsp.symlink( + "./" + relative(dirname(funcPrefix), nitro.options.output.serverDir), + funcPrefix + ".func", + "junction" ); } } @@ -85,10 +108,7 @@ export async function generateEdgeFunctionFiles(nitro: Nitro) { const buildConfig = generateBuildConfig(nitro); await writeFile(buildConfigPath, JSON.stringify(buildConfig, null, 2)); - const functionConfigPath = resolve( - nitro.options.output.serverDir, - ".vc-config.json" - ); + const functionConfigPath = resolve(nitro.options.output.serverDir, ".vc-config.json"); const functionConfig = { runtime: "edge", entrypoint: "index.mjs", @@ -103,35 +123,49 @@ export async function generateStaticFiles(nitro: Nitro) { await writeFile(buildConfigPath, JSON.stringify(buildConfig, null, 2)); } -function generateBuildConfig(nitro: Nitro) { +function generateBuildConfig(nitro: Nitro, o11Routes?: ObservabilityRoute[]) { const rules = Object.entries(nitro.options.routeRules).sort( (a, b) => b[0].split(/\/(?!\*)/).length - a[0].split(/\/(?!\*)/).length ); - const config = defu(nitro.options.vercel?.config, { + // Determine which proxy rules can be offloaded to Vercel CDN rewrites + const cdnProxyPaths = new Set( + rules + .filter(([_, routeRules]) => routeRules.proxy && canUseVercelRewrite(routeRules.proxy)) + .map(([path]) => path) + ); + + const config = defu(nitro.options.vercel?.config, { version: 3, + framework: { + name: nitro.options.framework.name, + version: nitro.options.framework.version, + }, overrides: { // Nitro static prerendered route overrides ...Object.fromEntries( - ( - nitro._prerenderedRoutes?.filter((r) => r.fileName !== r.route) || [] - ).map(({ route, fileName }) => [ - withoutLeadingSlash(fileName), - { path: route.replace(/^\//, "") }, - ]) + (nitro._prerenderedRoutes?.filter((r) => r.fileName !== r.route) || []).map( + ({ route, fileName }) => [ + withoutLeadingSlash(fileName), + { path: route.replace(/^\//, "") }, + ] + ) ), }, routes: [ - // Redirect and header rules + // Redirect and header rules (excluding paths handled as CDN proxy rewrites) ...rules - .filter(([_, routeRules]) => routeRules.redirect || routeRules.headers) + .filter( + ([path, routeRules]) => + (routeRules.redirect || routeRules.headers) && !cdnProxyPaths.has(path) + ) .map(([path, routeRules]) => { let route = { src: path.replace("/**", "/(.*)"), }; if (routeRules.redirect) { route = defu(route, { - status: routeRules.redirect.statusCode, + status: routeRules.redirect.status, headers: { Location: routeRules.redirect.to.replace("/**", "/$1"), }, @@ -142,6 +176,40 @@ function generateBuildConfig(nitro: Nitro) { } return route; }), + // Proxy rewrite rules (CDN-level reverse proxy) + // https://vercel.com/docs/rewrites + ...rules + .filter(([path]) => cdnProxyPaths.has(path)) + .map(([path, routeRules]) => { + const proxy = routeRules.proxy!; + const route: Record = { + src: path.replace("/**", "/(.*)"), + dest: proxy.to.replace("/**", "/$1"), + }; + if (routeRules.headers) { + route.headers = routeRules.headers; + } + return route; + }), + // Skew protection + ...(nitro.options.vercel?.skewProtection && nitro.options.manifest?.deploymentId + ? [ + { + src: "/.*", + has: [ + { + type: "header", + key: "Sec-Fetch-Dest", + value: "document", + }, + ], + headers: { + "Set-Cookie": `__vdpl=${nitro.options.manifest.deploymentId}; Path=${nitro.options.baseURL}; SameSite=Strict; Secure; HttpOnly`, + }, + continue: true, + }, + ] + : []), // Public asset rules ...nitro.options.publicAssets .filter((asset) => !asset.fallthrough) @@ -155,7 +223,20 @@ function generateBuildConfig(nitro: Nitro) { })), { handle: "filesystem" }, ], - }); + } as VercelBuildConfigV3); + + // Cron jobs from scheduledTasks + if ( + nitro.options.experimental.tasks && + Object.keys(nitro.options.scheduledTasks || {}).length > 0 + ) { + const cronPath = nitro.options.vercel!.cronHandlerRoute || "/_vercel/cron"; + const cronEntries = Object.keys(nitro.options.scheduledTasks).map((schedule) => ({ + path: cronPath, + schedule, + })); + config.crons = [...cronEntries, ...(config.crons || [])]; + } // Early return if we are building a static site if (nitro.options.static) { @@ -164,45 +245,47 @@ function generateBuildConfig(nitro: Nitro) { config.routes!.push( // ISR rules + // ...If we are using an ISR function for /, then we need to write this explicitly + ...(nitro.options.routeRules["/"]?.isr + ? [ + { + src: `(?<${ISR_URL_PARAM}>/)`, + dest: `/index${ISR_SUFFIX}?${ISR_URL_PARAM}=$${ISR_URL_PARAM}`, + }, + ] + : []), + // ...Add rest of the ISR routes ...rules - .filter( - ([key, value]) => - // value.isr === false || (value.isr && key.includes("/**")) - value.isr !== undefined && key !== "/" - ) + .filter(([key, value]) => value.isr !== undefined && key !== "/") .map(([key, value]) => { - const src = key.replace(/^(.*)\/\*\*/, "(?$1/.*)"); + const src = `(?<${ISR_URL_PARAM}>${normalizeRouteSrc(key)})`; if (value.isr === false) { - // we need to write a rule to avoid route being shadowed by another cache rule elsewhere + // We need to write a rule to avoid route being shadowed by another cache rule elsewhere return { src, - dest: "/__nitro", + dest: FALLBACK_ROUTE, }; } return { src, - dest: - nitro.options.preset === "vercel-edge" - ? "/__nitro?url=$url" - : generateEndpoint(key) + "?url=$url", + dest: withLeadingSlash( + normalizeRouteDest(key) + ISR_SUFFIX + `?${ISR_URL_PARAM}=$${ISR_URL_PARAM}` + ), }; }), - // If we are using an ISR function for /, then we need to write this explicitly - ...(nitro.options.routeRules["/"]?.isr - ? [ - { - src: "(?/)", - dest: "/__nitro-index?url=$url", - }, - ] - : []), - // If we are using an ISR function as a fallback, then we do not need to output the below fallback route as well + // Observability routes + ...(o11Routes || []).map((route) => ({ + src: joinURL(nitro.options.baseURL, route.src), + dest: withLeadingSlash(route.dest), + })), + // If we are using an ISR function as a fallback + // then we do not need to output the below fallback route as well ...(nitro.options.routeRules["/**"]?.isr ? [] : [ { src: "/(.*)", - dest: "/__nitro", + dest: FALLBACK_ROUTE, }, ]) ); @@ -210,22 +293,12 @@ function generateBuildConfig(nitro: Nitro) { return config; } -function generateEndpoint(url: string) { - if (url === "/") { - return "/__nitro-index"; - } - return url.includes("/**") - ? "/__nitro-" + - withoutLeadingSlash(url.replace(/\/\*\*.*/, "").replace(/[^a-z]/g, "-")) - : url; -} - export function deprecateSWR(nitro: Nitro) { if (nitro.options.future.nativeSWR) { return; } let hasLegacyOptions = false; - for (const [key, value] of Object.entries(nitro.options.routeRules)) { + for (const [_key, value] of Object.entries(nitro.options.routeRules)) { if (_hasProp(value, "isr")) { continue; } @@ -248,6 +321,221 @@ export function deprecateSWR(nitro: Nitro) { } } +// --- vercel.json --- + +// https://vercel.com/docs/project-configuration +// https://openapi.vercel.sh/vercel.json +export interface VercelConfig { + bunVersion?: string; +} + +export async function resolveVercelRuntime(nitro: Nitro) { + // 1. Respect explicit runtime from nitro config + let runtime: VercelServerlessFunctionConfig["runtime"] = nitro.options.vercel?.functions?.runtime; + + if (runtime) { + // Already specified + return runtime; + } + + // 2. Read runtime from vercel.json if specified + const vercelConfig = await readVercelConfig(nitro.options.rootDir); + + // 3. Use bun runtime if bunVersion is specified or bun used to build + if (vercelConfig.bunVersion || "Bun" in globalThis) { + runtime = "bun1.x"; + } else { + // 3. Auto-detect runtime based on system Node.js version + const systemNodeVersion = getSystemNodeVersion(); + const usedNodeVersion = + SUPPORTED_NODE_VERSIONS.find((version) => version >= systemNodeVersion) ?? + SUPPORTED_NODE_VERSIONS.at(-1); + runtime = `nodejs${usedNodeVersion}.x`; + } + + // Synchronize back to nitro config + nitro.options.vercel ??= {} as any; + nitro.options.vercel!.functions ??= {} as any; + nitro.options.vercel!.functions!.runtime = runtime; + + return runtime; +} + +export async function readVercelConfig(rootDir: string): Promise { + const vercelConfigPath = resolve(rootDir, "vercel.json"); + const vercelConfig = await fsp + .readFile(vercelConfigPath) + .then((config) => JSON.parse(config.toString())) + .catch(() => ({})); + return vercelConfig as VercelConfig; +} + function _hasProp(obj: any, prop: string) { return obj && typeof obj === "object" && prop in obj; } + +/** + * Check if a proxy rule can be offloaded to a Vercel CDN rewrite. + * A proxy is eligible when it targets an external URL and uses no + * ProxyOptions that Vercel's routing layer cannot handle at the edge. + */ +function canUseVercelRewrite(proxy: NitroRouteRules["proxy"]): proxy is { to: string } { + if (!proxy?.to) { + return false; + } + // Must be an external URL + if (!/^https?:\/\//.test(proxy.to.replace(/\/\*\*$/, ""))) { + return false; + } + // Must not use any ProxyOptions unsupported by Vercel rewrites + for (const key of UNSUPPORTED_PROXY_OPTIONS) { + if ((proxy as any)[key] !== undefined) { + return false; + } + } + return true; +} + +// --- utils for observability --- + +type ObservabilityRoute = { + src: string; // route pattern + dest: string; // function name +}; + +function getObservabilityRoutes(nitro: Nitro): ObservabilityRoute[] { + const compatDate = + nitro.options.compatibilityDate.vercel || nitro.options.compatibilityDate.default; + if (compatDate < "2025-07-15") { + return []; + } + + // Sort routes by how much specific they are + const routePatterns = [ + ...new Set([ + ...(nitro.options.ssrRoutes || []), + ...[...nitro.scannedHandlers, ...nitro.options.handlers] + .filter((h) => !h.middleware && h.route) + .map((h) => h.route!), + ]), + ]; + + const staticRoutes: string[] = []; + const dynamicRoutes: string[] = []; + const catchAllRoutes: string[] = []; + + for (const route of routePatterns) { + if (route.includes("**")) { + catchAllRoutes.push(route); + } else if (route.includes(":") || route.includes("*")) { + dynamicRoutes.push(route); + } else { + staticRoutes.push(route); + } + } + + return [ + ...normalizeRoutes(staticRoutes), + ...normalizeRoutes(dynamicRoutes), + ...normalizeRoutes(catchAllRoutes), + ]; +} + +function normalizeRoutes(routes: string[]) { + return routes + .sort((a, b) => + // a.split("/").length - b.split("/").length || + b.localeCompare(a) + ) + .map((route) => ({ + src: normalizeRouteSrc(route), + dest: normalizeRouteDest(route), + })); +} + +// Input is a rou3/radix3 compatible route pattern +// Output is a PCRE-compatible regular expression that matches each incoming pathname +// Reference: https://github.com/h3js/rou3/blob/main/src/regexp.ts +function normalizeRouteSrc(route: string): string { + let idCtr = 0; + return route + .split("/") + .map((segment) => { + if (segment.startsWith("**")) { + return segment === "**" ? "(?:.*)" : `?(?<${namedGroup(segment.slice(3))}>.+)`; + } + if (segment === "*") { + return `(?<_${idCtr++}>[^/]*)`; + } + if (segment.includes(":")) { + return segment + .replace(/:(\w+)/g, (_, id) => `(?<${namedGroup(id)}>[^/]+)`) + .replace(/\./g, String.raw`\.`); + } + return segment; + }) + .join("/"); +} + +// Valid PCRE capture group name +function namedGroup(input = "") { + if (/\d/.test(input[0])) { + input = `_${input}`; + } + return input.replace(/[^a-zA-Z0-9_]/g, "") || "_"; +} + +// Output is a destination pathname to function name +function normalizeRouteDest(route: string) { + return ( + route + .split("/") + .slice(1) + .map((segment) => { + if (segment.startsWith("**")) { + return `[...${segment.replace(/[*:]/g, "")}]`; + } + if (segment === "*") { + return "[-]"; + } + if (segment.startsWith(":")) { + return `[${segment.slice(1)}]`; + } + if (segment.includes(":")) { + return `[${segment.replace(/:/g, "_")}]`; + } + return segment; + }) + // Only use filesystem-safe characters + .map((segment) => segment.replace(SAFE_FS_CHAR_RE, "-")) + .join("/") || "index" + ); +} + +async function writePrerenderConfig( + filename: string, + isrConfig: NitroRouteRules["isr"], + bypassToken?: string +) { + // Normalize route rule + if (typeof isrConfig === "number") { + isrConfig = { expiration: isrConfig }; + } else if (isrConfig === true) { + isrConfig = { expiration: false }; + } else { + isrConfig = { ...isrConfig }; + } + + // Generate prerender config + const prerenderConfig: PrerenderFunctionConfig = { + expiration: isrConfig.expiration ?? false, + bypassToken, + ...isrConfig, + }; + + if (prerenderConfig.allowQuery && !prerenderConfig.allowQuery.includes(ISR_URL_PARAM)) { + prerenderConfig.allowQuery.push(ISR_URL_PARAM); + } + + await writeFile(filename, JSON.stringify(prerenderConfig, null, 2)); +} diff --git a/src/presets/winterjs/preset.ts b/src/presets/winterjs/preset.ts index ba948e544a..879e126078 100644 --- a/src/presets/winterjs/preset.ts +++ b/src/presets/winterjs/preset.ts @@ -1,9 +1,9 @@ -import { defineNitroPreset } from "nitropack/kit"; +import { defineNitroPreset } from "../_utils/preset.ts"; const winterjs = defineNitroPreset( { extends: "base-worker", - entry: "./runtime/winterjs", + entry: "./winterjs/runtime/winterjs", minify: false, serveStatic: "inline", wasm: { @@ -16,7 +16,6 @@ const winterjs = defineNitroPreset( }, { name: "winterjs" as const, - url: import.meta.url, } ); diff --git a/src/presets/winterjs/runtime/winterjs.ts b/src/presets/winterjs/runtime/winterjs.ts index 43ea4826a7..2cf4620e72 100644 --- a/src/presets/winterjs/runtime/winterjs.ts +++ b/src/presets/winterjs/runtime/winterjs.ts @@ -1,8 +1,6 @@ // @ts-nocheck TODO: Remove after removing polyfills -import "#nitro-internal-pollyfills"; -import { toPlainHandler } from "h3"; -import { useNitroApp } from "nitropack/runtime"; -import { toBuffer } from "nitropack/runtime/internal"; +import "#nitro/virtual/polyfills"; +import { useNitroApp } from "nitro/app"; import { hasProtocol, joinURL } from "ufo"; // Types are reverse engineered from runtime @@ -38,21 +36,21 @@ async function _handleEvent(event: FetchEvent) { headers: event.request.headers, context: { waitUntil: (promise: Promise) => event.waitUntil(promise), - winterjs: { - event, + _platform: { + winterjs: { + event, + }, }, }, }); - const body = - typeof res.body === "string" ? res.body : await toBuffer(res.body as any); + const body = typeof res.body === "string" ? res.body : await toBuffer(res.body as any); return new Response(body, { status: res.status, statusText: res.statusText, headers: res.headers, }); } catch (error: unknown) { - const errString = - (error as Error)?.message + "\n" + (error as Error)?.stack; + const errString = (error as Error)?.message + "\n" + (error as Error)?.stack; console.error(errString); return new Response(errString, { status: 500 }); } @@ -66,6 +64,27 @@ addEventListener("fetch" as any, async (event: FetchEvent) => { // Polyfills for missing APIs // ------------------------------ +function toBuffer(data: ReadableStream): Promise { + return new Promise((resolve, reject) => { + const chunks: Buffer[] = []; + data + .pipeTo( + new WritableStream({ + write(chunk) { + chunks.push(chunk); + }, + close() { + resolve(Buffer.concat(chunks)); + }, + abort(reason) { + reject(reason); + }, + }) + ) + .catch(reject); + }); +} + // Headers.entries if (!Headers.prototype.entries) { // @ts-ignore diff --git a/src/presets/zeabur/preset.ts b/src/presets/zeabur/preset.ts index 2dd84f9e62..ac86345dbc 100644 --- a/src/presets/zeabur/preset.ts +++ b/src/presets/zeabur/preset.ts @@ -1,15 +1,14 @@ import fsp from "node:fs/promises"; -import { writeFile } from "nitropack/kit"; -import { defineNitroPreset } from "nitropack/kit"; -import type { Nitro } from "nitropack/types"; +import { writeFile } from "../_utils/fs.ts"; +import { defineNitroPreset } from "../_utils/preset.ts"; +import type { Nitro } from "nitro/types"; import { dirname, relative, resolve } from "pathe"; // https://zeabur.com/docs/advanced/serverless-output-format const zeabur = defineNitroPreset( { - extends: "node", - entry: "./runtime/zeabur", + entry: "./zeabur/runtime/zeabur", output: { dir: "{{ rootDir }}/.zeabur/output", serverDir: "{{ output.dir }}/functions/__nitro.func", @@ -17,10 +16,7 @@ const zeabur = defineNitroPreset( }, hooks: { async compiled(nitro: Nitro) { - const buildConfigPath = resolve( - nitro.options.output.dir, - "config.json" - ); + const buildConfigPath = resolve(nitro.options.output.dir, "config.json"); const cfg = { containerized: false, routes: [{ src: ".*", dest: "/__nitro" }], @@ -32,14 +28,10 @@ const zeabur = defineNitroPreset( if (!value.isr) { continue; } - const funcPrefix = resolve( - nitro.options.output.serverDir, - ".." + key - ); + const funcPrefix = resolve(nitro.options.output.serverDir, ".." + key); await fsp.mkdir(dirname(funcPrefix), { recursive: true }); await fsp.symlink( - "./" + - relative(dirname(funcPrefix), nitro.options.output.serverDir), + "./" + relative(dirname(funcPrefix), nitro.options.output.serverDir), funcPrefix + ".func", "junction" ); @@ -54,7 +46,6 @@ const zeabur = defineNitroPreset( { name: "zeabur" as const, stdName: "zeabur", - url: import.meta.url, } ); @@ -71,7 +62,7 @@ const zeaburStatic = defineNitroPreset( }, { name: "zeabur-static" as const, - url: import.meta.url, + static: true, } ); diff --git a/src/presets/zeabur/runtime/zeabur.ts b/src/presets/zeabur/runtime/zeabur.ts index ab00d73a03..4a9b2db2e6 100644 --- a/src/presets/zeabur/runtime/zeabur.ts +++ b/src/presets/zeabur/runtime/zeabur.ts @@ -1,11 +1,5 @@ -import "#nitro-internal-pollyfills"; -import { type NodeListener, toNodeListener } from "h3"; -import { useNitroApp } from "nitropack/runtime"; +import "#nitro/virtual/polyfills"; +import { toNodeHandler } from "srvx/node"; +import { useNitroApp } from "nitro/app"; -const handler = toNodeListener(useNitroApp().h3App); - -const listener: NodeListener = function (req, res) { - return handler(req, res); -}; - -export default listener; +export default toNodeHandler(useNitroApp().fetch); diff --git a/src/presets/zephyr/preset.ts b/src/presets/zephyr/preset.ts new file mode 100644 index 0000000000..7657b0a1bb --- /dev/null +++ b/src/presets/zephyr/preset.ts @@ -0,0 +1,75 @@ +import { defineNitroPreset } from "../_utils/preset.ts"; +import type { Nitro } from "nitro/types"; +import { unenvCfExternals, unenvCfNodeCompat } from "../cloudflare/unenv/preset.ts"; +import { resolve } from "pathe"; +import { importDep } from "../../utils/dep.ts"; + +export type { ZephyrOptions as PresetOptions } from "./types.ts"; +const LOGGER_TAG = "zephyr-nitro-preset"; +type ZephyrAgentModule = Pick; + +const zephyr = defineNitroPreset( + { + extends: "base-worker", + entry: "./zephyr/runtime/server", + output: { + publicDir: "{{ output.dir }}/client/{{ baseURL }}", + }, + exportConditions: ["node"], + minify: false, + rollupConfig: { + output: { + format: "esm", + exports: "named", + inlineDynamicImports: false, + }, + }, + wasm: { + lazy: false, + esmImport: true, + }, + hooks: { + "build:before": (nitro: Nitro) => { + nitro.options.unenv.push(unenvCfExternals, unenvCfNodeCompat); + }, + compiled: async (nitro: Nitro) => { + try { + if (!(globalThis as any).__nitroDeploying__ && !nitro.options.zephyr?.deployOnBuild) { + nitro.logger.info(`[${LOGGER_TAG}] Zephyr deploy skipped on build.`); + return; + } + + const zephyrAgent = await importDep({ + id: "zephyr-agent", + reason: "deploying to Zephyr", + dir: nitro.options.rootDir, + }); + + const { deploymentUrl } = await zephyrAgent.uploadOutputToZephyr({ + rootDir: nitro.options.rootDir, + outputDir: nitro.options.output.dir, + baseURL: nitro.options.baseURL, + publicDir: resolve(nitro.options.output.dir, nitro.options.output.publicDir), + }); + if (deploymentUrl) { + nitro.logger.success(`[${LOGGER_TAG}] Zephyr deployment succeeded: ${deploymentUrl}`); + } else { + nitro.logger.success(`[${LOGGER_TAG}] Zephyr deployment succeeded.`); + } + + (globalThis as any).__nitroDeployed__ = true; + } catch (error) { + if (error instanceof Error) { + throw error; + } + throw new TypeError(`[${LOGGER_TAG}] ${String(error)}`); + } + }, + }, + }, + { + name: "zephyr" as const, + } +); + +export default [zephyr] as const; diff --git a/src/presets/zephyr/runtime/server.ts b/src/presets/zephyr/runtime/server.ts new file mode 100644 index 0000000000..91e3e309d9 --- /dev/null +++ b/src/presets/zephyr/runtime/server.ts @@ -0,0 +1,6 @@ +import "#nitro/virtual/polyfills"; +import { createHandler } from "../../cloudflare/runtime/_module-handler.ts"; + +export default createHandler({ + fetch() {}, +}); diff --git a/src/presets/zephyr/types.ts b/src/presets/zephyr/types.ts new file mode 100644 index 0000000000..acc564547c --- /dev/null +++ b/src/presets/zephyr/types.ts @@ -0,0 +1,8 @@ +export interface ZephyrOptions { + /** + * Deploy to Zephyr during `nitro build` when using the `zephyr` preset. + * + * @default false + */ + deployOnBuild?: boolean; +} diff --git a/src/presets/zerops/preset.ts b/src/presets/zerops/preset.ts index aff57c4822..4165f76dfe 100644 --- a/src/presets/zerops/preset.ts +++ b/src/presets/zerops/preset.ts @@ -1,12 +1,12 @@ -import { defineNitroPreset } from "nitropack/kit"; +import { defineNitroPreset } from "../_utils/preset.ts"; const zerops = defineNitroPreset( { extends: "node-server", + serveStatic: true, }, { name: "zerops" as const, - url: import.meta.url, } ); @@ -20,7 +20,7 @@ const zeropsStatic = defineNitroPreset( }, { name: "zerops-static" as const, - url: import.meta.url, + static: true, } ); diff --git a/src/preview.ts b/src/preview.ts new file mode 100644 index 0000000000..615db7e3f4 --- /dev/null +++ b/src/preview.ts @@ -0,0 +1,174 @@ +import type { ServerHandler, ServerRequest } from "srvx"; +import type { LoadOptions } from "srvx/loader"; +import { spawn } from "node:child_process"; +import consola from "consola"; +import { join, resolve } from "pathe"; +import { proxyFetch, proxyUpgrade, type ProxyUpgradeOptions } from "httpxy"; +import { prettyPath } from "./utils/fs.ts"; +import { getBuildInfo } from "./build/info.ts"; +import type { IncomingMessage } from "node:http"; +import type { Duplex } from "node:stream"; + +export interface PreviewInstance { + fetch: ServerHandler; + upgrade?: ( + req: IncomingMessage, + socket: Duplex, + head?: Buffer, + opts?: ProxyUpgradeOptions + ) => Promise; + close: () => Promise; +} + +export async function startPreview(opts: { + rootDir: string; + loader?: LoadOptions; +}): Promise { + const { outputDir, buildInfo } = await getBuildInfo(opts.rootDir); + if (!buildInfo) { + throw new Error("Cannot load nitro build info. Make sure to build first."); + } + + const info = [ + ["Build Directory:", prettyPath(outputDir)], + ["Date:", buildInfo.date && new Date(buildInfo.date).toLocaleString()], + ["Nitro Version:", buildInfo.versions.nitro], + ["Nitro Preset:", buildInfo.preset], + buildInfo.framework?.name !== "nitro" && [ + "Framework:", + buildInfo.framework?.name + + (buildInfo.framework?.version ? ` (v${buildInfo.framework.version})` : ""), + ], + ].filter((i) => i && i[1]) as [string, string][]; + consola.box({ + title: " [Build Info] ", + message: info.map((i) => `- ${i[0]} ${i[1]}`).join("\n"), + }); + + // Load .env files for preview mode + const dotEnvEntries = await loadPreviewDotEnv(opts.rootDir); + if (dotEnvEntries.length > 0) { + consola.box({ + title: " [Environment Variables] ", + message: [ + "Loaded variables from .env files (preview mode only).", + "Set platform environment variables for production:", + ...dotEnvEntries.map(([key, val]) => ` - ${key}`), + ].join("\n"), + }); + } + + // Currently cloudflare preset strictly requires preview command + if (buildInfo.preset.includes("cloudflare")) { + if (!buildInfo.commands?.preview) { + throw new Error(`No nitro build preview command found for the "${buildInfo.preset}" preset.`); + } + return await runPreviewCommand({ + command: buildInfo.commands.preview, + rootDir: opts.rootDir, + env: dotEnvEntries, + }); + } + + let fetchHandler: ServerHandler = () => + Promise.resolve(new Response("Not Found", { status: 404 })); + + if (buildInfo.serverEntry) { + for (const [key, val] of dotEnvEntries) { + if (!process.env[key]) { + process.env[key] = val; + } + } + const { loadServerEntry } = await import("srvx/loader"); + const entryPath = resolve(outputDir, buildInfo.serverEntry); + const entry = await loadServerEntry({ entry: entryPath, ...opts.loader }); + if (entry.fetch) { + fetchHandler = entry.fetch; + } + } + + if (buildInfo.publicDir) { + const { serveStatic } = await import("srvx/static"); + const staticHandler = serveStatic({ dir: join(outputDir, buildInfo.publicDir) }); + const originalFetchHandler = fetchHandler; + fetchHandler = async (req) => { + const staticRes: Response | undefined = await staticHandler(req, () => undefined as any); + if (staticRes) { + return staticRes; + } + return originalFetchHandler(req); + }; + } + + return { + fetch: fetchHandler, + async close() { + // No-op for in-process preview for now + }, + }; +} + +async function loadPreviewDotEnv(root: string): Promise<[string, string][]> { + const { loadDotenv } = await import("c12"); + const env = await loadDotenv({ + cwd: root, + fileName: [".env.preview", ".env.production", ".env"], + }); + return Object.entries(env).filter(([_key, val]) => val) as [string, string][]; +} + +async function runPreviewCommand(opts: { + command: string; + rootDir: string; + env: [string, string][]; +}): Promise { + const [arg0, ...args] = opts.command.split(" "); + + consola.info(`Spawning preview server...`); + consola.info(opts.command); + console.log(""); + + const { getRandomPort, waitForPort } = await import("get-port-please"); + const randomPort = await getRandomPort(); + const child = spawn(arg0, [...args, "--port", String(randomPort), "--host", "localhost"], { + stdio: "inherit", + cwd: opts.rootDir, + env: { + ...process.env, + ...Object.fromEntries(opts.env ?? []), + PORT: String(randomPort), + }, + }); + + const killChild = (signal: NodeJS.Signals) => { + if (child && !child.killed) { + child.kill(signal); + } + }; + + for (const sig of ["SIGINT", "SIGHUP"] as const) { + process.once(sig, () => { + killChild(sig); + }); + } + + child.once("exit", (code) => { + if (code && code !== 0) { + consola.error(`[nitro] Preview server exited with code ${code}`); + } + }); + + await waitForPort(randomPort, { retries: 20, delay: 500, host: "localhost" }); + + return { + fetch(req: ServerRequest) { + return proxyFetch({ port: randomPort, host: "localhost" }, req); + }, + async upgrade(req, socket, head, opts) { + await proxyUpgrade({ port: randomPort, host: "localhost" }, req, socket, head, opts); + }, + async close() { + killChild("SIGTERM"); + }, + }; +} diff --git a/src/rollup/config.ts b/src/rollup/config.ts deleted file mode 100644 index bd1502f591..0000000000 --- a/src/rollup/config.ts +++ /dev/null @@ -1,575 +0,0 @@ -import { builtinModules, createRequire } from "node:module"; -import { pathToFileURL } from "node:url"; -import { isAbsolute } from "node:path"; -import alias from "@rollup/plugin-alias"; -import commonjs from "@rollup/plugin-commonjs"; -import inject from "@rollup/plugin-inject"; -import json from "@rollup/plugin-json"; -import { nodeResolve } from "@rollup/plugin-node-resolve"; -import { defu } from "defu"; -import { sanitizeFilePath } from "mlly"; -import { resolveModulePath } from "exsolve"; -import { runtimeDependencies, runtimeDir } from "nitropack/runtime/meta"; -import type { - Nitro, - NitroStaticBuildFlags, - NodeExternalsOptions, - RollupConfig, -} from "nitropack/types"; -import { hash } from "ohash"; -import { dirname, join, normalize, resolve } from "pathe"; -import type { Plugin } from "rollup"; -import { visualizer } from "rollup-plugin-visualizer"; -import { isTest, isWindows } from "std-env"; -import { defineEnv } from "unenv"; -import unimportPlugin from "unimport/unplugin"; -import { rollup as unwasm } from "unwasm/plugin"; -import { appConfig } from "./plugins/app-config"; -import { database } from "./plugins/database"; -import { dynamicRequire } from "./plugins/dynamic-require"; -import { esbuild } from "./plugins/esbuild"; -import { externals } from "./plugins/externals"; -import { externals as legacyExternals } from "./plugins/externals-legacy"; -import { handlers } from "./plugins/handlers"; -import { handlersMeta } from "./plugins/handlers-meta"; -import { importMeta } from "./plugins/import-meta"; -import { publicAssets } from "./plugins/public-assets"; -import { raw } from "./plugins/raw"; -import { replace } from "./plugins/replace"; -import { serverAssets } from "./plugins/server-assets"; -import { sourcemapMininify } from "./plugins/sourcemap-min"; -import { storage } from "./plugins/storage"; -import { timing } from "./plugins/timing"; -import { virtual } from "./plugins/virtual"; -import { errorHandler } from "./plugins/error-handler"; -import { resolveAliases } from "./utils"; - -export const getRollupConfig = (nitro: Nitro): RollupConfig => { - const extensions: string[] = [ - ".ts", - ".mjs", - ".js", - ".json", - ".node", - ".tsx", - ".jsx", - ]; - - const isNodeless = nitro.options.node === false; - - const { env } = defineEnv({ - nodeCompat: isNodeless, - npmShims: true, - resolve: true, - presets: nitro.options.unenv, - overrides: { - alias: nitro.options.alias, - }, - }); - - const buildServerDir = join(nitro.options.buildDir, "dist/server"); - - const presetsDir = resolve(runtimeDir, "../presets"); - - const chunkNamePrefixes = [ - [nitro.options.buildDir, "build"], - [buildServerDir, "app"], - [runtimeDir, "nitro"], - [presetsDir, "nitro"], - ["\0raw:", "raw"], - ["\0nitro-wasm:", "wasm"], - ["\0", "virtual"], - ] as const; - - function getChunkGroup(id: string): string | void { - if (id.startsWith(runtimeDir) || id.startsWith(presetsDir)) { - return "nitro"; - } - } - - function getChunkName(id: string) { - // Known path prefixes - for (const [dir, name] of chunkNamePrefixes) { - if (id.startsWith(dir)) { - return `chunks/${name}/[name].mjs`; - } - } - - // Route handlers - const routeHandler = - nitro.options.handlers.find((h) => id.startsWith(h.handler as string)) || - nitro.scannedHandlers.find((h) => id.startsWith(h.handler as string)); - if (routeHandler?.route) { - const path = - routeHandler.route - .replace(/:([^/]+)/g, "_$1") - .replace(/\/[^/]+$/g, "") || "/"; - return `chunks/routes${path}/[name].mjs`; - } - - // Task handlers - const taskHandler = Object.entries(nitro.options.tasks).find( - ([_, task]) => task.handler === id - ); - if (taskHandler) { - return `chunks/tasks/[name].mjs`; - } - - // Unknown path - return `chunks/_/[name].mjs`; - } - - type _RollupConfig = Omit & { plugins: Plugin[] }; - - const rollupConfig: _RollupConfig = defu(nitro.options.rollupConfig as any, < - _RollupConfig - >{ - input: nitro.options.entry, - output: { - dir: nitro.options.output.serverDir, - entryFileNames: "index.mjs", - chunkFileNames(chunk) { - const lastModule = normalize(chunk.moduleIds.at(-1) || ""); - return getChunkName(lastModule); - }, - manualChunks(id) { - return getChunkGroup(id); - }, - inlineDynamicImports: nitro.options.inlineDynamicImports, - format: "esm", - exports: "auto", - intro: "", - outro: "", - generatedCode: { - constBindings: true, - }, - sanitizeFileName: sanitizeFilePath, - sourcemap: nitro.options.sourceMap, - sourcemapExcludeSources: true, - sourcemapIgnoreList(relativePath, sourcemapPath) { - return relativePath.includes("node_modules"); - }, - }, - external: [...env.external], - plugins: [], - onwarn(warning, rollupWarn) { - if ( - !["CIRCULAR_DEPENDENCY", "EVAL"].includes(warning.code || "") && - !warning.message.includes("Unsupported source map comment") - ) { - rollupWarn(warning); - } - }, - treeshake: { - moduleSideEffects(id) { - const normalizedId = normalize(id); - const idWithoutNodeModules = normalizedId.split("node_modules/").pop(); - if (!idWithoutNodeModules) { - return false; - } - if ( - normalizedId.startsWith(runtimeDir) || - idWithoutNodeModules.startsWith(runtimeDir) - ) { - return true; - } - return nitro.options.moduleSideEffects.some( - (m) => - normalizedId.startsWith(m) || idWithoutNodeModules.startsWith(m) - ); - }, - }, - }); - - if (rollupConfig.output.inlineDynamicImports) { - delete rollupConfig.output.manualChunks; - } - - if (nitro.options.timing) { - rollupConfig.plugins.push( - timing({ - silent: isTest, - }) - ); - } - - if (nitro.options.imports) { - rollupConfig.plugins.push( - unimportPlugin.rollup(nitro.options.imports) as Plugin - ); - } - - // Raw asset loader - rollupConfig.plugins.push(raw()); - - // WASM support - if (nitro.options.experimental.wasm) { - rollupConfig.plugins.push(unwasm(nitro.options.wasm || {})); - } - - // Build-time environment variables - let NODE_ENV = nitro.options.dev ? "development" : "production"; - if (nitro.options.preset === "nitro-prerender") { - NODE_ENV = "prerender"; - } - - const buildEnvVars = { - NODE_ENV, - prerender: nitro.options.preset === "nitro-prerender", - server: true, - client: false, - dev: String(nitro.options.dev), - DEBUG: nitro.options.dev, - }; - - const staticFlags: NitroStaticBuildFlags = { - dev: nitro.options.dev, - preset: nitro.options.preset, - prerender: nitro.options.preset === "nitro-prerender", - server: true, - client: false, - nitro: true, - baseURL: nitro.options.baseURL, - // @ts-expect-error - "versions.nitro": "", - "versions?.nitro": "", - // Internal - _asyncContext: nitro.options.experimental.asyncContext, - _websocket: nitro.options.experimental.websocket, - _tasks: nitro.options.experimental.tasks, - }; - - // Universal import.meta - rollupConfig.plugins.push(importMeta(nitro)); - - // https://github.com/rollup/plugins/tree/master/packages/replace - rollupConfig.plugins.push( - replace({ - preventAssignment: true, - values: { - "typeof window": '"undefined"', - _import_meta_url_: "import.meta.url", - "globalThis.process.": "process.", - "process.env.RUNTIME_CONFIG": () => - JSON.stringify(nitro.options.runtimeConfig, null, 2), - ...Object.fromEntries( - [".", ";", ")", "[", "]", "}", " "].map((d) => [ - `import.meta${d}`, - `globalThis._importMeta_${d}`, - ]) - ), - ...Object.fromEntries( - [";", "(", "{", "}", " ", "\t", "\n"].map((d) => [ - `${d}global.`, - `${d}globalThis.`, - ]) - ), - ...Object.fromEntries( - Object.entries(buildEnvVars).map(([key, val]) => [ - `process.env.${key}`, - JSON.stringify(val), - ]) - ), - ...Object.fromEntries( - Object.entries(buildEnvVars).map(([key, val]) => [ - `import.meta.env.${key}`, - JSON.stringify(val), - ]) - ), - ...Object.fromEntries( - Object.entries(staticFlags).map(([key, val]) => [ - `process.${key}`, - JSON.stringify(val), - ]) - ), - ...Object.fromEntries( - Object.entries(staticFlags).map(([key, val]) => [ - `import.meta.${key}`, - JSON.stringify(val), - ]) - ), - ...nitro.options.replace, - }, - }) - ); - - // esbuild - rollupConfig.plugins.push( - esbuild({ - target: "es2019", - sourceMap: nitro.options.sourceMap, - ...nitro.options.esbuild?.options, - }) - ); - - // Dynamic Require Support - rollupConfig.plugins.push( - dynamicRequire({ - dir: resolve(nitro.options.buildDir, "dist/server"), - inline: - nitro.options.node === false || nitro.options.inlineDynamicImports, - ignore: [ - "client.manifest.mjs", - "server.js", - "server.cjs", - "server.mjs", - "server.manifest.mjs", - ], - }) - ); - - // Server assets - rollupConfig.plugins.push(serverAssets(nitro)); - - // Public assets - rollupConfig.plugins.push(publicAssets(nitro)); - - // Storage - rollupConfig.plugins.push(storage(nitro)); - - // Database - rollupConfig.plugins.push(database(nitro)); - - // App.config - rollupConfig.plugins.push(appConfig(nitro)); - - // Handlers - rollupConfig.plugins.push(handlers(nitro)); - - // Handlers meta - if (nitro.options.experimental.openAPI) { - rollupConfig.plugins.push(handlersMeta(nitro)); - } - - // Error handler - rollupConfig.plugins.push(errorHandler(nitro)); - - // Polyfill - rollupConfig.plugins.push( - virtual( - { - "#nitro-internal-pollyfills": - env.polyfill.map((p) => `import '${p}';`).join("\n") || - `/* No polyfills */`, - }, - nitro.vfs - ) - ); - - // User virtuals - rollupConfig.plugins.push(virtual(nitro.options.virtual, nitro.vfs)); - - const nitroPlugins = [...new Set(nitro.options.plugins)]; - - // Plugins - rollupConfig.plugins.push( - virtual( - { - "#nitro-internal-virtual/plugins": ` -${nitroPlugins - .map( - (plugin) => `import _${hash(plugin).replace(/-/g, "")} from '${plugin}';` - ) - .join("\n")} - -export const plugins = [ - ${nitroPlugins.map((plugin) => `_${hash(plugin).replace(/-/g, "")}`).join(",\n")} -] - `, - }, - nitro.vfs - ) - ); - - // https://github.com/rollup/plugins/tree/master/packages/alias - let buildDir = nitro.options.buildDir; - // Windows (native) dynamic imports should be file:// urls - if ( - isWindows && - nitro.options.externals?.trace === false && - nitro.options.dev - ) { - buildDir = pathToFileURL(buildDir).href; - } - rollupConfig.plugins.push( - alias({ - entries: resolveAliases({ - "#build": buildDir, - "#internal/nitro": runtimeDir, - "nitro/runtime": runtimeDir, - "nitropack/runtime": runtimeDir, - "~": nitro.options.srcDir, - "@/": nitro.options.srcDir, - "~~": nitro.options.rootDir, - "@@/": nitro.options.rootDir, - ...env.alias, - }), - }) - ); - - // Externals Plugin - if (nitro.options.noExternals) { - rollupConfig.plugins.push({ - name: "no-externals", - async resolveId(id, importer, resolveOpts) { - if ( - nitro.options.node && - (id.startsWith("node:") || builtinModules.includes(id)) - ) { - return { id, external: true }; - } - const resolved = await this.resolve(id, importer, resolveOpts); - if (!resolved) { - const _resolved = resolveModulePath(id, { - try: true, - from: - importer && isAbsolute(importer) - ? [pathToFileURL(importer), ...nitro.options.nodeModulesDirs] - : nitro.options.nodeModulesDirs, - suffixes: ["", "/index"], - extensions: [".mjs", ".cjs", ".js", ".mts", ".cts", ".ts", ".json"], - conditions: [ - "default", - nitro.options.dev ? "development" : "production", - "node", - "import", - "require", - ], - }); - if (_resolved) { - return { id: _resolved, external: false }; - } - } - if (!resolved || (resolved.external && !id.endsWith(".wasm"))) { - throw new Error( - `Cannot resolve ${JSON.stringify(id)} from ${JSON.stringify( - importer - )} and externals are not allowed!` - ); - } - }, - }); - } else { - const externalsPlugin = nitro.options.experimental.legacyExternals - ? legacyExternals - : externals; - rollupConfig.plugins.push( - externalsPlugin( - defu(nitro.options.externals, { - outDir: nitro.options.output.serverDir, - moduleDirectories: nitro.options.nodeModulesDirs, - external: [ - ...(nitro.options.dev ? [nitro.options.buildDir] : []), - ...nitro.options.nodeModulesDirs, - ], - inline: [ - "#", - "~", - "@/", - "~~", - "@@/", - "virtual:", - "nitro/runtime", - "nitropack/runtime", - dirname(nitro.options.entry), - ...(nitro.options.experimental.wasm - ? [(id: string) => id?.endsWith(".wasm")] - : []), - runtimeDir, - nitro.options.srcDir, - ...nitro.options.handlers - .map((m) => m.handler) - .filter((i) => typeof i === "string"), - ...(nitro.options.dev || - nitro.options.preset === "nitro-prerender" || - nitro.options.experimental.bundleRuntimeDependencies === false - ? [] - : runtimeDependencies), - ], - traceOptions: { - base: "/", - processCwd: nitro.options.rootDir, - exportsOnly: true, - }, - traceAlias: { - "h3-nightly": "h3", - ...nitro.options.externals?.traceAlias, - }, - exportConditions: nitro.options.exportConditions, - }) - ) - ); - } - - // https://github.com/rollup/plugins/tree/master/packages/node-resolve - rollupConfig.plugins.push( - nodeResolve({ - extensions, - preferBuiltins: !!nitro.options.node, - rootDir: nitro.options.rootDir, - modulePaths: nitro.options.nodeModulesDirs, - // 'module' is intentionally not supported because of externals - mainFields: ["main"], - exportConditions: nitro.options.exportConditions, - }) - ); - - // https://github.com/rollup/plugins/tree/master/packages/commonjs - rollupConfig.plugins.push( - commonjs({ - strictRequires: "auto", // TODO: set to true (default) in v3 - esmExternals: (id) => !id.startsWith("unenv/"), - requireReturnsDefault: "auto", - ...nitro.options.commonJS, - }) - ); - - // https://github.com/rollup/plugins/tree/master/packages/json - rollupConfig.plugins.push(json()); - - // https://github.com/rollup/plugins/tree/master/packages/inject - rollupConfig.plugins.push(inject(env.inject)); - - // https://www.npmjs.com/package/@rollup/plugin-terser - // https://github.com/terser/terser#minify-options - if (nitro.options.minify) { - const _terser = createRequire(import.meta.url)("@rollup/plugin-terser"); - const terser = _terser.default || _terser; - rollupConfig.plugins.push( - terser({ - mangle: { - keep_fnames: true, - keep_classnames: true, - }, - format: { - comments: false, - }, - }) - ); - } - - // Minify sourcemaps - if ( - nitro.options.sourceMap && - !nitro.options.dev && - nitro.options.experimental.sourcemapMinify !== false - ) { - rollupConfig.plugins.push(sourcemapMininify()); - } - - if (nitro.options.analyze) { - // https://github.com/btd/rollup-plugin-visualizer - rollupConfig.plugins.push( - visualizer({ - ...nitro.options.analyze, - filename: (nitro.options.analyze.filename || "stats.html").replace( - "{name}", - "nitro" - ), - title: "Nitro Server bundle stats", - }) - ); - } - - return rollupConfig; -}; diff --git a/src/rollup/index.ts b/src/rollup/index.ts deleted file mode 100644 index 5c62e04f5e..0000000000 --- a/src/rollup/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./config"; diff --git a/src/rollup/plugins/app-config.ts b/src/rollup/plugins/app-config.ts deleted file mode 100644 index c5c4b48a59..0000000000 --- a/src/rollup/plugins/app-config.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { genImport } from "knitwork"; -import type { Nitro } from "nitropack/types"; -import { virtual } from "./virtual"; - -export function appConfig(nitro: Nitro) { - return virtual( - { - "#nitro-internal-virtual/app-config": () => ` -import { defuFn } from 'defu'; - -const inlineAppConfig = ${JSON.stringify(nitro.options.appConfig, null, 2)}; - -${nitro.options.appConfigFiles - .map((file, i) => genImport(file, "appConfig" + i) + ";") - .join("\n")} - -export const appConfig = defuFn(${[ - ...nitro.options.appConfigFiles.map((_, i) => "appConfig" + i), - "inlineAppConfig", - ].join(", ")}); - `, - }, - nitro.vfs - ); -} diff --git a/src/rollup/plugins/database.ts b/src/rollup/plugins/database.ts deleted file mode 100644 index 6a055be043..0000000000 --- a/src/rollup/plugins/database.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { connectors } from "db0"; -import type { Nitro } from "nitropack/types"; -import { camelCase } from "scule"; -import { virtual } from "./virtual"; - -export function database(nitro: Nitro) { - if (!nitro.options.experimental.database) { - return virtual( - { - "#nitro-internal-virtual/database": () => { - return /* js */ `export const connectionConfigs = {};`; - }, - }, - nitro.vfs - ); - } - - const dbConfigs = - (nitro.options.dev && nitro.options.devDatabase) || nitro.options.database; - - const connectorsNames = [ - ...new Set( - Object.values(dbConfigs || {}).map((config) => config?.connector) - ), - ].filter(Boolean); - - for (const name of connectorsNames) { - if (!connectors[name]) { - throw new Error(`Database connector "${name}" is invalid.`); - } - } - - return virtual( - { - "#nitro-internal-virtual/database": () => { - return ` -${connectorsNames - .map( - (name) => `import ${camelCase(name)}Connector from "${connectors[name]}";` - ) - .join("\n")} - -export const connectionConfigs = { - ${Object.entries(dbConfigs || {}) - .map( - ([name, { connector, options }]) => - `${name}: { - connector: ${camelCase(connector)}Connector, - options: ${JSON.stringify(options)} - }` - ) - .join(",\n")} -}; - `; - }, - }, - nitro.vfs - ); -} diff --git a/src/rollup/plugins/dynamic-require.ts b/src/rollup/plugins/dynamic-require.ts deleted file mode 100644 index 49643e3437..0000000000 --- a/src/rollup/plugins/dynamic-require.ts +++ /dev/null @@ -1,135 +0,0 @@ -import { pathToFileURL } from "node:url"; -import { globby } from "globby"; -import { genSafeVariableName } from "knitwork"; -import { resolve } from "pathe"; -import type { Plugin } from "rollup"; - -const PLUGIN_NAME = "dynamic-require"; -const HELPER_DYNAMIC = `\0${PLUGIN_NAME}.mjs`; -const DYNAMIC_REQUIRE_RE = /import\("\.\/" ?\+(.*)\).then/g; - -interface Options { - dir: string; - inline: boolean; - ignore: string[]; - outDir?: string; - prefix?: string; -} - -interface Chunk { - id: string; - src: string; - name: string; - meta?: { - id?: string; - ids?: string[]; - moduleIds?: string[]; - }; -} - -interface TemplateContext { - chunks: Chunk[]; -} - -export function dynamicRequire({ dir, ignore, inline }: Options): Plugin { - return { - name: PLUGIN_NAME, - transform(code: string, _id: string) { - return { - code: code.replace( - DYNAMIC_REQUIRE_RE, - `import('${HELPER_DYNAMIC}').then(r => r.default || r).then(dynamicRequire => dynamicRequire($1)).then` - ), - map: null, - }; - }, - resolveId(id: string) { - return id === HELPER_DYNAMIC ? id : null; - }, - // TODO: Async chunk loading over network! - // renderDynamicImport () { - // return { - // left: 'fetch(', right: ')' - // } - // }, - async load(_id: string) { - if (_id !== HELPER_DYNAMIC) { - return null; - } - - // Scan chunks - let files = []; - try { - const wpManifest = resolve(dir, "./server.manifest.json"); - files = await import(pathToFileURL(wpManifest).href).then((r) => - Object.keys(r.files).filter((file) => !ignore.includes(file)) - ); - } catch { - files = await globby("**/*.{cjs,mjs,js}", { - cwd: dir, - absolute: false, - ignore, - }); - } - - const chunks = ( - await Promise.all( - files.map(async (id) => ({ - id, - src: resolve(dir, id).replace(/\\/g, "/"), - name: genSafeVariableName(id), - meta: await getWebpackChunkMeta(resolve(dir, id)), - })) - ) - ).filter((chunk) => chunk.meta) as Chunk[]; - - return inline ? TMPL_INLINE({ chunks }) : TMPL_LAZY({ chunks }); - }, - }; -} - -async function getWebpackChunkMeta(src: string) { - const chunk = await import(pathToFileURL(src).href).then( - (r) => r.default || r || {} - ); - const { - __webpack_id__, - __webpack_ids__, - __webpack_modules__, - id = __webpack_id__, - ids = __webpack_ids__, - modules = __webpack_modules__, - } = chunk; - if (!id && !ids) { - return null; // Not a webpack chunk - } - return { - id, - ids, - moduleIds: Object.keys(modules || {}), - }; -} - -function TMPL_INLINE({ chunks }: TemplateContext) { - return `${chunks - .map((i) => `import * as ${i.name} from '${i.src}'`) - .join("\n")} -const dynamicChunks = { - ${chunks.map((i) => ` ['${i.id}']: ${i.name}`).join(",\n")} -}; - -export default function dynamicRequire(id) { - return Promise.resolve(dynamicChunks[id]); -};`; -} - -function TMPL_LAZY({ chunks }: TemplateContext) { - return ` -const dynamicChunks = { -${chunks.map((i) => ` ['${i.id}']: () => import('${i.src}')`).join(",\n")} -}; - -export default function dynamicRequire(id) { - return dynamicChunks[id](); -};`; -} diff --git a/src/rollup/plugins/error-handler.ts b/src/rollup/plugins/error-handler.ts deleted file mode 100644 index 2904adab47..0000000000 --- a/src/rollup/plugins/error-handler.ts +++ /dev/null @@ -1,45 +0,0 @@ -import type { Nitro } from "nitropack/types"; -import { virtual } from "./virtual"; -import { runtimeDir } from "nitropack/runtime/meta"; -import { join } from "pathe"; - -export function errorHandler(nitro: Nitro) { - return virtual( - { - "#nitro-internal-virtual/error-handler": () => { - const errorHandlers = Array.isArray(nitro.options.errorHandler) - ? nitro.options.errorHandler - : [nitro.options.errorHandler]; - - const builtinHandler = join( - runtimeDir, - `internal/error/${nitro.options.dev ? "dev" : "prod"}` - ); - - return /* js */ ` -${errorHandlers.map((h, i) => `import errorHandler$${i} from "${h}";`).join("\n")} - -const errorHandlers = [${errorHandlers.map((_, i) => `errorHandler$${i}`).join(", ")}]; - -import { defaultHandler } from "${builtinHandler}"; - -export default async function(error, event) { - for (const handler of errorHandlers) { - try { - await handler(error, event, { defaultHandler }); - if (event.handled) { - return; // Response handled - } - } catch(error) { - // Handler itself thrown, log and continue - console.error(error); - } - } - // H3 will handle fallback -} -`; - }, - }, - nitro.vfs - ); -} diff --git a/src/rollup/plugins/esbuild.ts b/src/rollup/plugins/esbuild.ts deleted file mode 100644 index 5a39ae0cf6..0000000000 --- a/src/rollup/plugins/esbuild.ts +++ /dev/null @@ -1,117 +0,0 @@ -// Based on https://github.com/egoist/rollup-plugin-esbuild (MIT) - -import { createFilter } from "unplugin-utils"; -import { type Loader, type TransformResult, transform } from "esbuild"; -import type { EsbuildOptions } from "nitropack/types"; -import { extname, relative } from "pathe"; -import type { Plugin, PluginContext } from "rollup"; - -const defaultLoaders: { [ext: string]: Loader } = { - ".ts": "ts", - ".js": "js", - ".tsx": "tsx", - ".jsx": "jsx", -}; - -export function esbuild(options: EsbuildOptions): Plugin { - const { - include, - exclude, - sourceMap, - loaders: loadersConfig, - minify, - ...transformOptions - } = options; - - const loaders = { ...defaultLoaders }; - if (loadersConfig) { - for (const key of Object.keys(loadersConfig)) { - const value = loadersConfig[key]; - if (typeof value === "string") { - loaders[key] = value; - } else if (value === false) { - delete loaders[key]; - } - } - } - - const extensions: string[] = Object.keys(loaders); - const INCLUDE_REGEXP = new RegExp( - `\\.(${extensions.map((ext) => ext.slice(1)).join("|")})$` - ); - const EXCLUDE_REGEXP = /node_modules/; - - const filter = createFilter( - include || INCLUDE_REGEXP, - exclude || EXCLUDE_REGEXP - ); - - return { - name: "esbuild", - - async transform(code, id) { - if (!filter(id)) { - return null; - } - - const ext = extname(id); - const loader = loaders[ext]; - - if (!loader) { - return null; - } - - const result = await transform(code, { - sourcemap: sourceMap === "hidden" ? "external" : sourceMap, - ...transformOptions, - loader, - sourcefile: id, - }); - - printWarnings(id, result, this); - - return ( - result.code && { - code: result.code, - map: result.map || null, - } - ); - }, - - async renderChunk(code) { - if (minify) { - const result = await transform(code, { - loader: "js", - minify: true, - target: transformOptions.target, - }); - if (result.code) { - return { - code: result.code, - map: result.map || null, - }; - } - } - return null; - }, - }; -} - -function printWarnings( - id: string, - result: TransformResult, - plugin: PluginContext -) { - if (result.warnings) { - for (const warning of result.warnings) { - let message = "[esbuild]"; - if (warning.location) { - message += ` (${relative(process.cwd(), id)}:${warning.location.line}:${ - warning.location.column - })`; - } - message += ` ${warning.text}`; - plugin.warn(message); - } - } -} diff --git a/src/rollup/plugins/externals-legacy.ts b/src/rollup/plugins/externals-legacy.ts deleted file mode 100644 index 5eb553a9d5..0000000000 --- a/src/rollup/plugins/externals-legacy.ts +++ /dev/null @@ -1,359 +0,0 @@ -import { existsSync, promises as fsp } from "node:fs"; -import { type NodeFileTraceOptions, nodeFileTrace } from "@vercel/nft"; -import { consola } from "consola"; -import { isValidNodeImport, normalizeid, resolvePath } from "mlly"; -import { isDirectory } from "nitropack/kit"; -import { dirname, isAbsolute, join, normalize, resolve } from "pathe"; -import type { Plugin } from "rollup"; -import semver from "semver"; -import { normalizeMatcher } from "./externals"; - -interface NodeExternalsOptions { - inline?: Array< - | string - | RegExp - | ((id: string, importer?: string) => Promise | boolean) - >; - external?: Array< - | string - | RegExp - | ((id: string, importer?: string) => Promise | boolean) - >; - outDir?: string; - trace?: boolean; - traceOptions?: NodeFileTraceOptions; - moduleDirectories?: string[]; - exportConditions?: string[]; - traceInclude?: string[]; -} - -export function externals(opts: NodeExternalsOptions): Plugin { - const trackedExternals = new Set(); - - const _resolveCache = new Map(); - const _resolve = async (id: string) => { - let resolved = _resolveCache.get(id); - if (resolved) { - return resolved; - } - resolved = await resolvePath(id, { - conditions: opts.exportConditions, - url: opts.moduleDirectories, - }); - _resolveCache.set(id, resolved); - return resolved; - }; - - // Normalize options - const inlineMatchers = (opts.inline || []).map((p) => normalizeMatcher(p)); - const externalMatchers = (opts.external || []).map((p) => - normalizeMatcher(p) - ); - - return { - name: "node-externals", - async resolveId(originalId, importer, resolveOpts) { - // Skip internals - if ( - !originalId || - originalId.startsWith("\u0000") || - originalId.includes("?") || - originalId.startsWith("#") - ) { - return null; - } - - // Skip relative paths - if (originalId.startsWith(".")) { - return null; - } - - // Normalize path (windows) - const id = normalize(originalId); - - // Check for explicit inlines - for (const matcher of inlineMatchers) { - if (matcher(id, importer)) { - return null; - } - } - - // Check for explicit externals - for (const matcher of externalMatchers) { - if (matcher(id, importer)) { - return { id, external: true }; - } - } - - // Resolve id using rollup resolver - const resolved = (await this.resolve( - originalId, - importer, - resolveOpts - )) || { - id, - }; - - // Try resolving with mlly as fallback - if ( - !isAbsolute(resolved.id) || - !existsSync(resolved.id) || - (await isDirectory(resolved.id)) - ) { - resolved.id = await _resolve(resolved.id).catch(() => resolved.id); - } - - // Inline invalid node imports - if (!(await isValidNodeImport(resolved.id).catch(() => false))) { - return null; - } - - // Externalize with full path if trace is disabled - if (opts.trace === false) { - return { - ...resolved, - id: isAbsolute(resolved.id) ? normalizeid(resolved.id) : resolved.id, - external: true, - }; - } - - // -- Trace externals -- - - // Try to extract package name from path - const { pkgName, subpath } = parseNodeModulePath(resolved.id); - - // Inline if cannot detect package name - if (!pkgName) { - return null; - } - - // Normally package name should be same as originalId - // Edge cases: Subpath export and full paths - if (pkgName !== originalId) { - // Subpath export - if (!isAbsolute(originalId)) { - const fullPath = await _resolve(originalId); - trackedExternals.add(fullPath); - return { - id: originalId, - external: true, - }; - } - - // Absolute path, we are not sure about subpath to generate import statement - // Guess as main subpath export - const packageEntry = await _resolve(pkgName).catch(() => null); - if (packageEntry !== originalId) { - // Guess subpathexport - const guessedSubpath = pkgName + subpath.replace(/\.[a-z]+$/, ""); - const resolvedGuess = await _resolve(guessedSubpath).catch( - () => null - ); - if (resolvedGuess === originalId) { - trackedExternals.add(resolvedGuess); - return { - id: guessedSubpath, - external: true, - }; - } - // Inline since we cannot guess subpath - return null; - } - } - - trackedExternals.add(resolved.id); - return { - id: pkgName, - external: true, - }; - }, - async buildEnd() { - if (opts.trace === false) { - return; - } - - // Force trace paths - for (const pkgName of opts.traceInclude || []) { - const path = await this.resolve(pkgName); - if (path?.id) { - trackedExternals.add(path.id.replace(/\?.+/, "")); - } - } - - // Trace files - let tracedFiles = await nodeFileTrace( - [...trackedExternals], - opts.traceOptions - ) - .then((r) => - [...r.fileList].map((f) => resolve(opts.traceOptions!.base!, f)) - ) - .then((r) => r.filter((file) => file.includes("node_modules"))); - - // Resolve symlinks - tracedFiles = await Promise.all( - tracedFiles.map((file) => fsp.realpath(file)) - ); - - // Read package.json with cache - const packageJSONCache = new Map(); // pkgDir => contents - const getPackageJson = async (pkgDir: string) => { - if (packageJSONCache.has(pkgDir)) { - return packageJSONCache.get(pkgDir); - } - const pkgJSON = JSON.parse( - await fsp.readFile(resolve(pkgDir, "package.json"), "utf8") - ); - packageJSONCache.set(pkgDir, pkgJSON); - return pkgJSON; - }; - - // Keep track of npm packages - const tracedPackages = new Map(); // name => pkgDir - const ignoreDirs = [] as string[]; - const ignoreWarns = new Set(); - for (const file of tracedFiles) { - const { baseDir, pkgName } = parseNodeModulePath(file); - if (!pkgName) { - continue; - } - let pkgDir = resolve(baseDir, pkgName); - - // Check for duplicate versions - const existingPkgDir = tracedPackages.get(pkgName); - if (existingPkgDir && existingPkgDir !== pkgDir) { - const v1 = await getPackageJson(existingPkgDir).then( - (r) => r.version - ); - const v2 = await getPackageJson(pkgDir).then((r) => r.version); - const isNewer = semver.gt(v2, v1); - - // Warn about major version differences - const getMajor = (v: string) => v.split(".").find((s) => s !== "0"); - if (getMajor(v1) !== getMajor(v2)) { - const warn = - `Multiple major versions of package \`${pkgName}\` are being externalized. Picking latest version:\n\n` + - [ - ` ${isNewer ? "-" : "+"} ` + existingPkgDir + "@" + v1, - ` ${isNewer ? "+" : "-"} ` + pkgDir + "@" + v2, - ].join("\n"); - if (!ignoreWarns.has(warn)) { - consola.warn(warn); - ignoreWarns.add(warn); - } - } - - const [newerDir, olderDir] = isNewer - ? [pkgDir, existingPkgDir] - : [existingPkgDir, pkgDir]; - // Try to map traced files from one package to another for minor/patch versions - if (getMajor(v1) === getMajor(v2)) { - tracedFiles = tracedFiles.map((f) => - f.startsWith(olderDir + "/") ? f.replace(olderDir, newerDir) : f - ); - } - // Exclude older version files - ignoreDirs.push(olderDir + "/"); - pkgDir = newerDir; // Update for tracedPackages - } - - // Add to traced packages - tracedPackages.set(pkgName, pkgDir); - } - - // Filter out files from ignored packages and dedup - tracedFiles = tracedFiles.filter( - (f) => !ignoreDirs.some((d) => f.startsWith(d)) - ); - tracedFiles = [...new Set(tracedFiles)]; - - // Ensure all package.json files are traced - for (const pkgDir of tracedPackages.values()) { - const pkgJSON = join(pkgDir, "package.json"); - if (!tracedFiles.includes(pkgJSON)) { - tracedFiles.push(pkgJSON); - } - } - - const writeFile = async (file: string) => { - if (!(await isFile(file))) { - return; - } - const src = resolve(opts.traceOptions!.base!, file); - const { pkgName, subpath } = parseNodeModulePath(file); - const dst = resolve(opts.outDir!, `node_modules/${pkgName! + subpath}`); - await fsp.mkdir(dirname(dst), { recursive: true }); - try { - await fsp.copyFile(src, dst); - } catch { - consola.warn(`Could not resolve \`${src}\`. Skipping.`); - } - }; - - // Write traced files - await Promise.all( - tracedFiles.map((file) => retry(() => writeFile(file), 3)) - ); - - // Write an informative package.json - await fsp.writeFile( - resolve(opts.outDir!, "package.json"), - JSON.stringify( - { - name: "nitro-output", - version: "0.0.0", - private: true, - bundledDependencies: [...tracedPackages.keys()].sort(), - }, - null, - 2 - ), - "utf8" - ); - }, - }; -} - -function parseNodeModulePath(path: string) { - if (!path) { - return {}; - } - const match = /^(.+\/node_modules\/)([^/@]+|@[^/]+\/[^/]+)(\/?.*?)?$/.exec( - normalize(path) - ); - if (!match) { - return {}; - } - const [, baseDir, pkgName, subpath] = match; - return { - baseDir, - pkgName, - subpath, - }; -} - -async function isFile(file: string) { - try { - const stat = await fsp.stat(file); - return stat.isFile(); - } catch (error: any) { - if (error.code === "ENOENT") { - return false; - } - throw error; - } -} - -async function retry(fn: () => Promise, retries: number) { - let retry = 0; - let lastError: any; - while (retry++ < retries) { - try { - return await fn(); - } catch (error) { - lastError = error; - await new Promise((resolve) => setTimeout(resolve, 2)); - } - } - throw lastError; -} diff --git a/src/rollup/plugins/externals.ts b/src/rollup/plugins/externals.ts deleted file mode 100644 index 1d50d36608..0000000000 --- a/src/rollup/plugins/externals.ts +++ /dev/null @@ -1,562 +0,0 @@ -import { existsSync, promises as fsp } from "node:fs"; -import { platform } from "node:os"; -import { fileURLToPath, pathToFileURL } from "node:url"; -import { nodeFileTrace } from "@vercel/nft"; -import { - isValidNodeImport, - lookupNodeModuleSubpath, - normalizeid, - parseNodeModulePath, -} from "mlly"; -import { resolveModuleURL } from "exsolve"; -import { isDirectory } from "nitropack/kit"; -import type { NodeExternalsOptions } from "nitropack/types"; -import { dirname, isAbsolute, join, normalize, relative, resolve } from "pathe"; -import type { PackageJson } from "pkg-types"; -import { readPackageJSON, writePackageJSON } from "pkg-types"; -import type { Plugin } from "rollup"; -import semver from "semver"; - -export function externals(opts: NodeExternalsOptions): Plugin { - const trackedExternals = new Set(); - - const tryResolve = ( - id: string, - importer: undefined | string - ): string | undefined => { - if (id.startsWith("\0")) { - return id; - } - const res = resolveModuleURL(id, { - try: true, - conditions: opts.exportConditions, - from: - importer && isAbsolute(importer) - ? [pathToFileURL(importer), ...opts.moduleDirectories!] - : opts.moduleDirectories, - suffixes: ["", "/index"], - extensions: [".mjs", ".cjs", ".js", ".mts", ".cts", ".ts", ".json"], - }); - return res?.startsWith("file://") ? fileURLToPath(res) : res; - }; - - // Normalize options - const inlineMatchers = (opts.inline || []) - .map((p) => normalizeMatcher(p)) - .sort((a, b) => (b.score || 0) - (a.score || 0)); - const externalMatchers = (opts.external || []) - .map((p) => normalizeMatcher(p)) - .sort((a, b) => (b.score || 0) - (a.score || 0)); - - // Utility to check explicit inlines - const isExplicitInline = (id: string, importer?: string) => { - if (id.startsWith("\0")) { - return true; - } - const inlineMatch = inlineMatchers.find((m) => m(id, importer)); - const externalMatch = externalMatchers.find((m) => m(id, importer)); - if ( - inlineMatch && - (!externalMatch || - (externalMatch && - (inlineMatch.score || 0) > (externalMatch.score || 0))) - ) { - return true; - } - }; - - return { - name: "node-externals", - async resolveId(originalId, importer, options) { - // Skip internals - if ( - !originalId || - originalId.startsWith("\u0000") || - originalId.includes("?") || - originalId.startsWith("#") - ) { - return null; - } - - // Skip relative paths - if (originalId.startsWith(".")) { - return null; - } - - // Normalize path (windows) - const id = normalize(originalId); - - // Check for explicit inlines and externals - if (isExplicitInline(id, importer)) { - return null; - } - - // Resolve id using rollup resolver - const resolved = (await this.resolve(originalId, importer, options)) || { - id, - }; - - // Check for explicit inlines and externals - if (isExplicitInline(resolved.id, importer)) { - return null; - } - - // Try resolving with Node.js algorithm as fallback - if ( - !isAbsolute(resolved.id) || - !existsSync(resolved.id) || - (await isDirectory(resolved.id)) - ) { - resolved.id = tryResolve(resolved.id, importer) || resolved.id; - } - - // Inline invalid node imports - if (!(await isValidNodeImport(resolved.id).catch(() => false))) { - return null; - } - - // Externalize with full path if trace is disabled - if (opts.trace === false) { - return { - ...resolved, - id: isAbsolute(resolved.id) ? normalizeid(resolved.id) : resolved.id, - external: true, - }; - } - - // -- Trace externals -- - - // Try to extract package name from path - const { name: pkgName } = parseNodeModulePath(resolved.id); - - // Inline if cannot detect package name - if (!pkgName) { - return null; - } - - // Normally package name should be same as originalId - // Edge cases: Subpath export and full paths - if (pkgName !== originalId) { - // Subpath export - if (!isAbsolute(originalId)) { - const fullPath = tryResolve(originalId, importer); - if (fullPath) { - trackedExternals.add(fullPath); - return { - id: originalId, - external: true, - }; - } - } - - // Absolute path, we are not sure about subpath to generate import statement - // Guess as main subpath export - const packageEntry = tryResolve(pkgName, importer); - if (packageEntry !== id) { - // Reverse engineer subpath export - const guessedSubpath: string | null | undefined = - await lookupNodeModuleSubpath(id).catch(() => null); - const resolvedGuess = - guessedSubpath && - tryResolve(join(pkgName, guessedSubpath), importer); - if (resolvedGuess === id) { - trackedExternals.add(resolvedGuess); - return { - id: join(pkgName, guessedSubpath!), - external: true, - }; - } - // Inline since we cannot guess subpath - return null; - } - } - - trackedExternals.add(resolved.id); - return { - id: pkgName, - external: true, - }; - }, - async buildEnd() { - if (opts.trace === false) { - return; - } - - // Manually traced paths - for (const pkgName of opts.traceInclude || []) { - const path = await this.resolve(pkgName); - if (path?.id) { - trackedExternals.add(path.id.replace(/\?.+/, "")); - } - } - - // Trace used files using nft - const _fileTrace = await nodeFileTrace([...trackedExternals], { - // https://github.com/nitrojs/nitro/pull/1562 - conditions: (opts.exportConditions || []).filter( - (c) => !["require", "import", "default"].includes(c) - ), - ...opts.traceOptions, - }); - - // Resolve traced files - type TracedFile = { - path: string; - subpath: string; - parents: string[]; - - pkgPath: string; - pkgName: string; - pkgVersion: string; - }; - const _resolveTracedPath = (p: string) => - fsp.realpath(resolve(opts.traceOptions?.base || ".", p)); - const tracedFiles: Record = Object.fromEntries( - (await Promise.all( - [..._fileTrace.reasons.entries()].map(async ([_path, reasons]) => { - if (reasons.ignored) { - return; - } - const path = await _resolveTracedPath(_path); - if (!path.includes("node_modules")) { - return; - } - if (!(await isFile(path))) { - return; - } - const { - dir: baseDir, - name: pkgName, - subpath, - } = parseNodeModulePath(path); - if (!baseDir || !pkgName) { - return; - } - const pkgPath = join(baseDir, pkgName); - const parents = await Promise.all( - [...reasons.parents].map((p) => _resolveTracedPath(p)) - ); - const tracedFile = { - path, - parents, - - subpath, - pkgName, - pkgPath, - }; - return [path, tracedFile]; - }) - ).then((r) => r.filter(Boolean))) as [string, TracedFile][] - ); - - // Resolve traced packages - type TracedPackage = { - name: string; - versions: Record< - string, - { - pkgJSON: PackageJson; - path: string; - files: string[]; - } - >; - }; - const tracedPackages: Record = {}; - for (const tracedFile of Object.values(tracedFiles)) { - // Use `node_modules/{name}` in path as name to support aliases - const pkgName = tracedFile.pkgName; - let tracedPackage = tracedPackages[pkgName]; - - // Read package.json for file - let pkgJSON = await readPackageJSON(tracedFile.pkgPath, { - cache: true, - }).catch( - () => {} // TODO: Only catch ENOENT - ); - if (!pkgJSON) { - pkgJSON = { name: pkgName, version: "0.0.0" }; - } - if (!tracedPackage) { - tracedPackage = { - name: pkgName, - versions: {}, - }; - tracedPackages[pkgName] = tracedPackage; - } - let tracedPackageVersion = - tracedPackage.versions[pkgJSON.version || "0.0.0"]; - if (!tracedPackageVersion) { - tracedPackageVersion = { - path: tracedFile.pkgPath, - files: [], - pkgJSON, - }; - tracedPackage.versions[pkgJSON.version || "0.0.0"] = - tracedPackageVersion; - } - tracedPackageVersion.files.push(tracedFile.path); - tracedFile.pkgName = pkgName; - if (pkgJSON.version) { - tracedFile.pkgVersion = pkgJSON.version; - } - } - - const usedAliases: Record = {}; - - const writePackage = async ( - name: string, - version: string, - _pkgPath?: string - ) => { - // Find pkg - const pkg = tracedPackages[name]; - const pkgPath = _pkgPath || pkg.name; - - // Copy files - for (const src of pkg.versions[version].files) { - const { subpath } = parseNodeModulePath(src); - if (!subpath) { - continue; - } - const dst = join(opts.outDir, "node_modules", pkgPath, subpath); - await fsp.mkdir(dirname(dst), { recursive: true }); - await fsp.copyFile(src, dst); - } - - // Copy package.json - const pkgJSON = pkg.versions[version].pkgJSON; - applyProductionCondition(pkgJSON.exports); - const pkgJSONPath = join( - opts.outDir, - "node_modules", - pkgPath, - "package.json" - ); - await fsp.mkdir(dirname(pkgJSONPath), { recursive: true }); - await fsp.writeFile( - pkgJSONPath, - JSON.stringify(pkgJSON, null, 2), - "utf8" - ); - - // Link aliases - if (opts.traceAlias && pkgPath in opts.traceAlias) { - usedAliases[opts.traceAlias[pkgPath]] = version; - await linkPackage(pkgPath, opts.traceAlias[pkgPath]); - } - }; - - const isWindows = platform() === "win32"; - const linkPackage = async (from: string, to: string) => { - const src = join(opts.outDir, "node_modules", from); - const dst = join(opts.outDir, "node_modules", to); - const dstStat = await fsp.lstat(dst).catch(() => null); - const exists = dstStat?.isSymbolicLink(); - // console.log("Linking", from, "to", to, exists ? "!!!!" : ""); - if (exists) { - return; - } - await fsp.mkdir(dirname(dst), { recursive: true }); - await fsp - .symlink( - relative(dirname(dst), src), - dst, - isWindows ? "junction" : "dir" - ) - .catch((error) => { - console.error("Cannot link", from, "to", to, error); - }); - }; - - // Utility to find package parents - const findPackageParents = (pkg: TracedPackage, version: string) => { - // Try to find parent packages - const versionFiles: TracedFile[] = pkg.versions[version].files.map( - (path) => tracedFiles[path] - ); - const parentPkgs = [ - ...new Set( - versionFiles.flatMap((file) => - file.parents - .map((parentPath) => { - const parentFile = tracedFiles[parentPath]; - if (parentFile.pkgName === pkg.name) { - return null; - } - return `${parentFile.pkgName}@${parentFile.pkgVersion}`; - }) - .filter(Boolean) - ) as string[] - ), - ]; - return parentPkgs; - }; - - // Analyze dependency tree - const multiVersionPkgs: Record = - {}; - const singleVersionPackages: string[] = []; - for (const tracedPackage of Object.values(tracedPackages)) { - const versions = Object.keys(tracedPackage.versions); - if (versions.length === 1) { - singleVersionPackages.push(tracedPackage.name); - continue; - } - multiVersionPkgs[tracedPackage.name] = {}; - for (const version of versions) { - multiVersionPkgs[tracedPackage.name][version] = findPackageParents( - tracedPackage, - version - ); - } - } - - // Directly write single version packages - await Promise.all( - singleVersionPackages.map((pkgName) => { - const pkg = tracedPackages[pkgName]; - const version = Object.keys(pkg.versions)[0]; - return writePackage(pkgName, version); - }) - ); - - // Write packages with multiple versions - for (const [pkgName, pkgVersions] of Object.entries(multiVersionPkgs)) { - const versionEntries = Object.entries(pkgVersions).sort( - ([v1, p1], [v2, p2]) => { - // 1. Package with no parent packages to be hoisted - if (p1.length === 0) { - return -1; - } - if (p2.length === 0) { - return 1; - } - // 2. Newest version to be hoisted - return compareVersions(v1, v2); - } - ); - for (const [version, parentPkgs] of versionEntries) { - // Write each version into node_modules/.nitro/{name}@{version} - await writePackage(pkgName, version, `.nitro/${pkgName}@${version}`); - // Link one version to the top level (for indirect bundle deps) - await linkPackage(`.nitro/${pkgName}@${version}`, `${pkgName}`); - // Link to parent packages - for (const parentPkg of parentPkgs) { - const parentPkgName = parentPkg.replace(/@[^@]+$/, ""); - await (multiVersionPkgs[parentPkgName] - ? linkPackage( - `.nitro/${pkgName}@${version}`, - `.nitro/${parentPkg}/node_modules/${pkgName}` - ) - : linkPackage( - `.nitro/${pkgName}@${version}`, - `${parentPkgName}/node_modules/${pkgName}` - )); - } - } - } - - // Write an informative package.json - const userPkg = await readPackageJSON( - opts.rootDir || process.cwd() - ).catch(() => ({}) as PackageJson); - - await writePackageJSON(resolve(opts.outDir, "package.json"), { - name: (userPkg.name || "server") + "-prod", - version: userPkg.version || "0.0.0", - type: "module", - private: true, - dependencies: Object.fromEntries( - [ - ...Object.values(tracedPackages).map((pkg) => [ - pkg.name, - Object.keys(pkg.versions)[0], - ]), - ...Object.entries(usedAliases), - ].sort(([a], [b]) => a.localeCompare(b)) - ), - }); - }, - }; -} - -function compareVersions(v1 = "0.0.0", v2 = "0.0.0") { - try { - return semver.lt(v1, v2, { loose: true }) ? 1 : -1; - } catch { - return v1.localeCompare(v2); - } -} - -export function applyProductionCondition(exports: PackageJson["exports"]) { - if ( - !exports || - typeof exports === "string" || - Array.isArray(exports) /* TODO: unhandled */ - ) { - return; - } - if ("production" in exports) { - if (typeof exports.production === "string") { - exports.default = exports.production; - } else { - Object.assign(exports, exports.production); - } - } - for (const key in exports) { - applyProductionCondition(exports[key as keyof typeof exports]); - } -} - -async function isFile(file: string) { - try { - const stat = await fsp.stat(file); - return stat.isFile(); - } catch (error) { - if ((error as any)?.code === "ENOENT") { - return false; - } - throw error; - } -} - -type Matcher = (( - id: string, - importer?: string -) => Promise | boolean) & { score?: number }; - -export function normalizeMatcher(input: string | RegExp | Matcher): Matcher { - if (typeof input === "function") { - input.score = input.score ?? 10_000; - return input; - } - - if (input instanceof RegExp) { - const matcher = ((id: string) => input.test(id)) as Matcher; - matcher.score = input.toString().length; - Object.defineProperty(matcher, "name", { value: `match(${input})` }); - return matcher; - } - - if (typeof input === "string") { - const pattern = normalize(input); - const matcher = ((id: string) => { - const idWithoutNodeModules = id.split("node_modules/").pop(); - return ( - id.startsWith(pattern) || idWithoutNodeModules?.startsWith(pattern) - ); - }) as Matcher; - matcher.score = input.length; - - // Increase score for npm package names to avoid breaking changes - // TODO: Remove in next major version - if (!isAbsolute(input) && input[0] !== ".") { - matcher.score += 1000; - } - - Object.defineProperty(matcher, "name", { value: `match(${pattern})` }); - return matcher; - } - - throw new Error(`Invalid matcher or pattern: ${input}`); -} diff --git a/src/rollup/plugins/handlers-meta.ts b/src/rollup/plugins/handlers-meta.ts deleted file mode 100644 index bc4003b78c..0000000000 --- a/src/rollup/plugins/handlers-meta.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { readFile } from "node:fs/promises"; -import { transform } from "esbuild"; -import type { Expression, Literal } from "estree"; -import type { Nitro, NitroEventHandler } from "nitropack/types"; -import { extname } from "pathe"; -import type { Plugin } from "rollup"; - -const virtualPrefix = "\0nitro-handler-meta:"; - -// From esbuild.ts -const esbuildLoaders = { - ".ts": "ts", - ".js": "js", - ".tsx": "tsx", - ".jsx": "jsx", -} as const; - -export function handlersMeta(nitro: Nitro) { - return { - name: "nitro:handlers-meta", - async resolveId(id, importer, resolveOpts) { - if (id.startsWith("\0")) { - return; - } - if (id.endsWith(`?meta`)) { - const resolved = await this.resolve( - id.replace(`?meta`, ``), - importer, - resolveOpts - ); - if (!resolved) { - return; - } - return virtualPrefix + resolved.id; - } - }, - load(id) { - if (id.startsWith(virtualPrefix)) { - const fullPath = id.slice(virtualPrefix.length); - return readFile(fullPath, { encoding: "utf8" }); - } - }, - async transform(code, id) { - if (!id.startsWith(virtualPrefix)) { - return; - } - - let meta: NitroEventHandler["meta"] | null = null; - - try { - const ext = extname(id) as keyof typeof esbuildLoaders; - const jsCode = await transform(code, { - loader: esbuildLoaders[ext], - }).then((r) => r.code); - const ast = this.parse(jsCode); - for (const node of ast.body) { - if ( - node.type === "ExpressionStatement" && - node.expression.type === "CallExpression" && - node.expression.callee.type === "Identifier" && - node.expression.callee.name === "defineRouteMeta" && - node.expression.arguments.length === 1 - ) { - meta = astToObject(node.expression.arguments[0] as any); - break; - } - } - } catch (error) { - nitro.logger.warn( - `[handlers-meta] Cannot extra route meta for: ${id}: ${error}` - ); - } - - return { - code: `export default ${JSON.stringify(meta)};`, - map: null, - }; - }, - } satisfies Plugin; -} - -function astToObject(node: Expression | Literal): any { - switch (node.type) { - case "ObjectExpression": { - const obj: Record = {}; - for (const prop of node.properties) { - if (prop.type === "Property") { - const key = (prop.key as any).name ?? (prop.key as any).value; - obj[key] = astToObject(prop.value as any); - } - } - return obj; - } - case "ArrayExpression": { - return node.elements.map((el) => astToObject(el as any)).filter(Boolean); - } - case "Literal": { - return node.value; - } - // No default - } -} diff --git a/src/rollup/plugins/handlers.ts b/src/rollup/plugins/handlers.ts deleted file mode 100644 index 9d40bac592..0000000000 --- a/src/rollup/plugins/handlers.ts +++ /dev/null @@ -1,173 +0,0 @@ -import { runtimeDir } from "nitropack/runtime/meta"; -import type { - Nitro, - NitroEventHandler, - NitroRouteRules, -} from "nitropack/types"; -import { hash } from "ohash"; -import { join } from "pathe"; -import { virtual } from "./virtual"; - -export function handlers(nitro: Nitro) { - const getHandlers = () => { - const handlers: NitroEventHandler[] = [ - ...nitro.scannedHandlers, - ...nitro.options.handlers, - ]; - - const envConditions = new Set( - [ - nitro.options.dev ? "dev" : "prod", - nitro.options.preset, - nitro.options.preset === "nitro-prerender" ? "prerender" : undefined, - ].filter(Boolean) as string[] - ); - - return handlers.filter((h) => { - const envs = (Array.isArray(h.env) ? h.env : [h.env]).filter( - Boolean - ) as string[]; - return envs.length === 0 || envs.some((env) => envConditions.has(env)); - }); - }; - - return virtual( - { - "#nitro-internal-virtual/server-handlers": () => { - const handlers = getHandlers(); - if (nitro.options.serveStatic) { - handlers.unshift({ - middleware: true, - handler: join(runtimeDir, "internal/static"), - }); - } - if (nitro.options.renderer) { - handlers.push({ - route: "/**", - lazy: true, - handler: nitro.options.renderer, - }); - } - - // If this handler would render a cached route rule then we can also inject a cached event handler - extendMiddlewareWithRuleOverlaps(handlers, nitro.options.routeRules); - - // Imports take priority - const imports = unique( - handlers.filter((h) => !h.lazy).map((h) => h.handler) - ); - - // Lazy imports should fill in the gaps - // TODO: At least warn if a handler is imported both lazy and non lazy - const lazyImports = unique( - handlers.filter((h) => h.lazy).map((h) => h.handler) - ); - - const code = /* js */ ` -${imports - .map((handler) => `import ${getImportId(handler)} from '${handler}';`) - .join("\n")} - -${lazyImports - .map( - (handler) => - `const ${getImportId(handler, true)} = () => import('${handler}');` - ) - .join("\n")} - -export const handlers = [ -${handlers - .map( - (h) => - ` { route: '${h.route || ""}', handler: ${getImportId( - h.handler, - h.lazy - )}, lazy: ${!!h.lazy}, middleware: ${!!h.middleware}, method: ${JSON.stringify( - h.method?.toLowerCase() - )} }` - ) - .join(",\n")} -]; - `.trim(); - return code; - }, - "#nitro-internal-virtual/server-handlers-meta": () => { - const handlers = getHandlers(); - const imports = unique(handlers.map((h) => h.handler)); - return /* js */ ` - ${imports - .map( - (handler) => `import ${getImportId(handler)}Meta from "${handler}?meta";` - ) - .join("\n")} -export const handlersMeta = [ - ${handlers - .map( - (h) => - /* js */ `{ route: ${JSON.stringify(h.route)}, method: ${JSON.stringify( - h.method?.toLowerCase() - )}, meta: ${getImportId(h.handler)}Meta }` - ) - .join(",\n")} - ]; - `; - }, - }, - nitro.vfs - ); -} - -function unique(arr: any[]) { - return [...new Set(arr)]; -} - -function getImportId(p: string, lazy?: boolean) { - return (lazy ? "_lazy_" : "_") + hash(p).replace(/-/g, "").slice(0, 6); -} - -const WILDCARD_PATH_RE = /\/\*\*.*$/; - -function extendMiddlewareWithRuleOverlaps( - handlers: NitroEventHandler[], - routeRules: Record -) { - const rules = Object.entries(routeRules); - for (const [path, rule] of rules) { - // We can ignore this rule if it is not cached and it isn't nested in a cached route - if (!rule.cache) { - // If we are nested 'within' a cached route, we want to inject a non-cached event handler - const isNested = rules.some( - ([p, r]) => - r.cache && - WILDCARD_PATH_RE.test(p) && - path.startsWith(p.replace(WILDCARD_PATH_RE, "")) - ); - if (!isNested) { - continue; - } - } - for (const [index, handler] of handlers.entries()) { - // Skip middleware - if (!handler.route || handler.middleware) { - continue; - } - // We will correctly register this rule as a cached route anyway - if (handler.route === path) { - break; - } - // We are looking for handlers that will render a route _despite_ not - // having an identical path to it - if (!WILDCARD_PATH_RE.test(handler.route)) { - continue; - } - if (!path.startsWith(handler.route.replace(WILDCARD_PATH_RE, ""))) { - continue; - } - handlers.splice(index, 0, { - ...handler, - route: path, - }); - break; - } - } -} diff --git a/src/rollup/plugins/import-meta.ts b/src/rollup/plugins/import-meta.ts deleted file mode 100644 index cb50db9018..0000000000 --- a/src/rollup/plugins/import-meta.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { Nitro } from "nitropack/types"; -import type { Plugin } from "rollup"; - -export const ImportMetaRe = /import\.meta|globalThis._importMeta_/; - -export function importMeta(nitro: Nitro): Plugin { - return { - name: "import-meta", - renderChunk(code, chunk) { - const isEntry = chunk.isEntry; - if ( - !isEntry && - (!ImportMetaRe.test(code) || code.includes("ROLLUP_NO_REPLACE")) - ) { - return; - } - const url = - nitro.options.node && isEntry && !code.includes("ROLLUP_NO_REPLACE") - ? "_import_meta_url_" - : '"file:///_entry.js"'; - const envImport = nitro.options.node - ? "import process from 'node:process';" - : ""; - const env = nitro.options.node ? "process.env" : "{}"; - const ref = "globalThis._importMeta_"; - const stub = `{url:${url},env:${env}}`; - const stubInit = isEntry ? `${ref}=${stub};` : `${ref}=${ref}||${stub};`; - - return { - code: envImport + stubInit + code, - map: null, - }; - }, - }; -} diff --git a/src/rollup/plugins/public-assets.ts b/src/rollup/plugins/public-assets.ts deleted file mode 100644 index 14c0d3a8a3..0000000000 --- a/src/rollup/plugins/public-assets.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { promises as fsp } from "node:fs"; -import createEtag from "etag"; -import { globby } from "globby"; -import mime from "mime"; -import type { Nitro } from "nitropack/types"; -import type { PublicAsset } from "nitropack/types"; -import { relative, resolve } from "pathe"; -import type { Plugin } from "rollup"; -import { withTrailingSlash } from "ufo"; -import { virtual } from "./virtual"; - -const readAssetHandler: Record< - Exclude, - "node" | "deno" | "null" | "inline" -> = { - true: "node", - node: "node", - false: "null", - deno: "deno", - inline: "inline", -}; - -export function publicAssets(nitro: Nitro): Plugin { - return virtual( - { - // #nitro-internal-virtual/public-assets-data - "#nitro-internal-virtual/public-assets-data": async () => { - const assets: Record = {}; - const files = await globby("**", { - cwd: nitro.options.output.publicDir, - absolute: false, - dot: true, - }); - for (const id of files) { - let mimeType = - mime.getType(id.replace(/\.(gz|br)$/, "")) || "text/plain"; - if (mimeType.startsWith("text")) { - mimeType += "; charset=utf-8"; - } - const fullPath = resolve(nitro.options.output.publicDir, id); - const assetData = await fsp.readFile(fullPath); - const etag = createEtag(assetData); - const stat = await fsp.stat(fullPath); - - const assetId = "/" + decodeURIComponent(id); - - let encoding; - if (id.endsWith(".gz")) { - encoding = "gzip"; - } else if (id.endsWith(".br")) { - encoding = "br"; - } - - assets[assetId] = { - type: nitro._prerenderMeta?.[assetId]?.contentType || mimeType, - encoding, - etag, - mtime: stat.mtime.toJSON(), - size: stat.size, - path: relative(nitro.options.output.serverDir, fullPath), - data: - nitro.options.serveStatic === "inline" - ? assetData.toString("base64") - : undefined, - }; - } - - return `export default ${JSON.stringify(assets, null, 2)};`; - }, - // #nitro-internal-virtual/public-assets-node - "#nitro-internal-virtual/public-assets-node": () => { - return ` -import { promises as fsp } from 'node:fs' -import { fileURLToPath } from 'node:url' -import { resolve, dirname } from 'pathe' -import assets from '#nitro-internal-virtual/public-assets-data' -export function readAsset (id) { - const serverDir = dirname(fileURLToPath(import.meta.url)) - return fsp.readFile(resolve(serverDir, assets[id].path)) -}`; - }, - // #nitro-internal-virtual/public-assets-deno - "#nitro-internal-virtual/public-assets-deno": () => { - return ` -import assets from '#nitro-internal-virtual/public-assets-data' -export function readAsset (id) { - // https://deno.com/deploy/docs/serve-static-assets - const path = '.' + decodeURIComponent(new URL(\`../public\${id}\`, 'file://').pathname) - return Deno.readFile(path); -}`; - }, - // #nitro-internal-virtual/public-assets-null - "#nitro-internal-virtual/public-assets-null": () => { - return ` - export function readAsset (id) { - return Promise.resolve(null); - }`; - }, - // #nitro-internal-virtual/public-assets-inline - "#nitro-internal-virtual/public-assets-inline": () => { - return ` - import assets from '#nitro-internal-virtual/public-assets-data' - export function readAsset (id) { - if (!assets[id]) { return undefined } - if (assets[id]._data) { return assets[id]._data } - if (!assets[id].data) { return assets[id].data } - assets[id]._data = Uint8Array.from(atob(assets[id].data), (c) => c.charCodeAt(0)) - return assets[id]._data -}`; - }, - // #nitro-internal-virtual/public-assets - "#nitro-internal-virtual/public-assets": () => { - const publicAssetBases = Object.fromEntries( - nitro.options.publicAssets - .filter((dir) => !dir.fallthrough && dir.baseURL !== "/") - .map((dir) => [ - withTrailingSlash(dir.baseURL), - { maxAge: dir.maxAge }, - ]) - ); - - // prettier-ignore - type _serveStaticAsKey = Exclude | "true" | "false"; - // prettier-ignore - const handlerName = readAssetHandler[nitro.options.serveStatic as _serveStaticAsKey] || "null"; - const readAssetImport = `#nitro-internal-virtual/public-assets-${handlerName}`; - - return ` -import assets from '#nitro-internal-virtual/public-assets-data' -export { readAsset } from "${readAssetImport}" -export const publicAssetBases = ${JSON.stringify(publicAssetBases)} - -export function isPublicAssetURL(id = '') { - if (assets[id]) { - return true - } - for (const base in publicAssetBases) { - if (id.startsWith(base)) { return true } - } - return false -} - -export function getPublicAssetMeta(id = '') { - for (const base in publicAssetBases) { - if (id.startsWith(base)) { return publicAssetBases[base] } - } - return {} -} - -export function getAsset (id) { - return assets[id] -} -`; - }, - }, - nitro.vfs - ); -} diff --git a/src/rollup/plugins/raw.ts b/src/rollup/plugins/raw.ts deleted file mode 100644 index 7439279a3e..0000000000 --- a/src/rollup/plugins/raw.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { promises as fsp } from "node:fs"; -import mime from "mime"; -import type { RawOptions } from "nitropack/types"; -import { extname } from "pathe"; -import type { Plugin } from "rollup"; - -const HELPER_ID = "\0raw-helpers"; - -export function raw(opts: RawOptions = {}): Plugin { - const extensions = new Set([ - ".md", - ".mdx", - ".txt", - ".css", - ".htm", - ".html", - ".sql", - ...(opts.extensions || []), - ]); - - return { - name: "raw", - async resolveId(id, importer, resolveOpts) { - if (id === HELPER_ID) { - return id; - } - - if (id[0] === "\0") { - return; - } - - const withRawSpecifier = id.startsWith("raw:"); - if (withRawSpecifier) { - id = id.slice(4); - } - - if (!withRawSpecifier && !extensions.has(extname(id))) { - return; - } - - const resolvedId = (await this.resolve(id, importer, resolveOpts))?.id; - - if (!resolvedId || resolvedId.startsWith("\0")) { - return resolvedId; - } - - if (!withRawSpecifier && !extensions.has(extname(resolvedId))) { - return; - } - - return { id: "\0raw:" + resolvedId }; - }, - load(id) { - if (id === HELPER_ID) { - return getHelpers(); - } - if (id.startsWith("\0raw:")) { - // this.addWatchFile(id.substring(5)) - return fsp.readFile(id.slice(5), isBinary(id) ? "binary" : "utf8"); - } - }, - transform(code, id) { - if (!id.startsWith("\0raw:")) { - return; - } - if (isBinary(id)) { - const serialized = Buffer.from(code, "binary").toString("base64"); - return { - code: `// ROLLUP_NO_REPLACE \n import {base64ToUint8Array } from "${HELPER_ID}" \n export default base64ToUint8Array("${serialized}")`, - map: null, - }; - } - return { - code: `// ROLLUP_NO_REPLACE \n export default ${JSON.stringify(code)}`, - map: null, - }; - }, - }; -} - -function isBinary(id: string) { - const idMime = mime.getType(id) || ""; - if (idMime.startsWith("text/")) { - return false; - } - if (/application\/(json|sql|xml|yaml)/.test(idMime)) { - return false; - } - return true; -} - -function getHelpers() { - const js = String.raw; - return js` -export function base64ToUint8Array(str) { - const data = atob(str); - const size = data.length; - const bytes = new Uint8Array(size); - for (let i = 0; i < size; i++) { - bytes[i] = data.charCodeAt(i); - } - return bytes; -} - `; -} diff --git a/src/rollup/plugins/replace.ts b/src/rollup/plugins/replace.ts deleted file mode 100644 index c37f904f42..0000000000 --- a/src/rollup/plugins/replace.ts +++ /dev/null @@ -1,20 +0,0 @@ -import _replace from "@rollup/plugin-replace"; -import type { RollupReplaceOptions } from "@rollup/plugin-replace"; -import type { Plugin } from "rollup"; - -const NO_REPLACE_RE = /ROLLUP_NO_REPLACE/; - -export function replace(options: RollupReplaceOptions): Plugin { - const _plugin = _replace(options); - return { - ..._plugin, - // https://github.com/rollup/plugins/blob/master/packages/replace/src/index.js#L94 - renderChunk(code, chunk, options) { - if (!NO_REPLACE_RE.test(code)) { - // prettier-ignore - // @ts-ignore - return (_plugin.renderChunk as () => any).call(this, code, chunk, options ); - } - }, - }; -} diff --git a/src/rollup/plugins/server-assets.ts b/src/rollup/plugins/server-assets.ts deleted file mode 100644 index 22cace2412..0000000000 --- a/src/rollup/plugins/server-assets.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { promises as fsp } from "node:fs"; -import createEtag from "etag"; -import { globby } from "globby"; -import mime from "mime"; -import type { Nitro } from "nitropack/types"; -import { resolve } from "pathe"; -import type { Plugin } from "rollup"; -import { normalizeKey } from "unstorage"; -import { virtual } from "./virtual"; - -interface ResolvedAsset { - fsPath: string; - meta: { - type?: string; - etag?: string; - mtime?: string; - }; -} - -export function serverAssets(nitro: Nitro): Plugin { - // Development: Use filesystem - if (nitro.options.dev || nitro.options.preset === "nitro-prerender") { - return virtual( - { "#nitro-internal-virtual/server-assets": getAssetsDev(nitro) }, - nitro.vfs - ); - } - - // Production: Bundle assets - return virtual( - { - "#nitro-internal-virtual/server-assets": async () => { - // Scan all assets - const assets: Record = {}; - for (const asset of nitro.options.serverAssets) { - const files = await globby(asset.pattern || "**/*", { - cwd: asset.dir, - absolute: false, - ignore: asset.ignore, - }); - for (const _id of files) { - const fsPath = resolve(asset.dir, _id); - const id = asset.baseName + "/" + _id; - assets[id] = { fsPath, meta: {} }; - // @ts-ignore TODO: Use mime@2 types - let type = mime.getType(id) || "text/plain"; - if (type.startsWith("text")) { - type += "; charset=utf-8"; - } - const etag = createEtag(await fsp.readFile(fsPath)); - const mtime = await fsp.stat(fsPath).then((s) => s.mtime.toJSON()); - assets[id].meta = { type, etag, mtime }; - } - } - return getAssetProd(assets); - }, - }, - nitro.vfs - ); -} - -function getAssetsDev(nitro: Nitro) { - return ` -import { createStorage } from 'unstorage' -import fsDriver from 'unstorage/drivers/fs' - -const serverAssets = ${JSON.stringify(nitro.options.serverAssets)} - -export const assets = createStorage() - -for (const asset of serverAssets) { - assets.mount(asset.baseName, fsDriver({ base: asset.dir, ignore: (asset?.ignore || []) })) -}`; -} - -function getAssetProd(assets: Record) { - return ` -const _assets = {\n${Object.entries(assets) - .map( - ([id, asset]) => - ` [${JSON.stringify( - normalizeKey(id) - )}]: {\n import: () => import(${JSON.stringify( - "raw:" + asset.fsPath - )}).then(r => r.default || r),\n meta: ${JSON.stringify( - asset.meta - )}\n }` - ) - .join(",\n")}\n} - -const normalizeKey = ${normalizeKey.toString()} - -export const assets = { - getKeys() { - return Promise.resolve(Object.keys(_assets)) - }, - hasItem (id) { - id = normalizeKey(id) - return Promise.resolve(id in _assets) - }, - getItem (id) { - id = normalizeKey(id) - return Promise.resolve(_assets[id] ? _assets[id].import() : null) - }, - getMeta (id) { - id = normalizeKey(id) - return Promise.resolve(_assets[id] ? _assets[id].meta : {}) - } -} -`; -} diff --git a/src/rollup/plugins/storage.ts b/src/rollup/plugins/storage.ts deleted file mode 100644 index 23bf568543..0000000000 --- a/src/rollup/plugins/storage.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { genImport, genSafeVariableName } from "knitwork"; -import type { Nitro } from "nitropack/types"; -import { builtinDrivers } from "unstorage"; -import { virtual } from "./virtual"; - -export function storage(nitro: Nitro) { - const mounts: { path: string; driver: string; opts: object }[] = []; - - const isDevOrPrerender = - nitro.options.dev || nitro.options.preset === "nitro-prerender"; - const storageMounts = isDevOrPrerender - ? { ...nitro.options.storage, ...nitro.options.devStorage } - : nitro.options.storage; - - for (const path in storageMounts) { - const mount = storageMounts[path]; - mounts.push({ - path, - driver: - builtinDrivers[mount.driver as keyof typeof builtinDrivers] || - mount.driver, - opts: mount, - }); - } - - const driverImports = [...new Set(mounts.map((m) => m.driver))]; - - const bundledStorageCode = ` -import { prefixStorage } from 'unstorage' -import overlay from 'unstorage/drivers/overlay' -import memory from 'unstorage/drivers/memory' - -const bundledStorage = ${JSON.stringify(nitro.options.bundledStorage)} -for (const base of bundledStorage) { - storage.mount(base, overlay({ - layers: [ - memory(), - // TODO - // prefixStorage(storage, base), - prefixStorage(storage, 'assets:nitro:bundled:' + base) - ] - })) -}`; - - return virtual( - { - "#nitro-internal-virtual/storage": ` -import { createStorage } from 'unstorage' -import { assets } from '#nitro-internal-virtual/server-assets' - -${driverImports.map((i) => genImport(i, genSafeVariableName(i))).join("\n")} - -export const storage = createStorage({}) - -storage.mount('/assets', assets) - -${mounts - .map( - (m) => - `storage.mount('${m.path}', ${genSafeVariableName( - m.driver - )}(${JSON.stringify(m.opts)}))` - ) - .join("\n")} - -${ - !isDevOrPrerender && nitro.options.bundledStorage.length > 0 - ? bundledStorageCode - : "" -} -`, - }, - nitro.vfs - ); -} diff --git a/src/rollup/plugins/timing.ts b/src/rollup/plugins/timing.ts deleted file mode 100644 index aabccff425..0000000000 --- a/src/rollup/plugins/timing.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { extname } from "pathe"; -import type { Plugin, RenderedChunk } from "rollup"; - -interface TimingOptions { - silent?: boolean; -} - -const TIMING = "globalThis.__timing__"; - -const iife = (code: string) => - `(function() { ${code.trim()} })();`.replace(/\n/g, ""); - -const HELPERIMPORT = "import './timing.js';"; - -export function timing(opts: TimingOptions = {}): Plugin { - const HELPER_DEBUG = opts.silent - ? "" - : `if (t > 0) { console.debug('>', id + ' (' + t + 'ms)'); }`; - - const HELPER = iife(/* js */ ` - const start = () => Date.now(); - const end = s => Date.now() - s; - const _s = {}; - const metrics = []; - const logStart = id => { _s[id] = Date.now(); }; - const logEnd = id => { const t = end(_s[id]); delete _s[id]; metrics.push([id, t]); ${HELPER_DEBUG} }; - ${TIMING} = { start, end, metrics, logStart, logEnd }; - `); - - return { - name: "timing", - generateBundle() { - this.emitFile({ - type: "asset", - fileName: "timing.js", - source: HELPER, - }); - }, - renderChunk(code, chunk: RenderedChunk) { - let name = chunk.fileName || ""; - name = name.replace(extname(name), ""); - const logName = name === "index" ? "Nitro Start" : "Load " + name; - return { - code: - (chunk.isEntry ? HELPERIMPORT : "") + - `${TIMING}.logStart('${logName}');` + - code + - `;${TIMING}.logEnd('${logName}');`, - map: null, - }; - }, - }; -} diff --git a/src/rollup/plugins/virtual.ts b/src/rollup/plugins/virtual.ts deleted file mode 100644 index 8d5b3b5426..0000000000 --- a/src/rollup/plugins/virtual.ts +++ /dev/null @@ -1,69 +0,0 @@ -import type { RollupVirtualOptions, VirtualModule } from "nitropack/types"; -import { dirname, resolve } from "pathe"; -import type { Plugin } from "rollup"; - -// Based on https://github.com/rollup/plugins/blob/master/packages/virtual/src/index.ts - -const PREFIX = "\0virtual:"; - -export function virtual( - modules: RollupVirtualOptions, - cache: Record = {} -): Plugin { - const _modules = new Map(); - - for (const [id, mod] of Object.entries(modules)) { - cache[id] = mod; - _modules.set(id, mod); - _modules.set(resolve(id), mod); - } - - return { - name: "virtual", - - resolveId(id, importer) { - if (id in modules) { - return PREFIX + id; - } - - if (importer) { - const importerNoPrefix = importer.startsWith(PREFIX) - ? importer.slice(PREFIX.length) - : importer; - const resolved = resolve(dirname(importerNoPrefix), id); - if (_modules.has(resolved)) { - return PREFIX + resolved; - } - } - - return null; - }, - - async load(id) { - if (!id.startsWith(PREFIX)) { - return null; - } - - const idNoPrefix = id.slice(PREFIX.length); - if (!_modules.has(idNoPrefix)) { - return null; - } - - let m = _modules.get(idNoPrefix); - if (typeof m === "function") { - m = await m(); - } - - if (!m) { - return null; - } - - cache[id.replace(PREFIX, "")] = m; - - return { - code: m as string, - map: null, - }; - }, - }; -} diff --git a/src/rollup/utils.ts b/src/rollup/utils.ts deleted file mode 100644 index db62ceb858..0000000000 --- a/src/rollup/utils.ts +++ /dev/null @@ -1,25 +0,0 @@ -export function resolveAliases(_aliases: Record) { - // Sort aliases from specific to general (ie. fs/promises before fs) - const aliases = Object.fromEntries( - Object.entries(_aliases).sort( - ([a], [b]) => - b.split("/").length - a.split("/").length || b.length - a.length - ) - ); - // Resolve alias values in relation to each other - for (const key in aliases) { - for (const alias in aliases) { - if (!["~", "@", "#"].includes(alias[0])) { - continue; - } - if (alias === "@" && !aliases[key].startsWith("@/")) { - continue; - } // Don't resolve @foo/bar - - if (aliases[key].startsWith(alias)) { - aliases[key] = aliases[alias] + aliases[key].slice(alias.length); - } - } - } - return aliases; -} diff --git a/src/routing.ts b/src/routing.ts new file mode 100644 index 0000000000..2cc9421eeb --- /dev/null +++ b/src/routing.ts @@ -0,0 +1,215 @@ +import type { Nitro, NitroEventHandler, NitroRouteRules } from "nitro/types"; +import type { RouterContext } from "rou3"; +import type { RouterCompilerOptions } from "rou3/compiler"; + +import { join } from "pathe"; +import { runtimeDir } from "nitro/meta"; +import { addRoute, createRouter, findRoute, findAllRoutes } from "rou3"; +import { compileRouterToString } from "rou3/compiler"; +import { hash } from "ohash"; + +const isGlobalMiddleware = (h: NitroEventHandler) => !h.method && (!h.route || h.route === "/**"); + +export function initNitroRouting(nitro: Nitro) { + const envConditions = new Set( + [ + nitro.options.dev ? "dev" : "prod", + nitro.options.preset, + nitro.options.preset === "nitro-prerender" ? "prerender" : undefined, + ].filter(Boolean) as string[] + ); + const matchesEnv = (h: NitroEventHandler) => { + const hEnv = Array.isArray(h.env) ? h.env : [h.env]; + const envs = hEnv.filter(Boolean) as string[]; + return envs.length === 0 || envs.some((env) => envConditions.has(env)); + }; + + type MaybeArray = T | T[]; + const routes = new Router>( + nitro.options.baseURL + ); + + const routeRules = new Router(nitro.options.baseURL); + + const globalMiddleware: (NitroEventHandler & { _importHash: string })[] = []; + + const routedMiddleware = new Router( + nitro.options.baseURL + ); + + const sync = () => { + // Update route rules + routeRules._update( + Object.entries(nitro.options.routeRules).map(([route, data]) => ({ + route, + method: "", + data: { + ...data, + _route: route, + }, + })) + ); + + // Update routes + const _routes = [ + ...Object.entries(nitro.options.routes).flatMap(([route, handler]) => { + if (typeof handler === "string") { + handler = { handler }; + } + return { ...handler, route, middleware: false }; + }), + ...nitro.options.handlers, + ...nitro.scannedHandlers, + ].filter((h) => h && !h.middleware && matchesEnv(h)); + if (nitro.options.serverEntry && nitro.options.serverEntry.handler) { + _routes.push({ + route: "/**", + lazy: false, + format: nitro.options.serverEntry.format, + handler: nitro.options.serverEntry.handler, + }); + } + if (nitro.options.renderer?.handler) { + _routes.push({ + route: "/**", + lazy: true, + handler: nitro.options.renderer?.handler, + }); + } + routes._update( + _routes.map((h) => ({ + ...h, + method: h.method || "", + data: handlerWithImportHash(h), + })), + { merge: true } + ); + + // Update middleware + const _middleware = [...nitro.scannedHandlers, ...nitro.options.handlers].filter( + (h) => h && h.middleware && matchesEnv(h) + ); + if (nitro.options.serveStatic) { + _middleware.unshift({ + route: "/**", + middleware: true, + handler: join(runtimeDir, "internal/static"), + }); + } + globalMiddleware.splice( + 0, + globalMiddleware.length, + ..._middleware.filter((h) => isGlobalMiddleware(h)).map((m) => handlerWithImportHash(m)) + ); + routedMiddleware._update( + _middleware + .filter((h) => !isGlobalMiddleware(h)) + .map((h) => ({ + ...h, + method: h.method || "", + data: handlerWithImportHash(h), + })) + ); + }; + + nitro.routing = Object.freeze({ + sync, + routes, + routeRules, + globalMiddleware, + routedMiddleware, + }); +} + +function handlerWithImportHash(h: NitroEventHandler) { + const id = (h.lazy ? "_lazy_" : "_") + hash(h.handler).replace(/-/g, "").slice(0, 6); + return { ...h, _importHash: id }; +} + +// --- Router --- + +export interface Route { + route: string; + method: string; + data: T; +} + +export class Router { + _routes?: Route[]; + _router?: RouterContext; + _compiled?: Record; + _baseURL: string; + + constructor(baseURL?: string) { + this._update([]); + this._baseURL = baseURL || ""; + if (this._baseURL.endsWith("/")) { + this._baseURL = this._baseURL.slice(0, -1); + } + } + + get routes() { + return this._routes!; + } + + _update(routes: Route[], opts?: { merge?: boolean }) { + this._routes = routes; + this._router = createRouter(); + this._compiled = undefined; + for (const route of routes) { + addRoute(this._router, route.method, this._baseURL + route.route, route.data); + } + if (opts?.merge) { + mergeCatchAll(this._router); + } + } + + hasRoutes() { + return this._routes!.length > 0; + } + + compileToString(opts?: RouterCompilerOptions) { + const key = opts ? hash(opts) : ""; + this._compiled ||= {}; + if (this._compiled[key]) { + return this._compiled[key]; + } + this._compiled[key] = compileRouterToString(this._router!, undefined, opts); + + // TODO: Upstream to rou3 compiler + const onlyWildcard = + this.routes.length === 1 && this.routes[0].route === "/**" && this.routes[0].method === ""; + if (onlyWildcard) { + // Optimize for single wildcard route + const data = (opts?.serialize || JSON.stringify)(this.routes[0].data); + let retCode = `{data,params:{"_":p.slice(1)}}`; + if (opts?.matchAll) { + retCode = `[${retCode}]`; + } + this._compiled[key] = + /* js */ `/* @__PURE__ */ (() => {const data=${data};return ((_m, p)=>{return ${retCode};})})()`; + } + + return this._compiled[key]; + } + + match(method: string, path: string): undefined | T { + return findRoute(this._router!, method, path)?.data; + } + + matchAll(method: string, path: string): T[] { + // Returns from less specific to more specific matches + return findAllRoutes(this._router!, method, path).map((route) => route.data); + } +} + +function mergeCatchAll(router: RouterContext) { + const handlers = router.root?.wildcard?.methods?.[""]; + if (!handlers || handlers.length < 2) { + return; + } + handlers.splice(0, handlers.length, { + ...handlers[0], + data: handlers.map((h) => h.data), + }); +} diff --git a/src/runtime/app.ts b/src/runtime/app.ts index cc26a2bb7f..37093ab6ee 100644 --- a/src/runtime/app.ts +++ b/src/runtime/app.ts @@ -1,4 +1 @@ -// Backward compatibility for imports from "#internal/nitro/*" or "nitropack/runtime/*" - -export { useNitroApp } from "./internal/app"; -export type { NitroApp } from "nitropack/types"; +export { useNitroApp, useNitroHooks, serverFetch, getRouteRules, fetch } from "./internal/app.ts"; diff --git a/src/runtime/cache.ts b/src/runtime/cache.ts index ff0b9f1a25..2daf9ba6fe 100644 --- a/src/runtime/cache.ts +++ b/src/runtime/cache.ts @@ -1,8 +1 @@ -// Backward compatibility for imports from "#internal/nitro/*" or "nitropack/runtime/*" - -export { - cachedEventHandler, - cachedFunction, - defineCachedEventHandler, - defineCachedFunction, -} from "./internal/cache"; +export { defineCachedFunction, defineCachedHandler } from "./internal/cache.ts"; diff --git a/src/runtime/config.ts b/src/runtime/config.ts index 5c8d6f5b13..780bd990d5 100644 --- a/src/runtime/config.ts +++ b/src/runtime/config.ts @@ -1,3 +1,7 @@ -// Backward compatibility for imports from "#internal/nitro/*" or "nitropack/runtime/*" +import type { NitroConfig } from "nitro/types"; -export { useAppConfig, useRuntimeConfig } from "./internal/config"; +export function defineConfig(config: Omit): Omit { + return config; +} + +export { defineConfig as defineNitroConfig }; diff --git a/src/runtime/context.ts b/src/runtime/context.ts index 9d5f35ef03..790e01f2c2 100644 --- a/src/runtime/context.ts +++ b/src/runtime/context.ts @@ -1,3 +1 @@ -// Backward compatibility for imports from "#internal/nitro/*" or "nitropack/runtime/*" - -export { useEvent } from "./internal/context"; +export { useRequest } from "./internal/context.ts"; diff --git a/src/runtime/database.ts b/src/runtime/database.ts index 7a38c43cf4..2973469ee7 100644 --- a/src/runtime/database.ts +++ b/src/runtime/database.ts @@ -1,3 +1 @@ -// Backward compatibility for imports from "#internal/nitro/*" or "nitropack/runtime/*" - -export { useDatabase } from "./internal/database"; +export { useDatabase } from "./internal/database.ts"; diff --git a/src/runtime/error.ts b/src/runtime/error.ts deleted file mode 100644 index cda85b1e02..0000000000 --- a/src/runtime/error.ts +++ /dev/null @@ -1,120 +0,0 @@ -// Backward compatibility for imports from "#internal/nitro/*" or "nitropack/runtime/*" - -import { - send, - setResponseHeader, - setResponseHeaders, - setResponseStatus, -} from "h3"; -import { defineNitroErrorHandler } from "./internal/error/utils"; -import { isJsonRequest, normalizeError } from "./utils"; - -export { defineNitroErrorHandler } from "./internal/error/utils"; - -const isDev = process.env.NODE_ENV === "development"; - -interface ParsedError { - url: string; - statusCode: number; - statusMessage: number; - message: string; - stack?: string[]; -} - -/** - * @deprecated This export is only provided for backward compatibility and will be removed in v3. - */ -export default defineNitroErrorHandler( - function defaultNitroErrorHandler(error, event) { - const { stack, statusCode, statusMessage, message } = normalizeError( - error, - isDev - ); - - const showDetails = isDev && statusCode !== 404; - - const errorObject = { - url: event.path || "", - statusCode, - statusMessage, - message, - stack: showDetails ? stack.map((i) => i.text) : undefined, - }; - - // Console output - if (error.unhandled || error.fatal) { - const tags = [ - "[request error]", - error.unhandled && "[unhandled]", - error.fatal && "[fatal]", - ] - .filter(Boolean) - .join(" "); - console.error( - tags, - error.message + "\n" + stack.map((l) => " " + l.text).join(" \n") - ); - } - - if (statusCode === 404) { - setResponseHeader(event, "Cache-Control", "no-cache"); - } - - // Security headers - setResponseHeaders(event, { - // Disable the execution of any js - "Content-Security-Policy": "script-src 'none'; frame-ancestors 'none';", - // Prevent browser from guessing the MIME types of resources. - "X-Content-Type-Options": "nosniff", - // Prevent error page from being embedded in an iframe - "X-Frame-Options": "DENY", - // Prevent browsers from sending the Referer header - "Referrer-Policy": "no-referrer", - }); - - setResponseStatus(event, statusCode, statusMessage); - - if (isJsonRequest(event)) { - setResponseHeader(event, "Content-Type", "application/json"); - return send(event, JSON.stringify(errorObject)); - } - setResponseHeader(event, "Content-Type", "text/html"); - return send(event, renderHTMLError(errorObject)); - } -); - -function renderHTMLError(error: ParsedError): string { - const statusCode = error.statusCode || 500; - const statusMessage = error.statusMessage || "Request Error"; - return ` - - - - - ${statusCode} ${statusMessage} - - - -

- -
-
-

${statusCode} ${statusMessage}

-
- - ${error.message}

- ${ - "\n" + - (error.stack || []).map((i) => `  ${i}`).join("
") - } -
- -
-
-
- - -`; -} diff --git a/src/runtime/index.ts b/src/runtime/index.ts deleted file mode 100644 index f1c9cc6b7a..0000000000 --- a/src/runtime/index.ts +++ /dev/null @@ -1,38 +0,0 @@ -// Public API (also exposed as auto-imports defined in core/imports.ts) - -// App -export { useNitroApp } from "./internal/app"; - -// Config -export { useRuntimeConfig, useAppConfig } from "./internal/config"; - -// Storage -export { useStorage } from "./internal/storage"; - -// Type (only) helpers -export { defineNitroPlugin } from "./internal/plugin"; -export { defineRouteMeta } from "./internal/meta"; -export { defineNitroErrorHandler } from "./internal/error/utils"; - -// Renderer -export { defineRenderHandler } from "./internal/renderer"; - -// Route rules -export { getRouteRules } from "./internal/route-rules"; - -// Context -export { useEvent } from "./internal/context"; - -// Tasks -export { defineTask, runTask } from "./internal/task"; - -// Database -export { useDatabase } from "./internal/database"; - -// Cache -export { - defineCachedFunction, - defineCachedEventHandler, - cachedFunction, - cachedEventHandler, -} from "./internal/cache"; diff --git a/src/runtime/internal/app.ts b/src/runtime/internal/app.ts index 9765459e3d..7f3f0089e7 100644 --- a/src/runtime/internal/app.ts +++ b/src/runtime/internal/app.ts @@ -1,210 +1,255 @@ -import destr from "destr"; -import { - type H3Error, - type H3Event, - createApp, - createRouter, - eventHandler, - fetchWithEvent, - isEvent, - lazyEventHandler, - toNodeListener, -} from "h3"; -import { createHooks } from "hookable"; import type { CaptureError, + MatchedRouteRules, NitroApp, + NitroAsyncContext, NitroRuntimeHooks, -} from "nitropack/types"; -import type { NitroAsyncContext } from "nitropack/types"; -import { Headers, createFetch } from "ofetch"; +} from "nitro/types"; +import type { ServerRequest, ServerRequestContext } from "srvx"; +import type { H3Config, H3EventContext, Middleware, WebSocketHooks } from "h3"; +import { H3Core, toRequest } from "h3"; +import { HookableCore } from "hookable"; +import { nitroAsyncContext } from "./context.ts"; + +// IMPORTANT: virtual imports and user code should be imported last to avoid initialization order issues +import errorHandler from "#nitro/virtual/error-handler"; +import { plugins } from "#nitro/virtual/plugins"; +import { + findRoute, + findRouteRules, + globalMiddleware, + findRoutedMiddleware, +} from "#nitro/virtual/routing"; import { - fetchNodeRequestHandler, - callNodeRequestHandler, - type AbstractRequest, -} from "node-mock-http"; -import errorHandler from "#nitro-internal-virtual/error-handler"; -import { plugins } from "#nitro-internal-virtual/plugins"; -import { handlers } from "#nitro-internal-virtual/server-handlers"; -import { cachedEventHandler } from "./cache"; -import { useRuntimeConfig } from "./config"; -import { nitroAsyncContext } from "./context"; -import { createRouteRulesHandler, getRouteRulesForPath } from "./route-rules"; -import { normalizeFetchResponse } from "./utils"; + hasRouteRules, + hasRoutedMiddleware, + hasGlobalMiddleware, + hasRoutes, + hasHooks, + hasPlugins, +} from "#nitro/virtual/feature-flags"; + +declare global { + var __nitro__: + | Partial> + | undefined; +} -function createNitroApp(): NitroApp { - const config = useRuntimeConfig(); +const APP_ID = import.meta.prerender ? "prerender" : "default"; + +export function useNitroApp(): NitroApp { + let instance: NitroApp | undefined = (useNitroApp as any)._instance; + if (instance) { + return instance; + } + instance = (useNitroApp as any)._instance = createNitroApp(); + globalThis.__nitro__ = globalThis.__nitro__ || {}; + globalThis.__nitro__[APP_ID] = instance; + if (hasPlugins) { + initNitroPlugins(instance); + } + return instance; +} + +export function useNitroHooks(): HookableCore { + const nitroApp = useNitroApp(); + const hooks = nitroApp.hooks; + if (hooks) { + return hooks; + } + return (nitroApp.hooks = new HookableCore()); +} + +export function serverFetch( + resource: string | URL | Request, + init?: RequestInit, + context?: ServerRequestContext | H3EventContext +): Promise { + const req = toRequest(resource, init); + req.context = { ...req.context, ...context }; + const appHandler = useNitroApp().fetch; + try { + return Promise.resolve(appHandler(req)); + } catch (error) { + return Promise.reject(error); + } +} + +export async function resolveWebsocketHooks(req: ServerRequest): Promise> { + // https://github.com/h3js/h3/blob/c11ca743d476e583b3b47de1717e6aae92114357/src/utils/ws.ts#L37 + const hooks = ((await serverFetch(req)) as any).crossws as Partial; + return hooks || {}; +} + +export function fetch( + resource: string | URL | Request, + init?: RequestInit, + context?: ServerRequestContext | H3EventContext +): Promise { + if (typeof resource === "string" && resource.charCodeAt(0) === 47) { + return serverFetch(resource, init, context); + } + resource = (resource as any)._request || resource; // unwrap srvx request + return fetch(resource, init); +} - const hooks = createHooks(); +function createNitroApp(): NitroApp { + const hooks = hasHooks ? new HookableCore() : undefined; - const captureError: CaptureError = (error, context = {}) => { - const promise = hooks - .callHookParallel("error", error, context) - .catch((error_) => { - console.error("Error while capturing another error", error_); + const captureError: CaptureError = (error, errorCtx) => { + const promise = + hasHooks && + hooks!.callHook("error", error, errorCtx)?.catch?.((hookError: any) => { + console.error("Error while capturing another error", hookError); }); - if (context.event && isEvent(context.event)) { - const errors = context.event.context.nitro?.errors; + if (errorCtx?.event) { + const errors = errorCtx.event.req.context?.nitro?.errors; if (errors) { - errors.push({ error, context }); + errors.push({ error, context: errorCtx }); } - if (context.event.waitUntil) { - context.event.waitUntil(promise); + if (hasHooks && promise && typeof errorCtx.event.req.waitUntil === "function") { + errorCtx.event.req.waitUntil(promise); } } }; - const h3App = createApp({ - debug: destr(process.env.DEBUG), - onError: (error, event) => { - captureError(error, { event, tags: ["request"] }); - return errorHandler(error as H3Error, event); + const h3App = createH3App({ + onError(error, event) { + hasHooks && captureError(error, { event }); + return errorHandler(error, event); }, - onRequest: async (event) => { - // Init nitro context - event.context.nitro = event.context.nitro || { errors: [] }; - - // Support platform context provided by local fetch - const envContext: { waitUntil?: H3Event["waitUntil"] } | undefined = ( - event.node.req as unknown as { __unenv__: any } - )?.__unenv__; - if (envContext) { - Object.assign(event.context, envContext); - } - - // Assign bound fetch to context - event.fetch = (req, init) => - fetchWithEvent(event, req, init, { fetch: localFetch }); - event.$fetch = (req, init) => - fetchWithEvent(event, req, init as RequestInit, { - fetch: $fetch as any, - }); - - // https://github.com/nitrojs/nitro/issues/1420 - event.waitUntil = (promise) => { - if (!event.context.nitro._waitUntilPromises) { - event.context.nitro._waitUntilPromises = []; - } - event.context.nitro._waitUntilPromises.push(promise); - if (envContext?.waitUntil) { - envContext.waitUntil(promise); - } - }; - - event.captureError = (error, context) => { - captureError(error, { event, ...context }); - }; + }); - await nitroApp.hooks.callHook("request", event).catch((error) => { + if (hasHooks) { + h3App.config.onRequest = (event) => { + return hooks!.callHook("request", event)?.catch?.((error: any) => { captureError(error, { event, tags: ["request"] }); }); - }, - onBeforeResponse: async (event, response) => { - await nitroApp.hooks - .callHook("beforeResponse", event, response) - .catch((error) => { - captureError(error, { event, tags: ["request", "response"] }); - }); - }, - onAfterResponse: async (event, response) => { - await nitroApp.hooks - .callHook("afterResponse", event, response) - .catch((error) => { - captureError(error, { event, tags: ["request", "response"] }); - }); - }, - }); - - const router = createRouter({ - preemptive: true, - }); - - // Create local fetch caller - const nodeHandler = toNodeListener(h3App); - const localCall = (aRequest: AbstractRequest) => - callNodeRequestHandler(nodeHandler, aRequest); - const localFetch: typeof fetch = (input, init) => { - if (!input.toString().startsWith("/")) { - return globalThis.fetch(input, init); - } - return fetchNodeRequestHandler( - nodeHandler, - input as string /* TODO */, - init - ).then((response) => normalizeFetchResponse(response)); - }; - const $fetch = createFetch({ - fetch: localFetch, - Headers, - defaults: { baseURL: config.app.baseURL }, - }); - - // @ts-ignore - globalThis.$fetch = $fetch; - - // Register route rule handlers - h3App.use(createRouteRulesHandler({ localFetch })); - - for (const h of handlers) { - let handler = h.lazy ? lazyEventHandler(h.handler) : h.handler; - if (h.middleware || !h.route) { - const middlewareBase = (config.app.baseURL + (h.route || "/")).replace( - /\/+/g, - "/" - ); - h3App.use(middlewareBase, handler); - } else { - const routeRules = getRouteRulesForPath( - h.route.replace(/:\w+|\*\*/g, "_") - ); - if (routeRules.cache) { - handler = cachedEventHandler(handler, { - group: "nitro/routes", - ...routeRules.cache, - }); - } - router.use(h.route, handler, h.method); - } + }; + h3App.config.onResponse = (res, event) => { + return hooks!.callHook("response", res, event)?.catch?.((error: any) => { + captureError(error, { event, tags: ["response"] }); + }); + }; } - h3App.use(config.app.baseURL as string, router.handler); + let appHandler = (req: ServerRequest): Response | Promise => { + req.context ||= {}; + req.context.nitro = req.context.nitro || { errors: [] }; + return h3App.fetch(req); + }; // Experimental async context support if (import.meta._asyncContext) { - const _handler = h3App.handler; - h3App.handler = (event) => { - const ctx: NitroAsyncContext = { event }; - return nitroAsyncContext.callAsync(ctx, () => _handler(event)); + const originalHandler = appHandler; + appHandler = (req: ServerRequest): Promise => { + const asyncCtx: NitroAsyncContext = { request: req as Request }; + return nitroAsyncContext.callAsync(asyncCtx, () => originalHandler(req)); }; } const app: NitroApp = { + fetch: appHandler, + h3: h3App, hooks, - h3App, - router, - localCall, - localFetch, captureError, }; return app; } -function runNitroPlugins(nitroApp: NitroApp) { +function initNitroPlugins(app: NitroApp) { for (const plugin of plugins) { try { - plugin(nitroApp); + plugin(app as NitroApp & { hooks: NonNullable }); } catch (error: any) { - nitroApp.captureError(error, { tags: ["plugin"] }); + app.captureError?.(error, { tags: ["plugin"] }); throw error; } } + return app; } -export const nitroApp: NitroApp = createNitroApp(); +function createH3App(config: H3Config) { + // Create H3 app + const h3App = new H3Core(config); + + // Compiled route matching + hasRoutes && (h3App["~findRoute"] = (event) => findRoute(event.req.method, event.url.pathname)); + + hasGlobalMiddleware && h3App["~middleware"].push(...globalMiddleware); + + if (hasRouteRules || hasRoutedMiddleware) { + h3App["~getMiddleware"] = (event, route) => { + const needsRouting = hasRouteRules || hasRoutedMiddleware; + const pathname = needsRouting ? event.url.pathname : undefined; + const method = needsRouting ? event.req.method : undefined; + const middleware: Middleware[] = []; + if (hasRouteRules) { + const routeRules = getRouteRules(method!, pathname!); + event.context.routeRules = routeRules?.routeRules; + if (routeRules?.routeRuleMiddleware.length) { + middleware.push(...routeRules.routeRuleMiddleware); + } + } + hasGlobalMiddleware && middleware.push(...h3App["~middleware"]); + hasRoutedMiddleware && + middleware.push(...findRoutedMiddleware(method!, pathname!).map((r) => r.data)); + if (hasRoutes && route?.data?.middleware?.length) { + middleware.push(...route.data.middleware); + } + return middleware; + }; + } -export function useNitroApp() { - return nitroApp; + return h3App; } -runNitroPlugins(nitroApp); +export function getRouteRules( + method: string, + pathname: string +): { + routeRules?: MatchedRouteRules; + routeRuleMiddleware: Middleware[]; +} { + const m = findRouteRules(method, pathname); + if (!m?.length) { + return { routeRuleMiddleware: [] }; + } + const routeRules: MatchedRouteRules = {}; + for (const layer of m) { + for (const rule of layer.data) { + const currentRule = routeRules[rule.name]; + if (currentRule) { + if (rule.options === false) { + // Remove/Reset existing rule with `false` value + delete routeRules[rule.name]; + continue; + } + if (typeof currentRule.options === "object" && typeof rule.options === "object") { + // Merge nested rule objects + currentRule.options = { ...currentRule.options, ...rule.options }; + } else { + // Override rule if non object + currentRule.options = rule.options; + } + // Routing (route and params) + currentRule.route = rule.route; + currentRule.params = { ...currentRule.params, ...layer.params }; + } else if (rule.options !== false) { + routeRules[rule.name] = { ...rule, params: layer.params }; + } + } + } + const middleware = []; + for (const rule of Object.values(routeRules)) { + if (rule.options === false || !rule.handler) { + continue; + } + middleware.push(rule.handler(rule)); + } + return { + routeRules, + routeRuleMiddleware: middleware, + }; +} diff --git a/src/runtime/internal/cache.ts b/src/runtime/internal/cache.ts index f848b82c79..76aad1ce83 100644 --- a/src/runtime/internal/cache.ts +++ b/src/runtime/internal/cache.ts @@ -1,496 +1,60 @@ +import { defineHandler, handleCacheHeaders, toResponse } from "h3"; +import { FastResponse } from "srvx"; import { - type EventHandler, - createEvent, - defineEventHandler, - fetchWithEvent, - handleCacheHeaders, - isEvent, - splitCookiesString, -} from "h3"; -import type { EventHandlerRequest, EventHandlerResponse, H3Event } from "h3"; -import type { - $Fetch, - CacheEntry, - CacheOptions, - CachedEventHandlerOptions, - NitroFetchRequest, - ResponseCacheEntry, -} from "nitropack/types"; -import { parseURL } from "ufo"; -import { useNitroApp } from "./app"; -import { useStorage } from "./storage"; -import { hash } from "./hash"; -import type { TransactionOptions } from "unstorage"; + defineCachedFunction as _defineCachedFunction, + defineCachedHandler as _defineCachedHandler, + setStorage, +} from "ocache"; +import { useNitroApp } from "./app.ts"; +import { useStorage } from "./storage.ts"; -function defaultCacheOptions() { - return { - name: "_", - base: "/cache", - swr: true, - maxAge: 1, - } as const; -} - -type ResolvedCacheEntry = CacheEntry & { value: T }; - -export function defineCachedFunction( - fn: (...args: ArgsT) => T | Promise, - opts: CacheOptions = {} -): (...args: ArgsT) => Promise { - opts = { ...defaultCacheOptions(), ...opts }; - - const pending: { [key: string]: Promise } = {}; - - // Normalize cache params - const group = opts.group || "nitro/functions"; - const name = opts.name || fn.name || "_"; - const integrity = opts.integrity || hash([fn, opts]); - const validate = opts.validate || ((entry) => entry.value !== undefined); - - async function get( - key: string, - resolver: () => T | Promise, - shouldInvalidateCache?: boolean, - event?: H3Event - ): Promise> { - // Use extension for key to avoid conflicting with parent namespace (foo/bar and foo/bar/baz) - const cacheKey = [opts.base, group, name, key + ".json"] - .filter(Boolean) - .join(":") - .replace(/:\/$/, ":index"); - - let entry: CacheEntry = - ((await useStorage() - .getItem(cacheKey) - .catch((error) => { - console.error(`[cache] Cache read error.`, error); - useNitroApp().captureError(error, { event, tags: ["cache"] }); - })) as unknown) || {}; - - // https://github.com/nitrojs/nitro/issues/2160 - if (typeof entry !== "object") { - entry = {}; - const error = new Error("Malformed data read from cache."); - console.error("[cache]", error); - useNitroApp().captureError(error, { event, tags: ["cache"] }); - } +import type { EventHandler, H3Event } from "h3"; +import type { CacheOptions, CachedEventHandlerOptions } from "nitro/types"; - const ttl = (opts.maxAge ?? 0) * 1000; - if (ttl) { - entry.expires = Date.now() + ttl; - } +let _storageReady = false; - const expired = - shouldInvalidateCache || - entry.integrity !== integrity || - (ttl && Date.now() - (entry.mtime || 0) > ttl) || - validate(entry) === false; - - const _resolve = async () => { - const isPending = pending[key]; - if (!isPending) { - if ( - entry.value !== undefined && - (opts.staleMaxAge || 0) >= 0 && - opts.swr === false - ) { - // Remove cached entry to prevent using expired cache on concurrent requests - entry.value = undefined; - entry.integrity = undefined; - entry.mtime = undefined; - entry.expires = undefined; - } - pending[key] = Promise.resolve(resolver()); - } - - try { - entry.value = await pending[key]; - } catch (error) { - // Make sure entries that reject get removed. - if (!isPending) { - delete pending[key]; - } - // Re-throw error to make sure the caller knows the task failed. - throw error; - } - - if (!isPending) { - // Update mtime, integrity + validate and set the value in cache only the first time the request is made. - entry.mtime = Date.now(); - entry.integrity = integrity; - delete pending[key]; - if (validate(entry) !== false) { - let setOpts: TransactionOptions | undefined; - if (opts.maxAge && !opts.swr /* TODO: respect staleMaxAge */) { - setOpts = { ttl: opts.maxAge }; - } - const promise = useStorage() - .setItem(cacheKey, entry, setOpts) - .catch((error) => { - console.error(`[cache] Cache write error.`, error); - useNitroApp().captureError(error, { event, tags: ["cache"] }); - }); - if (event?.waitUntil) { - event.waitUntil(promise); - } - } - } - }; - - const _resolvePromise = expired ? _resolve() : Promise.resolve(); - - if (entry.value === undefined) { - await _resolvePromise; - } else if (expired && event && event.waitUntil) { - event.waitUntil(_resolvePromise); - } - - if (opts.swr && validate(entry) !== false) { - _resolvePromise.catch((error) => { - console.error(`[cache] SWR handler error.`, error); - useNitroApp().captureError(error, { event, tags: ["cache"] }); - }); - return entry as ResolvedCacheEntry; - } - - return _resolvePromise.then(() => entry) as Promise>; +function ensureStorage() { + if (_storageReady) { + return; } - - return async (...args) => { - const shouldBypassCache = await opts.shouldBypassCache?.(...args); - if (shouldBypassCache) { - return fn(...args); - } - const key = await (opts.getKey || getKey)(...args); - const shouldInvalidateCache = await opts.shouldInvalidateCache?.(...args); - const entry = await get( - key, - () => fn(...args), - shouldInvalidateCache, - args[0] && isEvent(args[0]) ? args[0] : undefined - ); - let value = entry.value; - if (opts.transform) { - value = (await opts.transform(entry, ...args)) || value; - } - return value; - }; -} - -export function cachedFunction( - fn: (...args: ArgsT) => T | Promise, - opts: CacheOptions = {} -): (...args: ArgsT) => Promise { - return defineCachedFunction(fn, opts); -} - -function getKey(...args: unknown[]) { - return args.length > 0 ? hash(args) : ""; + _storageReady = true; + const storage = useStorage(); + setStorage({ + get: (key) => storage.getItem(key) as any, + set: (key, value, opts) => + storage.setItem(key, value as any, opts?.ttl ? { ttl: opts.ttl } : undefined), + }); } -function escapeKey(key: string | string[]) { - return String(key).replace(/\W/g, ""); +function defaultOnError(error: unknown) { + console.error("[cache]", error); + useNitroApp().captureError?.(error as Error, { tags: ["cache"] }); } -export function defineCachedEventHandler< - Request extends EventHandlerRequest = EventHandlerRequest, - Response = EventHandlerResponse, ->( - handler: EventHandler, - opts?: CachedEventHandlerOptions -): EventHandler, Response>; -// TODO: remove when appropriate -// This signature provides backwards compatibility with previous signature where first generic was return type -export function defineCachedEventHandler< - Request = Omit, - Response = EventHandlerResponse, ->( - handler: EventHandler< - Request extends EventHandlerRequest ? Request : EventHandlerRequest, - Request extends EventHandlerRequest ? Response : Request - >, - opts?: CachedEventHandlerOptions< - Request extends EventHandlerRequest ? Response : Request - > -): EventHandler< - Request extends EventHandlerRequest ? Request : EventHandlerRequest, - Request extends EventHandlerRequest ? Response : Request ->; -export function defineCachedEventHandler< - Request extends EventHandlerRequest = EventHandlerRequest, - Response = EventHandlerResponse, ->( - handler: EventHandler, - opts: CachedEventHandlerOptions = defaultCacheOptions() -): EventHandler { - const variableHeaderNames = (opts.varies || []) - .filter(Boolean) - .map((h) => h.toLowerCase()) - .sort(); - - const _opts: CacheOptions> = { +export function defineCachedFunction( + fn: (...args: ArgsT) => T | Promise, + opts: CacheOptions = {} +): (...args: ArgsT) => Promise { + ensureStorage(); + return _defineCachedFunction(fn, { + group: "nitro/functions", + onError: defaultOnError, ...opts, - getKey: async (event: H3Event) => { - // Custom user-defined key - const customKey = await opts.getKey?.(event); - if (customKey) { - return escapeKey(customKey); - } - // Auto-generated key - const _path = - event.node.req.originalUrl || event.node.req.url || event.path; - let _pathname: string; - try { - _pathname = - escapeKey(decodeURI(parseURL(_path).pathname)).slice(0, 16) || - "index"; - } catch { - _pathname = "-"; - } - const _hashedPath = `${_pathname}.${hash(_path)}`; - const _headers = variableHeaderNames - .map((header) => [header, event.node.req.headers[header]]) - .map(([name, value]) => `${escapeKey(name as string)}.${hash(value)}`); - return [_hashedPath, ..._headers].join(":"); - }, - validate: (entry) => { - if (!entry.value) { - return false; - } - if (entry.value.code >= 400) { - return false; - } - if (entry.value.body === undefined) { - return false; - } - // https://github.com/nitrojs/nitro/pull/1857 - if ( - entry.value.headers.etag === "undefined" || - entry.value.headers["last-modified"] === "undefined" - ) { - return false; - } - return true; - }, - group: opts.group || "nitro/handlers", - integrity: opts.integrity || hash([handler, opts]), - }; - - const _cachedHandler = cachedFunction>( - async (incomingEvent: H3Event) => { - // Only pass headers which are defined in opts.varies - const variableHeaders: Record = {}; - for (const header of variableHeaderNames) { - const value = incomingEvent.node.req.headers[header]; - if (value !== undefined) { - variableHeaders[header] = value; - } - } - - // Create proxies to avoid sharing state with user request - const reqProxy = cloneWithProxy(incomingEvent.node.req, { - headers: variableHeaders, - }); - const resHeaders: Record = {}; - let _resSendBody; - const resProxy = cloneWithProxy(incomingEvent.node.res, { - statusCode: 200, - writableEnded: false, - writableFinished: false, - headersSent: false, - closed: false, - getHeader(name) { - return resHeaders[name]; - }, - setHeader(name, value) { - resHeaders[name] = value as any; - return this as typeof incomingEvent.node.res; - }, - getHeaderNames() { - return Object.keys(resHeaders); - }, - hasHeader(name) { - return name in resHeaders; - }, - removeHeader(name) { - delete resHeaders[name]; - }, - getHeaders() { - return resHeaders; - }, - end(chunk, arg2?, arg3?) { - if (typeof chunk === "string") { - _resSendBody = chunk; - } - if (typeof arg2 === "function") { - arg2(); - } - if (typeof arg3 === "function") { - arg3(); - } - return this as typeof incomingEvent.node.res; - }, - write(chunk, arg2?, arg3?) { - if (typeof chunk === "string") { - _resSendBody = chunk; - } - if (typeof arg2 === "function") { - arg2(undefined); - } - if (typeof arg3 === "function") { - arg3(); - } - return true; - }, - writeHead(statusCode, headers) { - this.statusCode = statusCode; - if (headers) { - if (Array.isArray(headers) || typeof headers === "string") { - throw new TypeError("Raw headers is not supported."); - } - for (const header in headers) { - const value = headers[header]; - if (value !== undefined) { - (this as typeof incomingEvent.node.res).setHeader( - header, - value - ); - } - } - } - return this as typeof incomingEvent.node.res; - }, - }); - - // Call handler - const event = createEvent(reqProxy, resProxy); - // Assign bound fetch to context - event.fetch = (url, fetchOptions) => - fetchWithEvent(event, url, fetchOptions, { - fetch: useNitroApp().localFetch as any, - }); - event.$fetch = (url, fetchOptions) => - fetchWithEvent(event, url, fetchOptions as RequestInit, { - fetch: globalThis.$fetch as any, - }); - event.waitUntil = incomingEvent.waitUntil; - event.context = incomingEvent.context; - event.context.cache = { - options: _opts, - }; - const body = (await handler(event)) || _resSendBody; - - // Collect cacheable headers - const headers = event.node.res.getHeaders(); - headers.etag = String( - headers.Etag || headers.etag || `W/"${hash(body)}"` - ); - headers["last-modified"] = String( - headers["Last-Modified"] || - headers["last-modified"] || - new Date().toUTCString() - ); - const cacheControl = []; - if (opts.swr) { - if (opts.maxAge) { - cacheControl.push(`s-maxage=${opts.maxAge}`); - } - if (opts.staleMaxAge) { - cacheControl.push(`stale-while-revalidate=${opts.staleMaxAge}`); - } else { - cacheControl.push("stale-while-revalidate"); - } - } else if (opts.maxAge) { - cacheControl.push(`max-age=${opts.maxAge}`); - } - if (cacheControl.length > 0) { - headers["cache-control"] = cacheControl.join(", "); - } - - // Create cache entry for response - const cacheEntry: ResponseCacheEntry = { - code: event.node.res.statusCode, - headers, - body, - }; - - return cacheEntry; - }, - _opts - ); - - return defineEventHandler(async (event) => { - // Headers-only mode - if (opts.headersOnly) { - // TODO: Send SWR too - if (handleCacheHeaders(event, { maxAge: opts.maxAge })) { - return; - } - return handler(event); - } - - // Call with cache - const response = (await _cachedHandler( - event - )) as ResponseCacheEntry; - - // Don't continue if response is already handled by user - if (event.node.res.headersSent || event.node.res.writableEnded) { - return response.body; - } - - // Check for cache headers - if ( - handleCacheHeaders(event, { - modifiedTime: new Date(response.headers["last-modified"] as string), - etag: response.headers.etag as string, - maxAge: opts.maxAge, - }) - ) { - return; - } - - // Send status and headers - event.node.res.statusCode = response.code; - for (const name in response.headers) { - const value = response.headers[name]; - if (name === "set-cookie") { - // TODO: Show warning and remove this header in the next major version of Nitro - event.node.res.appendHeader( - name, - splitCookiesString(value as string[]) - ); - } else { - if (value !== undefined) { - event.node.res.setHeader(name, value); - } - } - } - - // Send body - return response.body; }); } -function cloneWithProxy( - obj: T, - overrides: Partial -): T { - return new Proxy(obj, { - get(target, property, receiver) { - if (property in overrides) { - return overrides[property as keyof T]; - } - return Reflect.get(target, property, receiver); - }, - set(target, property, value, receiver) { - if (property in overrides) { - overrides[property as keyof T] = value; - return true; - } - return Reflect.set(target, property, value, receiver); - }, +export function defineCachedHandler( + handler: EventHandler, + opts: CachedEventHandlerOptions = {} +): EventHandler { + ensureStorage(); + const ocacheHandler = _defineCachedHandler(handler as any, { + group: "nitro/handlers", + onError: defaultOnError, + toResponse: (value, event) => toResponse(value, event as H3Event), + createResponse: (body, init) => new FastResponse(body, init), + handleCacheHeaders: (event, conditions) => handleCacheHeaders(event as H3Event, conditions), + ...opts, }); + return defineHandler((event) => ocacheHandler(event as any)); } - -export const cachedEventHandler = defineCachedEventHandler; diff --git a/src/runtime/internal/client.ts b/src/runtime/internal/client.ts deleted file mode 100644 index 368c9e3806..0000000000 --- a/src/runtime/internal/client.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { $Fetch, NitroFetchRequest } from "nitropack/types"; -// Client polyfill -import { $fetch } from "ofetch"; - -if (!globalThis.$fetch) { - globalThis.$fetch = $fetch as $Fetch; -} diff --git a/src/runtime/internal/config.ts b/src/runtime/internal/config.ts deleted file mode 100644 index eadaf89ead..0000000000 --- a/src/runtime/internal/config.ts +++ /dev/null @@ -1,84 +0,0 @@ -import type { H3Event } from "h3"; -import { klona } from "klona"; -import type { NitroRuntimeConfig } from "nitropack/types"; -import { appConfig as _inlineAppConfig } from "#nitro-internal-virtual/app-config"; -import { type EnvOptions, applyEnv } from "./utils.env"; - -// Static runtime config inlined by nitro build -const _inlineRuntimeConfig = process.env.RUNTIME_CONFIG as any; -const envOptions: EnvOptions = { - prefix: "NITRO_", - altPrefix: - _inlineRuntimeConfig.nitro.envPrefix ?? process.env.NITRO_ENV_PREFIX ?? "_", - envExpansion: - _inlineRuntimeConfig.nitro.envExpansion ?? - process.env.NITRO_ENV_EXPANSION ?? - false, -}; - -// Runtime config -const _sharedRuntimeConfig = _deepFreeze( - applyEnv(klona(_inlineRuntimeConfig), envOptions) -); -export function useRuntimeConfig< - T extends NitroRuntimeConfig = NitroRuntimeConfig, ->(event?: H3Event): T { - // Backwards compatibility with ambient context - if (!event) { - return _sharedRuntimeConfig as T; - } - // Reuse cached runtime config from event context - if (event.context.nitro.runtimeConfig) { - return event.context.nitro.runtimeConfig; - } - // Prepare runtime config for event context - const runtimeConfig = klona(_inlineRuntimeConfig) as T; - applyEnv(runtimeConfig, envOptions); - event.context.nitro.runtimeConfig = runtimeConfig; - return runtimeConfig; -} - -// App config -const _sharedAppConfig = _deepFreeze(klona(_inlineAppConfig)); -export function useAppConfig(event?: H3Event) { - // Backwards compatibility with ambient context - if (!event) { - return _sharedAppConfig; - } - // Reuse cached app config from event context - if (event.context.nitro.appConfig) { - return event.context.nitro.appConfig; - } - // Prepare app config for event context - const appConfig = klona(_inlineAppConfig); - event.context.nitro.appConfig = appConfig; - return appConfig; -} - -// --- Utils --- - -function _deepFreeze(object: Record) { - const propNames = Object.getOwnPropertyNames(object); - for (const name of propNames) { - const value = object[name]; - if (value && typeof value === "object") { - _deepFreeze(value); - } - } - return Object.freeze(object); -} - -// --- Deprecated default export --- -// TODO: Remove in next major version -export default new Proxy(Object.create(null), { - get: (_, prop) => { - console.warn( - "Please use `useRuntimeConfig()` instead of accessing config directly." - ); - const runtimeConfig = useRuntimeConfig(); - if (prop in runtimeConfig) { - return runtimeConfig[prop as string]; - } - return undefined; - }, -}); diff --git a/src/runtime/internal/context.ts b/src/runtime/internal/context.ts index e8dfca194a..8a3722298f 100644 --- a/src/runtime/internal/context.ts +++ b/src/runtime/internal/context.ts @@ -1,30 +1,33 @@ +import type { NitroAsyncContext } from "nitro/types"; +import type { ServerRequest } from "srvx"; + import { AsyncLocalStorage } from "node:async_hooks"; -import { type H3Event, createError } from "h3"; -import type { NitroAsyncContext } from "nitropack/types"; -import { getContext } from "unctx"; +import { HTTPError } from "h3"; +import { getContext, type UseContext } from "unctx"; -export const nitroAsyncContext = getContext("nitro-app", { - asyncContext: import.meta._asyncContext, - AsyncLocalStorage: import.meta._asyncContext ? AsyncLocalStorage : undefined, -}); +export const nitroAsyncContext: UseContext = /* @__PURE__ */ (() => + getContext("nitro-app", { + asyncContext: import.meta._asyncContext, + AsyncLocalStorage: import.meta._asyncContext ? AsyncLocalStorage : undefined, + }))(); /** * - * Access to the current Nitro request event. + * Access to the current Nitro request. * * @experimental * - Requires `experimental.asyncContext: true` config to work. * - Works in Node.js and limited runtimes only * */ -export function useEvent(): H3Event { +export function useRequest(): ServerRequest { try { - return nitroAsyncContext.use().event; + return nitroAsyncContext.use().request; } catch { const hint = import.meta._asyncContext ? "Note: This is an experimental feature and might be broken on non-Node.js environments." : "Enable the experimental flag using `experimental.asyncContext: true`."; - throw createError({ + throw new HTTPError({ message: `Nitro request context is not available. ${hint}`, }); } diff --git a/src/runtime/internal/database.ts b/src/runtime/internal/database.ts index 7d713a1afe..632e252fa3 100644 --- a/src/runtime/internal/database.ts +++ b/src/runtime/internal/database.ts @@ -1,6 +1,6 @@ import type { Database } from "db0"; import { createDatabase } from "db0"; -import { connectionConfigs } from "#nitro-internal-virtual/database"; +import { connectionConfigs } from "#nitro/virtual/database"; const instances: Record = Object.create(null); diff --git a/src/runtime/internal/debug.ts b/src/runtime/internal/debug.ts deleted file mode 100644 index e712d301ab..0000000000 --- a/src/runtime/internal/debug.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createDebugger } from "hookable"; -import { defineNitroPlugin } from "./plugin"; - -export default defineNitroPlugin((nitro) => { - createDebugger(nitro.hooks, { tag: "nitro-runtime" }); -}); diff --git a/src/runtime/internal/error/dev.ts b/src/runtime/internal/error/dev.ts index d93d264570..b317f7c2ed 100644 --- a/src/runtime/internal/error/dev.ts +++ b/src/runtime/internal/error/dev.ts @@ -1,56 +1,43 @@ -import { - type H3Event, - type H3Error, - send, - getRequestHeader, - getRequestHeaders, - getRequestURL, - getResponseHeader, - setResponseHeaders, - setResponseStatus, -} from "h3"; +import { HTTPError, type HTTPEvent } from "h3"; +import { getRequestURL } from "h3"; import { readFile } from "node:fs/promises"; import { resolve, dirname } from "node:path"; import consola from "consola"; -import { ErrorParser } from "youch-core"; -import { Youch } from "youch"; -import { SourceMapConsumer } from "source-map"; -import { defineNitroErrorHandler, type InternalHandlerResponse } from "./utils"; +import type { ErrorParser } from "youch-core"; +import { defineNitroErrorHandler } from "./utils.ts"; +import type { InternalHandlerResponse } from "./utils.ts"; +import { FastResponse } from "srvx"; +import type { NitroErrorHandler } from "nitro/types"; -export default defineNitroErrorHandler( +const errorHandler: NitroErrorHandler = defineNitroErrorHandler( async function defaultNitroErrorHandler(error, event) { const res = await defaultHandler(error, event); - setResponseHeaders(event, res.headers!); - setResponseStatus(event, res.status, res.statusText); - return send( - event, - typeof res.body === "string" - ? res.body - : JSON.stringify(res.body, null, 2) + return new FastResponse( + typeof res.body === "string" ? res.body : JSON.stringify(res.body, null, 2), + res ); } ); +export default errorHandler; + export async function defaultHandler( - error: H3Error, - event: H3Event, + error: HTTPError, + event: HTTPEvent, opts?: { silent?: boolean; json?: boolean } ): Promise { - const isSensitive = error.unhandled || error.fatal; - const statusCode = error.statusCode || 500; - const statusMessage = error.statusMessage || "Server Error"; - // prettier-ignore - const url = getRequestURL(event, { xForwardedHost: true, xForwardedProto: true }) + const unhandled = error.unhandled ?? !HTTPError.isError(error); + const { status = 500, statusText = "" } = unhandled ? {} : error; + const url = getRequestURL(event, { xForwardedHost: true, xForwardedProto: true }); // Redirects with base URL - if (statusCode === 404) { + if (status === 404) { const baseURL = import.meta.baseURL || "/"; if (/^\/[^/]/.test(baseURL) && !url.pathname.startsWith(baseURL)) { - const redirectTo = `${baseURL}${url.pathname.slice(1)}${url.search}`; return { status: 302, statusText: "Found", - headers: { location: redirectTo }, + headers: new Headers({ location: `${baseURL}${url.pathname.slice(1)}${url.search}` }), body: `Redirecting...`, }; } @@ -59,84 +46,68 @@ export async function defaultHandler( // Load stack trace with source maps await loadStackTrace(error).catch(consola.error); + const { Youch } = await import("youch"); + // https://github.com/poppinss/youch const youch = new Youch(); // Console output - if (isSensitive && !opts?.silent) { - // prettier-ignore - const tags = [error.unhandled && "[unhandled]", error.fatal && "[fatal]"].filter(Boolean).join(" ") - const ansiError = await ( - await youch.toANSI(error) - ).replaceAll(process.cwd(), "."); - consola.error( - `[request error] ${tags} [${event.method}] ${url}\n\n`, - ansiError - ); + if (unhandled && !opts?.silent) { + const ansiError = (await youch.toANSI(error)).replaceAll(process.cwd(), "."); + consola.error(`[request error] [${event.req.method}] ${url}\n\n`, ansiError); } // Use HTML response only when user-agent expects it (browsers) - const useJSON = - opts?.json || !getRequestHeader(event, "accept")?.includes("text/html"); - - // Prepare headers - const headers: HeadersInit = { - "content-type": useJSON ? "application/json" : "text/html", - // Prevent browser from guessing the MIME types of resources. - "x-content-type-options": "nosniff", - // Prevent error page from being embedded in an iframe - "x-frame-options": "DENY", - // Prevent browsers from sending the Referer header - "referrer-policy": "no-referrer", - // Disable the execution of any js - "content-security-policy": - "script-src 'self' 'unsafe-inline'; object-src 'none'; base-uri 'self';", - }; - if (statusCode === 404 || !getResponseHeader(event, "cache-control")) { - headers["cache-control"] = "no-cache"; - } - - // Prepare body - const body = useJSON - ? { + const useJSON = opts?.json ?? !event.req.headers.get("accept")?.includes("text/html"); + + const headers = new Headers(unhandled ? {} : error.headers); + + if (useJSON) { + headers.set("Content-Type", "application/json; charset=utf-8"); + const jsonBody = + typeof error.toJSON === "function" + ? error.toJSON() + : { status, statusText, message: error.message }; + return { + status, + statusText, + headers, + body: { error: true, - url, - statusCode, - statusMessage, - message: error.message, - data: error.data, stack: error.stack?.split("\n").map((line) => line.trim()), - } - : await youch.toHTML(error, { - request: { - url: url.href, - method: event.method, - headers: getRequestHeaders(event), - }, - }); + ...jsonBody, + }, + }; + } + // HTML response + headers.set("Content-Type", "text/html; charset=utf-8"); return { - status: statusCode, - statusText: statusMessage, + status, + statusText: unhandled ? "" : error.statusText, headers, - body, + body: await youch.toHTML(error, { + request: { + url: url.href, + method: event.req.method, + headers: Object.fromEntries(event.req.headers.entries()), + }, + }), }; } // ---- Source Map support ---- -export async function loadStackTrace(error: any) { +export async function loadStackTrace(error: any): Promise { if (!(error instanceof Error)) { return; } - const parsed = await new ErrorParser() - .defineSourceLoader(sourceLoader) - .parse(error); - const stack = - error.message + - "\n" + - parsed.frames.map((frame) => fmtFrame(frame)).join("\n"); + const { ErrorParser } = await import("youch-core"); + + const parsed = await new ErrorParser().defineSourceLoader(sourceLoader).parse(error); + + const stack = error.message + "\n" + parsed.frames.map((frame) => fmtFrame(frame)).join("\n"); Object.defineProperty(error, "stack", { value: stack }); @@ -156,6 +127,7 @@ async function sourceLoader(frame: StackFrame) { // prettier-ignore const rawSourceMap = await readFile(`${frame.fileName}.map`, "utf8").catch(() => {}); if (rawSourceMap) { + const { SourceMapConsumer } = await import("source-map"); const consumer = await new SourceMapConsumer(rawSourceMap); // prettier-ignore const originalPosition = consumer.originalPositionFor({ line: frame.lineNumber!, column: frame.columnNumber! }); diff --git a/src/runtime/internal/error/hooks.ts b/src/runtime/internal/error/hooks.ts new file mode 100644 index 0000000000..c0e6da7deb --- /dev/null +++ b/src/runtime/internal/error/hooks.ts @@ -0,0 +1,11 @@ +import { useNitroApp } from "../app.ts"; + +function _captureError(error: Error, type: string): void { + console.error(`[${type}]`, error); + useNitroApp().captureError?.(error, { tags: [type] }); +} + +export function trapUnhandledErrors(): void { + process.on("unhandledRejection", (error: Error) => _captureError(error, "unhandledRejection")); + process.on("uncaughtException", (error: Error) => _captureError(error, "uncaughtException")); +} diff --git a/src/runtime/internal/error/prod.ts b/src/runtime/internal/error/prod.ts index 2a9c8acd15..756c6b026d 100644 --- a/src/runtime/internal/error/prod.ts +++ b/src/runtime/internal/error/prod.ts @@ -1,84 +1,49 @@ -import { - type H3Error, - type H3Event, - getRequestURL, - getResponseHeader, - send, - setResponseHeaders, - setResponseStatus, -} from "h3"; -import { defineNitroErrorHandler, type InternalHandlerResponse } from "./utils"; +import { HTTPError, type H3Event, type HTTPEvent } from "h3"; +import type { InternalHandlerResponse } from "./utils.ts"; +import { FastResponse } from "srvx"; +import type { NitroErrorHandler } from "nitro/types"; -export default defineNitroErrorHandler( - function defaultNitroErrorHandler(error, event) { - const res = defaultHandler(error, event); - setResponseHeaders(event, res.headers); - setResponseStatus(event, res.status, res.statusText); - return send(event, JSON.stringify(res.body, null, 2)); - } -); +const errorHandler: NitroErrorHandler = (error, event) => { + const res = defaultHandler(error, event); + return new FastResponse( + typeof res.body === "string" ? res.body : JSON.stringify(res.body, null, 2), + res + ); +}; + +export default errorHandler; -export function defaultHandler( - error: H3Error, - event: H3Event, - opts?: { silent?: boolean; json?: boolean } -): InternalHandlerResponse { - const isSensitive = error.unhandled || error.fatal; - const statusCode = error.statusCode || 500; - const statusMessage = error.statusMessage || "Server Error"; - // prettier-ignore - const url = getRequestURL(event, { xForwardedHost: true, xForwardedProto: true }) +export function defaultHandler(error: HTTPError, event: HTTPEvent): InternalHandlerResponse { + const unhandled = error.unhandled ?? !HTTPError.isError(error); + const { status = 500, statusText = "" } = unhandled ? {} : error; - if (statusCode === 404) { + if (status === 404) { + const url = (event as H3Event).url || new URL(event.req.url); const baseURL = import.meta.baseURL || "/"; if (/^\/[^/]/.test(baseURL) && !url.pathname.startsWith(baseURL)) { - const redirectTo = `${baseURL}${url.pathname.slice(1)}${url.search}`; return { status: 302, - statusText: "Found", - headers: { location: redirectTo }, - body: `Redirecting...`, + headers: new Headers({ location: `${baseURL}${url.pathname.slice(1)}${url.search}` }), }; } } - // Console output - if (isSensitive && !opts?.silent) { - // prettier-ignore - const tags = [error.unhandled && "[unhandled]", error.fatal && "[fatal]"].filter(Boolean).join(" ") - console.error(`[request error] ${tags} [${event.method}] ${url}\n`, error); - } + const headers = new Headers(unhandled ? {} : error.headers); + headers.set("content-type", "application/json; charset=utf-8"); - // Send response - const headers: HeadersInit = { - "content-type": "application/json", - // Prevent browser from guessing the MIME types of resources. - "x-content-type-options": "nosniff", - // Prevent error page from being embedded in an iframe - "x-frame-options": "DENY", - // Prevent browsers from sending the Referer header - "referrer-policy": "no-referrer", - // Disable the execution of any js - "content-security-policy": "script-src 'none'; frame-ancestors 'none';", - }; - setResponseStatus(event, statusCode, statusMessage); - if (statusCode === 404 || !getResponseHeader(event, "cache-control")) { - headers["cache-control"] = "no-cache"; - } - - const body = { - error: true, - url: url.href, - statusCode, - statusMessage, - message: isSensitive ? "Server Error" : error.message, - data: isSensitive ? undefined : error.data, - }; + const jsonBody = unhandled + ? { status, unhandled: true } + : typeof error.toJSON === "function" + ? error.toJSON() + : { status, statusText, message: error.message }; return { - status: statusCode, - statusText: statusMessage, + status, + statusText, headers, - body, + body: { + error: true, + ...jsonBody, + }, }; } diff --git a/src/runtime/internal/error/utils.ts b/src/runtime/internal/error/utils.ts index 175b6a1b92..37dbef2210 100644 --- a/src/runtime/internal/error/utils.ts +++ b/src/runtime/internal/error/utils.ts @@ -1,14 +1,12 @@ -import type { NitroErrorHandler } from "nitropack/types"; +import type { NitroErrorHandler } from "nitro/types"; -export function defineNitroErrorHandler( - handler: NitroErrorHandler -): NitroErrorHandler { +export function defineNitroErrorHandler(handler: NitroErrorHandler): NitroErrorHandler { return handler; } export type InternalHandlerResponse = { - status: number; - statusText: string; - headers: Record; - body: string | Record; + status?: number; + statusText?: string | undefined; + headers?: HeadersInit; + body?: string | Record; }; diff --git a/src/runtime/internal/hash.ts b/src/runtime/internal/hash.ts deleted file mode 100644 index e60ce5685d..0000000000 --- a/src/runtime/internal/hash.ts +++ /dev/null @@ -1,218 +0,0 @@ -import { digest } from "ohash"; - -// hash implementation compatible with ohash v1 to reduce cache invalidation in same semver Nitro versions - -export function hash(value: any) { - return digest(typeof value === "string" ? value : serialize(value)) - .replace(/[-_]/g, "") - .slice(0, 10); -} - -/** -Source: https://github.com/unjs/ohash/blob/v1/src/object-hash.ts -Based on https://github.com/puleos/object-hash v3.0.0 (MIT) - */ - -export function serialize(object: any): string { - const hasher = new Hasher(); - hasher.dispatch(object); - return hasher.buff; -} - -class Hasher { - buff = ""; - #context = new Map(); - - write(str: string) { - this.buff += str; - } - - dispatch(value: any): string | void { - const type = value === null ? "null" : typeof value; - return this[type](value); - } - object(object: any): string | void { - if (object && typeof object.toJSON === "function") { - return this.object(object.toJSON()); - } - - const objString = Object.prototype.toString.call(object); - - let objType = ""; - const objectLength = objString.length; - - // '[object a]'.length === 10, the minimum - objType = - objectLength < 10 - ? "unknown:[" + objString + "]" - : objString.slice(8, objectLength - 1); - - objType = objType.toLowerCase(); - - let objectNumber = null; - - if ((objectNumber = this.#context.get(object)) === undefined) { - this.#context.set(object, this.#context.size); - } else { - return this.dispatch("[CIRCULAR:" + objectNumber + "]"); - } - - if ( - typeof Buffer !== "undefined" && - Buffer.isBuffer && - Buffer.isBuffer(object) - ) { - this.write("buffer:"); - return this.write(object.toString("utf8")); - } - - if ( - objType !== "object" && - objType !== "function" && - objType !== "asyncfunction" - ) { - // @ts-ignore - if (this[objType]) { - // @ts-ignore - this[objType](object); - } else { - this.unknown(object, objType); - } - } else { - const keys = Object.keys(object).sort(); - const extraKeys = [] as readonly string[]; - this.write("object:" + (keys.length + extraKeys.length) + ":"); - const dispatchForKey = (key: string) => { - this.dispatch(key); - this.write(":"); - this.dispatch(object[key]); - this.write(","); - }; - for (const key of keys) { - dispatchForKey(key); - } - for (const key of extraKeys) { - dispatchForKey(key); - } - } - } - array(arr: any, unordered: boolean): string | void { - unordered = unordered === undefined ? false : unordered; - this.write("array:" + arr.length + ":"); - if (!unordered || arr.length <= 1) { - for (const entry of arr) { - this.dispatch(entry); - } - return; - } - const contextAdditions = new Map(); - const entries = arr.map((entry: any) => { - const hasher = new Hasher(); - hasher.dispatch(entry); - for (const [key, value] of hasher.#context) { - contextAdditions.set(key, value); - } - return hasher.toString(); - }); - this.#context = contextAdditions; - entries.sort(); - return this.array(entries, false); - } - date(date: any) { - return this.write("date:" + date.toJSON()); - } - symbol(sym: any) { - return this.write("symbol:" + sym.toString()); - } - unknown(value: any, type: string) { - this.write(type); - if (!value) { - return; - } - this.write(":"); - if (value && typeof value.entries === "function") { - return this.array([...value.entries()], true /* ordered */); - } - } - error(err: any) { - return this.write("error:" + err.toString()); - } - boolean(bool: any) { - return this.write("bool:" + bool); - } - string(string: any) { - this.write("string:" + string.length + ":"); - this.write(string); - } - function(fn: any) { - this.write("fn:"); - if (isNativeFunction(fn)) { - this.dispatch("[native]"); - } else { - this.dispatch(fn.toString()); - } - } - number(number: any) { - return this.write("number:" + number); - } - null() { - return this.write("Null"); - } - undefined() { - return this.write("Undefined"); - } - regexp(regex: any) { - return this.write("regex:" + regex.toString()); - } - arraybuffer(arr: any) { - this.write("arraybuffer:"); - return this.dispatch(new Uint8Array(arr)); - } - url(url: any) { - return this.write("url:" + url.toString()); - } - map(map: any) { - this.write("map:"); - const arr = [...map]; - return this.array(arr, false); - } - set(set: any) { - this.write("set:"); - const arr = [...set]; - return this.array(arr, false); - } - bigint(number: number) { - return this.write("bigint:" + number.toString()); - } -} - -for (const type of [ - "uint8array", - "uint8clampedarray", - "unt8array", - "uint16array", - "unt16array", - "uint32array", - "unt32array", - "float32array", - "float64array", -]) { - // @ts-ignore - Hasher.prototype[type] = function (arr: any) { - this.write(type + ":"); - return this.array([...arr], false); - }; -} - -const nativeFunc = "[native code] }"; -const nativeFuncLength = nativeFunc.length; - -/** Check if the given function is a native function */ -function isNativeFunction(f: any) { - if (typeof f !== "function") { - return false; - } - return ( - Function.prototype.toString.call(f).slice(-nativeFuncLength) === nativeFunc - ); -} diff --git a/src/runtime/internal/index.ts b/src/runtime/internal/index.ts deleted file mode 100644 index e01787237a..0000000000 --- a/src/runtime/internal/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -// Limited INTERNAL exports used by the presets runtime -// Please don't use these in your project code! - -export { - trapUnhandledNodeErrors, - normalizeCookieHeader, - requestHasBody, - joinHeaders, - toBuffer, -} from "./utils"; - -export { - normalizeLambdaIncomingHeaders, - normalizeLambdaOutgoingHeaders, - normalizeLambdaOutgoingBody, -} from "./utils.lambda"; - -export { startScheduleRunner, runCronTasks } from "./task"; -export { getAzureParsedCookiesFromHeaders } from "./utils.azure"; -export { getGracefulShutdownConfig, setupGracefulShutdown } from "./shutdown"; -export { getRouteRulesForPath } from "./route-rules"; diff --git a/src/runtime/internal/lib/http-graceful-shutdown.ts b/src/runtime/internal/lib/http-graceful-shutdown.ts deleted file mode 100644 index e8f2e05656..0000000000 --- a/src/runtime/internal/lib/http-graceful-shutdown.ts +++ /dev/null @@ -1,319 +0,0 @@ -// @ts-nocheck - -// ============================================================================= -// gracefully shuts downs http server -// can be used with http, express, koa, ... -// (c) 2023 Sebastian Hildebrandt -// License: MIT -// https://github.com/sebhildebrandt/http-graceful-shutdown/blob/master/LICENSE -// https://github.com/sebhildebrandt/http-graceful-shutdown/blob/master/lib/index.js -// ============================================================================= - -import http from "node:http"; - -const debug = (...args: unknown[]) => {}; - -/** - * Gracefully shuts down `server` when the process receives - * the passed signals - * - * @param {http.Server} server - * @param {object} opts - * signals: string (each signal separated by SPACE) - * timeout: timeout value for forceful shutdown in ms - * forceExit: force process.exit() - otherwise just let event loop clear - * development: boolean value (if true, no graceful shutdown to speed up development - * preShutdown: optional function. Needs to return a promise. - HTTP sockets are still available and untouched - * onShutdown: optional function. Needs to return a promise. - * finally: optional function, handled at the end of the shutdown. - */ - -function GracefulShutdown(server, opts) { - // option handling - // ---------------------------------- - opts = opts || {}; - - // merge opts with default options - const options = Object.assign( - { - signals: "SIGINT SIGTERM", - timeout: 30_000, - development: false, - forceExit: true, - onShutdown: (signal) => Promise.resolve(signal), - preShutdown: (signal) => Promise.resolve(signal), - }, - opts - ); - - let isShuttingDown = false; - const connections = {}; - let connectionCounter = 0; - const secureConnections = {}; - let secureConnectionCounter = 0; - let failed = false; - let finalRun = false; - - function onceFactory() { - let called = false; - return (emitter, events, callback) => { - function call() { - if (!called) { - called = true; - // eslint-disable-next-line prefer-rest-params - return Reflect.apply(callback, this, arguments); - } - } - for (const e of events) { - emitter.on(e, call); - } - }; - } - - const signals = options.signals - .split(" ") - .map((s) => s.trim()) - .filter((s) => s.length > 0); - - const once = onceFactory(); - - once(process, signals, (signal) => { - debug("received shut down signal", signal); - shutdown(signal) - .then(() => { - if (options.forceExit) { - // eslint-disable-next-line unicorn/no-process-exit - process.exit(failed ? 1 : 0); - } - }) - .catch((error) => { - debug("server shut down error occurred", error); - // eslint-disable-next-line unicorn/no-process-exit - process.exit(1); - }); - }); - - // helper function - // ---------------------------------- - function isFunction(functionToCheck) { - const getType = Object.prototype.toString.call(functionToCheck); - return /^\[object\s([A-Za-z]+)?Function]$/.test(getType); - } - - function destroy(socket, force = false) { - if ((socket._isIdle && isShuttingDown) || force) { - socket.destroy(); - if (socket.server instanceof http.Server) { - delete connections[socket._connectionId]; - } else { - delete secureConnections[socket._connectionId]; - } - } - } - - function destroyAllConnections(force = false) { - // destroy empty and idle connections / all connections (if force = true) - debug("Destroy Connections : " + (force ? "forced close" : "close")); - let counter = 0; - let secureCounter = 0; - for (const key of Object.keys(connections)) { - const socket = connections[key]; - const serverResponse = socket._httpMessage; - - // send connection close header to open connections - if (serverResponse && !force) { - if (!serverResponse.headersSent) { - serverResponse.setHeader("connection", "close"); - } - } else { - counter++; - destroy(socket); - } - } - - debug("Connections destroyed : " + counter); - debug("Connection Counter : " + connectionCounter); - - for (const key of Object.keys(secureConnections)) { - const socket = secureConnections[key]; - const serverResponse = socket._httpMessage; - - // send connection close header to open connections - if (serverResponse && !force) { - if (!serverResponse.headersSent) { - serverResponse.setHeader("connection", "close"); - } - } else { - secureCounter++; - destroy(socket); - } - } - - debug("Secure Connections destroyed : " + secureCounter); - debug("Secure Connection Counter : " + secureConnectionCounter); - } - - // set up server/process events - // ---------------------------------- - server.on("request", (req, res) => { - req.socket._isIdle = false; - if (isShuttingDown && !res.headersSent) { - res.setHeader("connection", "close"); - } - - res.on("finish", () => { - req.socket._isIdle = true; - destroy(req.socket); - }); - }); - - server.on("connection", (socket) => { - if (isShuttingDown) { - socket.destroy(); - } else { - const id = connectionCounter++; - socket._isIdle = true; - socket._connectionId = id; - connections[id] = socket; - - socket.once("close", () => { - delete connections[socket._connectionId]; - }); - } - }); - - server.on("secureConnection", (socket) => { - if (isShuttingDown) { - socket.destroy(); - } else { - const id = secureConnectionCounter++; - socket._isIdle = true; - socket._connectionId = id; - secureConnections[id] = socket; - - socket.once("close", () => { - delete secureConnections[socket._connectionId]; - }); - } - }); - - process.on("close", () => { - debug("closed"); - }); - - // shutdown event (per signal) - // ---------------------------------- - function shutdown(sig) { - function cleanupHttp() { - destroyAllConnections(); - debug("Close http server"); - - return new Promise((resolve, reject) => { - server.close((err) => { - if (err) { - return reject(err); - } - return resolve(true); - }); - }); - } - - debug("shutdown signal - " + sig); - - // Don't bother with graceful shutdown on development to speed up round trip - if (options.development) { - debug("DEV-Mode - immediate forceful shutdown"); - // eslint-disable-next-line unicorn/no-process-exit - return process.exit(0); - } - - function finalHandler() { - if (!finalRun) { - finalRun = true; - if (options.finally && isFunction(options.finally)) { - debug("executing finally()"); - options.finally(); - } - } - - return Promise.resolve(); - } - - // returns true if should force shut down. returns false for shut down without force - function waitForReadyToShutDown(totalNumInterval) { - debug(`waitForReadyToShutDown... ${totalNumInterval}`); - - if (totalNumInterval === 0) { - // timeout reached - debug( - `Could not close connections in time (${options.timeout}ms), will forcefully shut down` - ); - return Promise.resolve(true); - } - - // test all connections closed already? - const allConnectionsClosed = - Object.keys(connections).length === 0 && - Object.keys(secureConnections).length === 0; - - if (allConnectionsClosed) { - debug("All connections closed. Continue to shutting down"); - return Promise.resolve(false); - } - - debug("Schedule the next waitForReadyToShutdown"); - return new Promise((resolve) => { - setTimeout(() => { - resolve(waitForReadyToShutDown(totalNumInterval - 1)); - }, 250); - }); - } - - if (isShuttingDown) { - return Promise.resolve(); - } - - debug("shutting down"); - - return options - .preShutdown(sig) - .then(() => { - isShuttingDown = true; - cleanupHttp(); - }) - .then(() => { - const pollIterations = options.timeout - ? Math.round(options.timeout / 250) - : 0; - - return waitForReadyToShutDown(pollIterations); - }) - .then((force) => { - debug("Do onShutdown now"); - - // if after waiting for connections to drain within timeout period - // or if timeout has reached, we forcefully disconnect all sockets - if (force) { - destroyAllConnections(force); - } - - return options.onShutdown(sig); - }) - .then(finalHandler) - .catch((error) => { - const errString = - typeof error === "string" ? error : JSON.stringify(error); - debug(errString); - failed = true; - throw errString; - }); - } - - function shutdownManual() { - return shutdown("manual"); - } - - return shutdownManual; -} - -export default GracefulShutdown; diff --git a/src/runtime/internal/meta.ts b/src/runtime/internal/meta.ts index 1cf66eaf9d..e09387ca0e 100644 --- a/src/runtime/internal/meta.ts +++ b/src/runtime/internal/meta.ts @@ -1,5 +1,5 @@ -import type { NitroRouteMeta } from "nitropack/types"; +import type { NitroRouteMeta } from "nitro/types"; -export function defineRouteMeta(meta: NitroRouteMeta) { +export function defineRouteMeta(meta: NitroRouteMeta): NitroRouteMeta { return meta; } diff --git a/src/runtime/internal/plugin.ts b/src/runtime/internal/plugin.ts index ff93dca004..b8e49fac2b 100644 --- a/src/runtime/internal/plugin.ts +++ b/src/runtime/internal/plugin.ts @@ -1,7 +1,7 @@ -import type { NitroAppPlugin } from "nitropack/types"; +import type { NitroAppPlugin } from "nitro/types"; -export function defineNitroPlugin(def: NitroAppPlugin) { +export function defineNitroPlugin(def: NitroAppPlugin): NitroAppPlugin { return def; } -export const nitroPlugin = defineNitroPlugin; +export const nitroPlugin: (def: NitroAppPlugin) => NitroAppPlugin = defineNitroPlugin; diff --git a/src/runtime/internal/renderer.ts b/src/runtime/internal/renderer.ts deleted file mode 100644 index 356eaffbe1..0000000000 --- a/src/runtime/internal/renderer.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { - H3Event, - eventHandler, - getResponseStatus, - send, - setResponseHeader, - setResponseHeaders, - setResponseStatus, -} from "h3"; -import type { RenderHandler, RenderContext } from "nitropack/types"; -import { useNitroApp } from "./app"; -import { useRuntimeConfig } from "./config"; - -export function defineRenderHandler(render: RenderHandler) { - const runtimeConfig = useRuntimeConfig(); - return eventHandler(async (event) => { - const nitroApp = useNitroApp(); - - // Create shared context for hooks - const ctx: RenderContext = { event, render, response: undefined }; - - // Call initial hook to prepare and optionally custom render - await nitroApp.hooks.callHook("render:before", ctx); - - if (!ctx.response /* not handled by hook */) { - // TODO: Use serve-placeholder - if (event.path === `${runtimeConfig.app.baseURL}favicon.ico`) { - setResponseHeader(event, "Content-Type", "image/x-icon"); - return send( - event, - "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" - ); - } - - ctx.response = await ctx.render(event); - - if (!ctx.response) { - const _currentStatus = getResponseStatus(event); - setResponseStatus(event, _currentStatus === 200 ? 500 : _currentStatus); - return send( - event, - "No response returned from render handler: " + event.path - ); - } - } - - // Allow modifying response - await nitroApp.hooks.callHook("render:response", ctx.response, ctx); - - // Send headers - if (ctx.response.headers) { - setResponseHeaders(event, ctx.response.headers); - } - if (ctx.response.statusCode || ctx.response.statusMessage) { - setResponseStatus( - event, - ctx.response.statusCode, - ctx.response.statusMessage - ); - } - - // Send response body - return ctx.response.body; - }); -} diff --git a/src/runtime/internal/route-rules.ts b/src/runtime/internal/route-rules.ts index 4e392ad269..1100bc50a6 100644 --- a/src/runtime/internal/route-rules.ts +++ b/src/runtime/internal/route-rules.ts @@ -1,91 +1,91 @@ -import defu from "defu"; -import { - type H3Event, - eventHandler, - proxyRequest, - sendRedirect, - setHeaders, -} from "h3"; -import type { NitroRouteRules } from "nitropack/types"; -import { createRouter as createRadixRouter, toRouteMatcher } from "radix3"; -import { getQuery, joinURL, withQuery, withoutBase } from "ufo"; -import { useRuntimeConfig } from "./config"; +import { proxyRequest, redirect as sendRedirect, requireBasicAuth } from "h3"; +import type { BasicAuthOptions, EventHandler, Middleware } from "h3"; +import type { MatchedRouteRule, NitroRouteRules } from "nitro/types"; +import { joinURL, withQuery, withoutBase } from "ufo"; +import { defineCachedHandler } from "./cache.ts"; -const config = useRuntimeConfig(); -const _routeRulesMatcher = toRouteMatcher( - createRadixRouter({ routes: config.nitro.routeRules }) -); +// Note: Remember to update RuntimeRouteRules in src/build/virtual/routing.ts when adding new route rules -export function createRouteRulesHandler(ctx: { - localFetch: typeof globalThis.fetch; -}) { - return eventHandler((event) => { - // Match route options against path - const routeRules = getRouteRules(event); - // Apply headers options - if (routeRules.headers) { - setHeaders(event, routeRules.headers); +type RouteRuleCtor = (m: MatchedRouteRule) => Middleware; + +// Headers route rule +export const headers: RouteRuleCtor<"headers"> = ((m) => + function headersRouteRule(event) { + for (const [key, value] of Object.entries(m.options || {})) { + event.res.headers.set(key, value); } - // Apply redirect options - if (routeRules.redirect) { - let target = routeRules.redirect.to; - if (target.endsWith("/**")) { - let targetPath = event.path; - const strpBase = (routeRules.redirect as any)._redirectStripBase; - if (strpBase) { - targetPath = withoutBase(targetPath, strpBase); - } - target = joinURL(target.slice(0, -3), targetPath); - } else if (event.path.includes("?")) { - const query = getQuery(event.path); - target = withQuery(target, query); - } - return sendRedirect(event, target, routeRules.redirect.statusCode); + }) satisfies RouteRuleCtor<"headers">; + +// Redirect route rule +export const redirect: RouteRuleCtor<"redirect"> = ((m) => + function redirectRouteRule(event) { + let target = m.options?.to; + if (!target) { + return; } - // Apply proxy options - if (routeRules.proxy) { - let target = routeRules.proxy.to; - if (target.endsWith("/**")) { - let targetPath = event.path; - const strpBase = (routeRules.proxy as any)._proxyStripBase; - if (strpBase) { - targetPath = withoutBase(targetPath, strpBase); - } - target = joinURL(target.slice(0, -3), targetPath); - } else if (event.path.includes("?")) { - const query = getQuery(event.path); - target = withQuery(target, query); + if (target.endsWith("/**")) { + let targetPath = event.url.pathname + event.url.search; + const strpBase = (m.options as any)._redirectStripBase; + if (strpBase) { + targetPath = withoutBase(targetPath, strpBase); } - return proxyRequest(event, target, { - fetch: ctx.localFetch, - ...routeRules.proxy, - }); + target = joinURL(target.slice(0, -3), targetPath); + } else if (event.url.search) { + target = withQuery(target, Object.fromEntries(event.url.searchParams)); } - }); -} + return sendRedirect(target, m.options?.status); + }) satisfies RouteRuleCtor<"redirect">; -export function getRouteRules(event: H3Event): NitroRouteRules { - event.context._nitro = event.context._nitro || {}; - if (!event.context._nitro.routeRules) { - event.context._nitro.routeRules = getRouteRulesForPath( - withoutBase(event.path.split("?")[0], useRuntimeConfig().app.baseURL) - ); - } - return event.context._nitro.routeRules; -} +// Proxy route rule +export const proxy: RouteRuleCtor<"proxy"> = ((m) => + function proxyRouteRule(event) { + let target = m.options?.to; + if (!target) { + return; + } + if (target.endsWith("/**")) { + let targetPath = event.url.pathname + event.url.search; + const strpBase = (m.options as any)._proxyStripBase; + if (strpBase) { + targetPath = withoutBase(targetPath, strpBase); + } + target = joinURL(target.slice(0, -3), targetPath); + } else if (event.url.search) { + target = withQuery(target, Object.fromEntries(event.url.searchParams)); + } + return proxyRequest(event, target, { + ...m.options, + }); + }) satisfies RouteRuleCtor<"proxy">; -// prettier-ignore -type DeepReadonly = T extends Record - ? { readonly [K in keyof T]: DeepReadonly } - : T extends Array - ? ReadonlyArray> - : T; +// Cache route rule +export const cache: RouteRuleCtor<"cache"> = ((m) => + function cacheRouteRule(event, next) { + if (!event.context.matchedRoute) { + return next(); + } + const cachedHandlers: Map = ((globalThis as any).__nitroCachedHandlers ??= + new Map()); + const { handler, route } = event.context.matchedRoute; + const key = `${m.route}:${route}`; + let cachedHandler = cachedHandlers.get(key); + if (!cachedHandler) { + cachedHandler = defineCachedHandler(handler, { + group: "nitro/route-rules", + name: key, + ...m.options, + }); + cachedHandlers.set(key, cachedHandler); + } + return cachedHandler(event); + }) satisfies RouteRuleCtor<"cache">; -/** - * @param path - The path to match against route rules. This should not contain a query string. - */ -export function getRouteRulesForPath( - path: string -): DeepReadonly { - return defu({}, ..._routeRulesMatcher.matchAll(path).reverse()); -} +// basicAuth auth route rule +export const basicAuth: RouteRuleCtor<"auth"> = ((m) => + async function authRouteRule(event, next) { + if (!m.options) { + return; + } + await requireBasicAuth(event, m.options as BasicAuthOptions); + return next(); + }) satisfies RouteRuleCtor<"auth">; diff --git a/src/runtime/internal/routes/dev-tasks.ts b/src/runtime/internal/routes/dev-tasks.ts new file mode 100644 index 0000000000..da55b16037 --- /dev/null +++ b/src/runtime/internal/routes/dev-tasks.ts @@ -0,0 +1,32 @@ +import { H3 } from "h3"; +import { runTask } from "../task.ts"; + +import { scheduledTasks, tasks } from "#nitro/virtual/tasks"; + +const app: H3 = new H3() + .get("/_nitro/tasks", async () => { + const _tasks = await Promise.all( + Object.entries(tasks).map(async ([name, task]) => { + const _task = await task.resolve?.(); + return [name, { description: _task?.meta?.description }]; + }) + ); + return { + tasks: Object.fromEntries(_tasks), + scheduledTasks, + }; + }) + .get("/_nitro/tasks/:name", async (event) => { + const name = event.context.params?.name; + const body = (await event.req.json().catch(() => ({}))) as Record; + const payload = { + ...Object.fromEntries(event.url.searchParams.entries()), + ...body, + }; + return await runTask(name!, { + context: { waitUntil: event.req.waitUntil }, + payload, + }); + }); + +export default app; diff --git a/src/runtime/internal/routes/openapi.ts b/src/runtime/internal/routes/openapi.ts index 6d5890ae5a..a12edac806 100644 --- a/src/runtime/internal/routes/openapi.ts +++ b/src/runtime/internal/routes/openapi.ts @@ -1,20 +1,21 @@ -import { type HTTPMethod, eventHandler, getRequestURL } from "h3"; +import { defineHandler, getRequestURL } from "h3"; +import type { EventHandler, HTTPMethod } from "h3"; import type { - ComponentsObject, + Extensable, OpenAPI3, OperationObject, ParameterObject, PathItemObject, PathsObject, -} from "openapi-typescript"; +} from "../../../types/openapi-ts.ts"; import { joinURL } from "ufo"; import { defu } from "defu"; -import { handlersMeta } from "#nitro-internal-virtual/server-handlers-meta"; -import { useRuntimeConfig } from "../config"; +import { handlersMeta } from "#nitro/virtual/routing-meta"; +import { useRuntimeConfig } from "../runtime-config.ts"; // Served as /_openapi.json -export default eventHandler((event) => { - const runtimeConfig = useRuntimeConfig(event); +export default defineHandler((event) => { + const runtimeConfig = useRuntimeConfig(); const base = runtimeConfig.app?.baseURL; const url = joinURL(getRequestURL(event).origin, base); @@ -24,13 +25,20 @@ export default eventHandler((event) => { ...runtimeConfig.nitro?.openAPI?.meta, }; - const { paths, globals } = getHandlersMeta(); + const { + paths, + globals: { components, ...globalsRest }, + } = getHandlersMeta(); + + const extensible: Extensable = Object.fromEntries( + Object.entries(globalsRest).filter(([key]) => key.startsWith("x-")) + ); - return { + return { openapi: "3.1.0", info: { title: meta?.title, - version: meta?.version, + version: meta?.version || "1.0.0", description: meta?.description, }, servers: [ @@ -41,11 +49,12 @@ export default eventHandler((event) => { }, ], paths, - components: globals.components, - }; -}); + components, + ...extensible, + } satisfies OpenAPI3; +}) as EventHandler; -type OpenAPIGlobals = Pick; +type OpenAPIGlobals = Pick & Extensable; function getHandlersMeta(): { paths: PathsObject; @@ -61,14 +70,14 @@ function getHandlersMeta(): { const { $global, ...openAPI } = h.meta?.openAPI || {}; const item: PathItemObject = { - [method]: { + [method]: { tags, parameters, responses: { 200: { description: "OK" }, }, ...openAPI, - }, + } satisfies OperationObject, }; if ($global) { diff --git a/src/runtime/internal/routes/renderer-template.dev.ts b/src/runtime/internal/routes/renderer-template.dev.ts new file mode 100644 index 0000000000..a83109234d --- /dev/null +++ b/src/runtime/internal/routes/renderer-template.dev.ts @@ -0,0 +1,30 @@ +import type { H3Event } from "h3"; +import { serverFetch } from "../app.ts"; +import { + rendererTemplate, + rendererTemplateFile, + isStaticTemplate, +} from "#nitro/virtual/renderer-template"; +import { HTTPResponse } from "h3"; +import { hasTemplateSyntax, renderToResponse, compileTemplate } from "rendu"; + +export default async function renderIndexHTML(event: H3Event): Promise { + let html = await rendererTemplate(event.req as Request); + + if ((globalThis as any).__transform_html__) { + html = await (globalThis as any).__transform_html__(html); + } + + const isStatic = isStaticTemplate ?? !hasTemplateSyntax(html); + if (isStatic) { + return new HTTPResponse(html, { + headers: { "content-type": "text/html; charset=utf-8" }, + }); + } + + const template = compileTemplate(html, { filename: rendererTemplateFile }); + return renderToResponse(template, { + request: event.req as Request, + context: { serverFetch }, + }); +} diff --git a/src/runtime/internal/routes/renderer-template.ts b/src/runtime/internal/routes/renderer-template.ts new file mode 100644 index 0000000000..c0d69e5f5d --- /dev/null +++ b/src/runtime/internal/routes/renderer-template.ts @@ -0,0 +1,6 @@ +import type { H3Event } from "h3"; +import { rendererTemplate } from "#nitro/virtual/renderer-template"; + +export default function renderIndexHTML(event: H3Event): any { + return rendererTemplate(event.req as Request); +} diff --git a/src/runtime/internal/routes/scalar.ts b/src/runtime/internal/routes/scalar.ts index 5aeba9eefe..54b96015a0 100644 --- a/src/runtime/internal/routes/scalar.ts +++ b/src/runtime/internal/routes/scalar.ts @@ -1,25 +1,26 @@ -import type { ReferenceConfiguration } from "@scalar/api-reference"; -import { eventHandler } from "h3"; -import { useRuntimeConfig } from "../config"; +import type { ApiReferenceConfiguration } from "@scalar/api-reference"; +import { defineHandler, type EventHandler } from "h3"; +import { useRuntimeConfig } from "../runtime-config.ts"; // Served as /_scalar -export default eventHandler((event) => { - const runtimeConfig = useRuntimeConfig(event); - const title = runtimeConfig.nitro.openAPI?.meta?.title || "API Reference"; - const description = runtimeConfig.nitro.openAPI?.meta?.description || ""; - const openAPIEndpoint = - runtimeConfig.nitro.openAPI?.route || "./_openapi.json"; +export default defineHandler((event) => { + const runtimeConfig = useRuntimeConfig(); + const title = runtimeConfig.nitro?.openAPI?.meta?.title || "API Reference"; + const description = runtimeConfig.nitro?.openAPI?.meta?.description || ""; + const openAPIEndpoint = runtimeConfig.nitro?.openAPI?.route || "./_openapi.json"; // https://github.com/scalar/scalar - const _config = runtimeConfig.nitro.openAPI?.ui - ?.scalar as ReferenceConfiguration; - const scalarConfig: ReferenceConfiguration = { + const _config = runtimeConfig.nitro?.openAPI?.ui?.scalar as ApiReferenceConfiguration; + const scalarConfig: ApiReferenceConfiguration = { ..._config, + url: openAPIEndpoint, + // @ts-expect-error spec: { url: openAPIEndpoint, ..._config?.spec }, }; // The default page title + event.res.headers.set("Content-Type", "text/html"); return /* html */ ` @@ -34,14 +35,12 @@ export default eventHandler((event) => { `; -}); +}) as EventHandler; const customTheme = /* css */ `/* basic theme */ .light-mode, diff --git a/src/runtime/internal/routes/swagger.ts b/src/runtime/internal/routes/swagger.ts index c7b69f9762..6174ea0c05 100644 --- a/src/runtime/internal/routes/swagger.ts +++ b/src/runtime/internal/routes/swagger.ts @@ -1,17 +1,17 @@ -import type { ReferenceConfiguration } from "@scalar/api-reference"; -import { eventHandler } from "h3"; -import { useRuntimeConfig } from "../config"; +import { defineHandler } from "h3"; +import type { EventHandler } from "h3"; +import { useRuntimeConfig } from "../runtime-config.ts"; // https://github.com/swagger-api/swagger-ui -export default eventHandler((event) => { - const runtimeConfig = useRuntimeConfig(event); - const title = runtimeConfig.nitro.openAPI?.meta?.title || "API Reference"; - const description = runtimeConfig.nitro.openAPI?.meta?.description || ""; - const openAPIEndpoint = - runtimeConfig.nitro.openAPI?.route || "./_openapi.json"; +export default defineHandler((event) => { + const runtimeConfig = useRuntimeConfig(); + const title = runtimeConfig.nitro?.openAPI?.meta?.title || "API Reference"; + const description = runtimeConfig.nitro?.openAPI?.meta?.description || ""; + const openAPIEndpoint = runtimeConfig.nitro?.openAPI?.route || "./_openapi.json"; const CDN_BASE = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@^5"; + event.res.headers.set("Content-Type", "text/html"); return /* html */ ` @@ -43,4 +43,4 @@ export default eventHandler((event) => { `; -}); +}) as EventHandler; diff --git a/src/runtime/internal/utils.env.ts b/src/runtime/internal/runtime-config.ts similarity index 61% rename from src/runtime/internal/utils.env.ts rename to src/runtime/internal/runtime-config.ts index 5af08885ae..53e342e65b 100644 --- a/src/runtime/internal/utils.env.ts +++ b/src/runtime/internal/runtime-config.ts @@ -1,28 +1,34 @@ -import destr from "destr"; +import type { NitroRuntimeConfig } from "nitro/types"; import { snakeCase } from "scule"; +import { runtimeConfig } from "#nitro/virtual/runtime-config"; -export type EnvOptions = { +export function useRuntimeConfig(): NitroRuntimeConfig { + return ((useRuntimeConfig as any)._cached ||= getRuntimeConfig()); +} + +function getRuntimeConfig() { + const env = globalThis.process?.env || {}; + applyEnv(runtimeConfig, { + prefix: "NITRO_", + altPrefix: runtimeConfig.nitro?.envPrefix ?? env?.NITRO_ENV_PREFIX ?? "_", + envExpansion: Boolean(runtimeConfig.nitro?.envExpansion ?? env?.NITRO_ENV_EXPANSION ?? false), + }); + return runtimeConfig; +} + +// ---- utils ---- + +type EnvOptions = { prefix?: string; altPrefix?: string; envExpansion?: boolean; }; -export function getEnv(key: string, opts: EnvOptions) { - const envKey = snakeCase(key).toUpperCase(); - return destr( - process.env[opts.prefix + envKey] ?? process.env[opts.altPrefix + envKey] - ); -} - -function _isObject(input: unknown) { - return typeof input === "object" && !Array.isArray(input); -} - export function applyEnv( obj: Record, opts: EnvOptions, parentKey = "" -) { +): Record { for (const key in obj) { const subKey = parentKey ? `${parentKey}_${key}` : key; const envValue = getEnv(subKey, opts); @@ -60,3 +66,12 @@ function _expandFromEnv(value: string) { return process.env[key] || match; }); } + +function getEnv(key: string, opts: EnvOptions) { + const envKey = snakeCase(key).toUpperCase(); + return process.env[opts.prefix + envKey] ?? process.env[opts.altPrefix + envKey]; +} + +function _isObject(input: unknown) { + return input !== null && typeof input === "object" && !Array.isArray(input); +} diff --git a/src/runtime/internal/shutdown.ts b/src/runtime/internal/shutdown.ts deleted file mode 100644 index 91411a93f9..0000000000 --- a/src/runtime/internal/shutdown.ts +++ /dev/null @@ -1,48 +0,0 @@ -import type { Server as HttpServer } from "node:http"; -import type { NitroApp } from "nitropack/types"; -import gracefulShutdown from "./lib/http-graceful-shutdown"; - -export function getGracefulShutdownConfig() { - return { - disabled: !!process.env.NITRO_SHUTDOWN_DISABLED, - signals: (process.env.NITRO_SHUTDOWN_SIGNALS || "SIGTERM SIGINT") - .split(" ") - .map((s) => s.trim()), - timeout: - Number.parseInt(process.env.NITRO_SHUTDOWN_TIMEOUT || "", 10) || 30_000, - forceExit: !process.env.NITRO_SHUTDOWN_NO_FORCE_EXIT, - }; -} - -export function setupGracefulShutdown( - listener: HttpServer, - nitroApp: NitroApp -) { - const shutdownConfig = getGracefulShutdownConfig(); - if (shutdownConfig.disabled) { - return; - } - // https://github.com/sebhildebrandt/http-graceful-shutdown - gracefulShutdown(listener, { - signals: shutdownConfig.signals.join(" "), - timeout: shutdownConfig.timeout, - forceExit: shutdownConfig.forceExit, - onShutdown: async () => { - await new Promise((resolve) => { - const timeout = setTimeout(() => { - console.warn("Graceful shutdown timeout, force exiting..."); - resolve(); - }, shutdownConfig.timeout); - nitroApp.hooks - .callHook("close") - .catch((error) => { - console.error(error); - }) - .finally(() => { - clearTimeout(timeout); - resolve(); - }); - }); - }, - }); -} diff --git a/src/runtime/internal/static.ts b/src/runtime/internal/static.ts index 95c0599230..44ff2e1875 100644 --- a/src/runtime/internal/static.ts +++ b/src/runtime/internal/static.ts @@ -1,46 +1,23 @@ -import { - type HTTPMethod, - createError, - eventHandler, - getRequestHeader, - getResponseHeader, - removeResponseHeader, - setResponseHeader, - appendResponseHeader, - setResponseStatus, -} from "h3"; -import type { PublicAsset } from "nitropack/types"; -import { - decodePath, - joinURL, - parseURL, - withLeadingSlash, - withoutTrailingSlash, -} from "ufo"; -import { - getAsset, - isPublicAssetURL, - readAsset, -} from "#nitro-internal-virtual/public-assets"; +import { HTTPError, defineHandler } from "h3"; +import type { EventHandler, HTTPMethod } from "h3"; +import type { PublicAsset } from "nitro/types"; +import { decodePath, joinURL, withLeadingSlash, withoutTrailingSlash } from "ufo"; +import { getAsset, isPublicAssetURL, readAsset } from "#nitro/virtual/public-assets"; const METHODS = new Set(["HEAD", "GET"] as HTTPMethod[]); -const EncodingMap = { gzip: ".gz", br: ".br" } as const; +const EncodingMap = { gzip: ".gz", br: ".br", zstd: ".zst" } as const; -export default eventHandler((event) => { - if (event.method && !METHODS.has(event.method)) { +export default defineHandler((event) => { + if (event.req.method && !METHODS.has(event.req.method as HTTPMethod)) { return; } - let id = decodePath( - withLeadingSlash(withoutTrailingSlash(parseURL(event.path).pathname)) - ); + let id = decodePath(withLeadingSlash(withoutTrailingSlash(event.url.pathname))); let asset: PublicAsset | undefined; - const encodingHeader = String( - getRequestHeader(event, "accept-encoding") || "" - ); + const encodingHeader = event.req.headers.get("accept-encoding") || ""; const encodings = [ ...encodingHeader .split(",") @@ -49,9 +26,6 @@ export default eventHandler((event) => { .sort(), "", ]; - if (encodings.length > 1) { - appendResponseHeader(event, "Vary", "Accept-Encoding"); - } for (const encoding of encodings) { for (const _id of [id + encoding, joinURL(id, "index.html" + encoding)]) { @@ -66,51 +40,50 @@ export default eventHandler((event) => { if (!asset) { if (isPublicAssetURL(id)) { - removeResponseHeader(event, "Cache-Control"); - throw createError({ - statusMessage: "Cannot find static asset " + id, - statusCode: 404, - }); + event.res.headers.delete("Cache-Control"); + throw new HTTPError({ status: 404 }); } return; } - const ifNotMatch = getRequestHeader(event, "if-none-match") === asset.etag; + if (encodings.length > 1) { + event.res.headers.append("Vary", "Accept-Encoding"); + } + + const ifNotMatch = event.req.headers.get("if-none-match") === asset.etag; if (ifNotMatch) { - setResponseStatus(event, 304, "Not Modified"); + event.res.status = 304; + event.res.statusText = "Not Modified"; return ""; } - const ifModifiedSinceH = getRequestHeader(event, "if-modified-since"); + const ifModifiedSinceH = event.req.headers.get("if-modified-since"); const mtimeDate = new Date(asset.mtime); - if ( - ifModifiedSinceH && - asset.mtime && - new Date(ifModifiedSinceH) >= mtimeDate - ) { - setResponseStatus(event, 304, "Not Modified"); + if (ifModifiedSinceH && asset.mtime && new Date(ifModifiedSinceH) >= mtimeDate) { + event.res.status = 304; + event.res.statusText = "Not Modified"; return ""; } - if (asset.type && !getResponseHeader(event, "Content-Type")) { - setResponseHeader(event, "Content-Type", asset.type); + if (asset.type) { + event.res.headers.set("Content-Type", asset.type); } - if (asset.etag && !getResponseHeader(event, "ETag")) { - setResponseHeader(event, "ETag", asset.etag); + if (asset.etag && !event.res.headers.has("ETag")) { + event.res.headers.set("ETag", asset.etag); } - if (asset.mtime && !getResponseHeader(event, "Last-Modified")) { - setResponseHeader(event, "Last-Modified", mtimeDate.toUTCString()); + if (asset.mtime && !event.res.headers.has("Last-Modified")) { + event.res.headers.set("Last-Modified", mtimeDate.toUTCString()); } - if (asset.encoding && !getResponseHeader(event, "Content-Encoding")) { - setResponseHeader(event, "Content-Encoding", asset.encoding); + if (asset.encoding && !event.res.headers.has("Content-Encoding")) { + event.res.headers.set("Content-Encoding", asset.encoding); } - if (asset.size > 0 && !getResponseHeader(event, "Content-Length")) { - setResponseHeader(event, "Content-Length", asset.size); + if (asset.size > 0 && !event.res.headers.has("Content-Length")) { + event.res.headers.set("Content-Length", asset.size.toString()); } return readAsset(id); -}); +}) as EventHandler; diff --git a/src/runtime/internal/storage.ts b/src/runtime/internal/storage.ts index 66dee2faa6..1dc05e544a 100644 --- a/src/runtime/internal/storage.ts +++ b/src/runtime/internal/storage.ts @@ -1,11 +1,8 @@ import type { Storage, StorageValue } from "unstorage"; import { prefixStorage } from "unstorage"; -import { storage } from "#nitro-internal-virtual/storage"; +import { initStorage } from "#nitro/virtual/storage"; -export function useStorage( - base = "" -): Storage { - return (base - ? prefixStorage(storage, base) - : storage) as unknown as Storage; +export function useStorage(base = ""): Storage { + const storage = ((useStorage as any)._storage ??= initStorage()); + return (base ? prefixStorage(storage, base) : storage) as unknown as Storage; } diff --git a/src/runtime/internal/task.ts b/src/runtime/internal/task.ts index 8f4af70bb1..f119cefd3d 100644 --- a/src/runtime/internal/task.ts +++ b/src/runtime/internal/task.ts @@ -1,14 +1,7 @@ import { Cron } from "croner"; -import { createError } from "h3"; -import type { - Task, - TaskContext, - TaskEvent, - TaskPayload, - TaskResult, -} from "nitropack/types"; -import { isTest } from "std-env"; -import { scheduledTasks, tasks } from "#nitro-internal-virtual/tasks"; +import { HTTPError } from "h3"; +import type { Task, TaskContext, TaskEvent, TaskPayload, TaskResult } from "nitro/types"; +import { scheduledTasks, tasks } from "#nitro/virtual/tasks"; /** @experimental */ export function defineTask(def: Task): Task { @@ -25,26 +18,23 @@ const __runningTasks__: { [name: string]: ReturnType["run"]> } = {}; /** @experimental */ export async function runTask( name: string, - { - payload = {}, - context = {}, - }: { payload?: TaskPayload; context?: TaskContext } = {} + { payload = {}, context = {} }: { payload?: TaskPayload; context?: TaskContext } = {} ): Promise> { if (__runningTasks__[name]) { return __runningTasks__[name]; } if (!(name in tasks)) { - throw createError({ + throw new HTTPError({ message: `Task \`${name}\` is not available!`, - statusCode: 404, + status: 404, }); } if (!tasks[name].resolve) { - throw createError({ + throw new HTTPError({ message: `Task \`${name}\` is not implemented!`, - statusCode: 501, + status: 501, }); } @@ -61,8 +51,12 @@ export async function runTask( } /** @experimental */ -export function startScheduleRunner() { - if (!scheduledTasks || scheduledTasks.length === 0 || isTest) { +export function startScheduleRunner({ + waitUntil, +}: { + waitUntil?: ((promise: Promise) => void) | undefined; +} = {}): void { + if (!scheduledTasks || scheduledTasks.length === 0 || process.env.TEST) { return; } @@ -71,17 +65,14 @@ export function startScheduleRunner() { }; for (const schedule of scheduledTasks) { - const cron = new Cron(schedule.cron, async () => { + new Cron(schedule.cron, async () => { await Promise.all( schedule.tasks.map((name) => runTask(name, { payload, - context: {}, + context: { waitUntil }, }).catch((error) => { - console.error( - `Error while running scheduled task "${name}"`, - error - ); + console.error(`Error while running scheduled task "${name}"`, error); }) ) ); diff --git a/src/runtime/internal/timing.ts b/src/runtime/internal/timing.ts deleted file mode 100644 index 65ec188eeb..0000000000 --- a/src/runtime/internal/timing.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { eventHandler } from "h3"; - -import { defineNitroPlugin } from "./plugin"; - -const globalTiming = (globalThis as any).__timing__ || { - start: () => 0, - end: () => 0, - metrics: [], -}; - -// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Server-Timing -const timingMiddleware = eventHandler((event) => { - const start = globalTiming.start(); - - const _end = event.node.res.end; - // @ts-expect-error - event.node.res.end = function ( - chunk: any, - encoding: BufferEncoding, - cb?: () => void - ) { - const metrics = [ - ["Generate", globalTiming.end(start)], - ...globalTiming.metrics, - ]; - const serverTiming = metrics - .map((m) => `-;dur=${m[1]};desc="${encodeURIComponent(m[0])}"`) - .join(", "); - if (!event.node.res.headersSent) { - event.node.res.setHeader("Server-Timing", serverTiming); - } - _end.call(event.node.res, chunk, encoding, cb); - // @ts-expect-error - return this; - }.bind(event.node.res); -}); - -export default defineNitroPlugin((nitro) => { - // Always add timing middleware to the beginning of handler stack - nitro.h3App.stack.unshift({ - route: "/", - handler: timingMiddleware, - }); -}); diff --git a/src/runtime/internal/utils.lambda.ts b/src/runtime/internal/utils.lambda.ts deleted file mode 100644 index 114473a1a1..0000000000 --- a/src/runtime/internal/utils.lambda.ts +++ /dev/null @@ -1,62 +0,0 @@ -import type { Readable } from "node:stream"; -import type { APIGatewayProxyEventHeaders } from "aws-lambda"; -import { toBuffer } from "./utils"; - -export function normalizeLambdaIncomingHeaders( - headers?: APIGatewayProxyEventHeaders -): Record { - return Object.fromEntries( - Object.entries(headers || {}).map(([key, value]) => [ - key.toLowerCase(), - value, - ]) - ); -} - -export function normalizeLambdaOutgoingHeaders( - headers: Record, - stripCookies = false -) { - const entries = stripCookies - ? Object.entries(headers).filter(([key]) => !["set-cookie"].includes(key)) - : Object.entries(headers); - - return Object.fromEntries( - entries.map(([k, v]) => [k, Array.isArray(v) ? v.join(",") : String(v)]) - ); -} - -// AWS Lambda proxy integrations requires base64 encoded buffers -// binaryMediaTypes should be */* -// see https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-payload-encodings.html -export async function normalizeLambdaOutgoingBody( - body: - | BodyInit - | ReadableStream - | Buffer - | Readable - | Uint8Array - | null - | undefined, - headers: Record -): Promise<{ type: "text" | "binary"; body: string }> { - if (typeof body === "string") { - return { type: "text", body }; - } - if (!body) { - return { type: "text", body: "" }; - } - const buffer = await toBuffer(body as any); - const contentType = (headers["content-type"] as string) || ""; - return isTextType(contentType) - ? { type: "text", body: buffer.toString("utf8") } - : { type: "binary", body: buffer.toString("base64") }; -} - -// -- Internal -- - -const TEXT_TYPE_RE = /^text\/|\/(javascript|json|xml)|utf-?8/; - -function isTextType(contentType = "") { - return TEXT_TYPE_RE.test(contentType); -} diff --git a/src/runtime/internal/utils.ts b/src/runtime/internal/utils.ts deleted file mode 100644 index 247dcd47ee..0000000000 --- a/src/runtime/internal/utils.ts +++ /dev/null @@ -1,119 +0,0 @@ -import type { Readable } from "node:stream"; -import type { H3Event } from "h3"; -import { getRequestHeader, splitCookiesString } from "h3"; -import { useNitroApp } from "./app"; - -const METHOD_WITH_BODY_RE = /post|put|patch/i; -const TEXT_MIME_RE = /application\/text|text\/html/; -const JSON_MIME_RE = /application\/json/; - -export function requestHasBody(request: globalThis.Request): boolean { - return METHOD_WITH_BODY_RE.test(request.method); -} - -export async function useRequestBody( - request: globalThis.Request -): Promise { - const contentType = request.headers.get("content-type") || ""; - if (contentType.includes("form")) { - const formData = await request.formData(); - const body = Object.create(null); - for (const entry of formData.entries()) { - body[entry[0]] = entry[1]; - } - return body; - } - if (JSON_MIME_RE.test(contentType)) { - return request.json(); - } - if (TEXT_MIME_RE.test(contentType)) { - return request.text(); - } - const blob = await request.blob(); - return URL.createObjectURL(blob); -} - -function _captureError(error: Error, type: string) { - console.error(`[${type}]`, error); - useNitroApp().captureError(error, { tags: [type] }); -} - -export function trapUnhandledNodeErrors() { - process.on("unhandledRejection", (error: Error) => - _captureError(error, "unhandledRejection") - ); - process.on("uncaughtException", (error: Error) => - _captureError(error, "uncaughtException") - ); -} - -export function joinHeaders(value: number | string | string[]) { - return Array.isArray(value) ? value.join(", ") : String(value); -} - -export function normalizeFetchResponse(response: Response) { - if (!response.headers.has("set-cookie")) { - return response; - } - return new Response(response.body, { - status: response.status, - statusText: response.statusText, - headers: normalizeCookieHeaders(response.headers), - }); -} - -export function normalizeCookieHeader(header: number | string | string[] = "") { - return splitCookiesString(joinHeaders(header)); -} - -export function normalizeCookieHeaders(headers: Headers) { - const outgoingHeaders = new Headers(); - for (const [name, header] of headers) { - if (name === "set-cookie") { - for (const cookie of normalizeCookieHeader(header)) { - outgoingHeaders.append("set-cookie", cookie); - } - } else { - outgoingHeaders.set(name, joinHeaders(header)); - } - } - return outgoingHeaders; -} - -export function toBuffer(data: ReadableStream | Readable | Uint8Array) { - if ("pipeTo" in data && typeof data.pipeTo === "function") { - return new Promise((resolve, reject) => { - const chunks: Buffer[] = []; - data - .pipeTo( - new WritableStream({ - write(chunk) { - chunks.push(chunk); - }, - close() { - resolve(Buffer.concat(chunks)); - }, - abort(reason) { - reject(reason); - }, - }) - ) - .catch(reject); - }); - } - if ("pipe" in data && typeof data.pipe === "function") { - return new Promise((resolve, reject) => { - const chunks: Buffer[] = []; - data - .on("data", (chunk: any) => { - chunks.push(chunk); - }) - .on("end", () => { - resolve(Buffer.concat(chunks)); - }) - .on("error", reject); - }); - } - // @ts-ignore - return Buffer.from(data as unknown as Uint16Array); -} diff --git a/src/runtime/internal/vite/dev-entry.mjs b/src/runtime/internal/vite/dev-entry.mjs new file mode 100644 index 0000000000..cb1176ee09 --- /dev/null +++ b/src/runtime/internal/vite/dev-entry.mjs @@ -0,0 +1,18 @@ +import "#nitro/virtual/polyfills"; +import wsAdapter from "crossws/adapters/node"; + +import { useNitroApp } from "nitro/app"; +import { resolveWebsocketHooks } from "#nitro/runtime/app"; +import { startScheduleRunner } from "#nitro/runtime/task"; + +const nitroApp = useNitroApp(); + +export const fetch = nitroApp.fetch; + +const ws = import.meta._websocket ? wsAdapter({ resolve: resolveWebsocketHooks }) : undefined; + +if (import.meta._tasks) { + startScheduleRunner({}); +} + +export const handleUpgrade = ws?.handleUpgrade; diff --git a/src/runtime/internal/vite/dev-worker.mjs b/src/runtime/internal/vite/dev-worker.mjs new file mode 100644 index 0000000000..0cf82a1736 --- /dev/null +++ b/src/runtime/internal/vite/dev-worker.mjs @@ -0,0 +1,264 @@ +import { ModuleRunner, ESModulesEvaluator } from "vite/module-runner"; +import { createViteTransport } from "env-runner/vite"; + +// Custom evaluator for workerd where `new AsyncFunction()` is disallowed. +// Uses the unsafeEvalBinding exposed by the env-runner miniflare wrapper. +class WorkerdModuleEvaluator { + startOffset = 0; + + async runInlinedModule(context, code) { + const unsafeEval = globalThis.__ENV_RUNNER_UNSAFE_EVAL__; + const keys = Object.keys(context); + const fn = unsafeEval.newAsyncFunction('"use strict";' + code, "runInlinedModule", ...keys); + await fn(...keys.map((k) => context[k])); + Object.seal(context[Object.keys(context)[0]]); + } + + runExternalModule(filepath) { + return import(filepath); + } +} + +// ----- IPC ----- + +let sendMessage; +const messageListeners = new Set(); + +// ----- Environment runners ----- + +const envs = (globalThis.__nitro_vite_envs__ ??= { + nitro: undefined, + ssr: undefined, +}); + +class ViteEnvRunner { + constructor({ name, entry }) { + this.name = name; + this.entryPath = entry; + + this.entry = undefined; + this.entryError = undefined; + + // Create Vite Module Runner + // https://vite.dev/guide/api-environment-runtimes.html#modulerunner + const onMessage = (listener) => messageListeners.add(listener); + const transport = createViteTransport((data) => sendMessage?.(data), onMessage, name); + const evaluator = globalThis.__ENV_RUNNER_UNSAFE_EVAL__ + ? new WorkerdModuleEvaluator() + : new ESModulesEvaluator(); + const debug = + typeof process !== "undefined" && process.env?.NITRO_DEBUG ? console.debug : undefined; + this.runner = new ModuleRunner({ transport }, evaluator, debug); + + this.reload(); + } + + async reload() { + try { + this.entry = await this.runner.import(this.entryPath); + this.entryError = undefined; + } catch (error) { + console.error(error); + this.entryError = error; + } + } + + async fetch(req, init) { + if (this.entryError) { + return renderError(req, this.entryError); + } + for (let i = 0; i < 5 && !(this.entry || this.entryError); i++) { + await new Promise((r) => setTimeout(r, 100 * Math.pow(2, i))); + } + if (this.entryError) { + return renderError(req, this.entryError); + } + if (!this.entry) { + throw httpError(503, `Vite environment "${this.name}" is unavailable`); + } + try { + const entryFetch = this.entry.fetch || this.entry.default?.fetch; + if (!entryFetch) { + throw httpError(500, `No fetch handler exported from ${this.entryPath}`); + } + return await entryFetch(req, init); + } catch (error) { + return renderError(req, error); + } + } +} + +// ----- RPC ----- + +const rpcRequests = new Map(); + +function rpc(name, data, timeout = 3000) { + const id = Math.random().toString(36).slice(2); + return new Promise((resolve, reject) => { + const timer = setTimeout(() => { + rpcRequests.delete(id); + reject(new Error(`RPC "${name}" timed out`)); + }, timeout); + rpcRequests.set(id, { resolve, reject, timer }); + sendMessage?.({ __rpc: name, __rpc_id: id, data }); + }); +} + +// Trap unhandled errors to avoid worker crash +if (typeof process !== "undefined" && typeof process.on === "function") { + process.on("unhandledRejection", (error) => console.error(error)); + process.on("uncaughtException", (error) => console.error(error)); +} + +// ----- RSC Support ----- + +// define __VITE_ENVIRONMENT_RUNNER_IMPORT__ for RSC support +// https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/README.md#__vite_environment_runner_import__ + +globalThis.__VITE_ENVIRONMENT_RUNNER_IMPORT__ = async function (environmentName, id) { + const env = envs[environmentName]; + if (!env) { + throw new Error(`Vite environment "${environmentName}" is not registered`); + } + return env.runner.import(id); +}; + +// ----- Reload ----- + +async function reload() { + try { + await Promise.all(Object.values(envs).map((env) => env?.reload())); + } catch (error) { + console.error(error); + } +} + +// eslint-disable-next-line unicorn/prefer-top-level-await +reload(); + +// ----- HTML Transform ----- + +globalThis.__transform_html__ = async function (html) { + html = await rpc("transformHTML", html).catch((error) => { + console.warn("Failed to transform HTML via Vite:", error); + return html; + }); + return html; +}; + +// ----- Exports (env-runner AppEntry) ----- + +export function fetch(req) { + const viteEnv = req?.headers.get("x-vite-env") || "nitro"; + const env = envs[viteEnv]; + if (!env) { + return renderError(req, httpError(500, `Unknown vite environment "${viteEnv}"`)); + } + return env.fetch(req); +} + +export function upgrade(context) { + const handleUpgrade = envs.nitro?.entry?.handleUpgrade; + if (handleUpgrade) { + handleUpgrade(context.node.req, context.node.socket, context.node.head); + } +} + +export const ipc = { + onOpen(ctx) { + sendMessage = ctx.sendMessage; + }, + onMessage(message) { + if (message?.__rpc_id) { + const req = rpcRequests.get(message.__rpc_id); + if (req) { + clearTimeout(req.timer); + rpcRequests.delete(message.__rpc_id); + if (message.error) { + req.reject(typeof message.error === "string" ? new Error(message.error) : message.error); + } else { + req.resolve(message.data); + } + } + return; + } + if (message?.type === "custom") { + if (message.event === "nitro:vite-env") { + const { name, entry } = message.data; + if (!envs[name]) { + envs[name] = new ViteEnvRunner({ name, entry }); + } + return; + } + } + if (message?.type === "full-reload") { + reload(); + return; + } + for (const listener of messageListeners) { + listener(message); + } + }, + onClose() {}, +}; + +// ----- Error handling ----- + +function httpError(status, message) { + const error = new Error(message || `HTTP Error ${status}`); + error.status = status; + error.name = "NitroViteError"; + return error; +} + +async function renderError(req, error) { + if (req.headers.get("accept")?.includes("application/json")) { + return new Response( + JSON.stringify( + { + status: error.status || 500, + name: error.name || "Error", + message: error.message, + stack: (error.stack || "") + .split("\n") + .splice(1) + .map((l) => l.trim()), + }, + null, + 2 + ), + { + status: error.status || 500, + headers: { + "Content-Type": "application/json", + "Cache-Control": "no-store, max-age=0, must-revalidate", + Pragma: "no-cache", + Expires: "0", + }, + } + ); + } + try { + const { Youch } = await import("youch"); + const youch = new Youch(); + return new Response(await youch.toHTML(error), { + status: error.status || 500, + headers: { + "Content-Type": "text/html", + "Cache-Control": "no-store, max-age=0, must-revalidate", + Pragma: "no-cache", + Expires: "0", + }, + }); + } catch { + return new Response(`
${error.stack || error.message || error}
`, { + status: error.status || 500, + headers: { + "Content-Type": "text/html", + "Cache-Control": "no-store, max-age=0, must-revalidate", + Pragma: "no-cache", + Expires: "0", + }, + }); + } +} diff --git a/src/runtime/internal/vite/ssr-renderer.mjs b/src/runtime/internal/vite/ssr-renderer.mjs new file mode 100644 index 0000000000..45e3e63c7d --- /dev/null +++ b/src/runtime/internal/vite/ssr-renderer.mjs @@ -0,0 +1,6 @@ +import { fetchViteEnv } from "nitro/vite/runtime"; + +/** @param {{ req: Request }} HTTPEvent */ +export default function ssrRenderer({ req }) { + return fetchViteEnv("ssr", req); +} diff --git a/src/runtime/meta.ts b/src/runtime/meta.ts new file mode 100644 index 0000000000..99df0553c6 --- /dev/null +++ b/src/runtime/meta.ts @@ -0,0 +1,32 @@ +import { fileURLToPath } from "node:url"; + +import packageJson from "../../package.json" with { type: "json" }; + +export const version: string = packageJson.version; + +const resolve = (path: string) => fileURLToPath(new URL(path, import.meta.url)); + +export const runtimeDir: string = /* @__PURE__ */ resolve("./"); +export const presetsDir: string = /* @__PURE__ */ resolve("../presets/"); +export const pkgDir: string = /* @__PURE__ */ resolve("../../"); + +export const runtimeDependencies: string[] = [ + "crossws", // dep + "croner", // traced + "db0", // dep + "defu", // traced + "destr", // traced + "h3", // dep + "rou3", // sub-dep of h3 + "hookable", // traced + "ofetch", // dep + "ocache", // dep + "ohash", // traced + "rendu", // traced + "scule", // traced + "srvx", // dep + "ufo", // traced + "unctx", // traced + "unenv", // dep + "unstorage", // dep +]; diff --git a/src/runtime/nitro.ts b/src/runtime/nitro.ts new file mode 100644 index 0000000000..e80231a26f --- /dev/null +++ b/src/runtime/nitro.ts @@ -0,0 +1,58 @@ +// Config +import type { NitroConfig } from "nitro/types"; +import type { ServerRequestContext } from "srvx"; +import { toRequest, type H3EventContext } from "h3"; + +export function defineConfig(config: Omit): Omit { + return config; +} + +// Type (only) helpers +export { defineNitroPlugin as definePlugin } from "./internal/plugin.ts"; +export { defineRouteMeta } from "./internal/meta.ts"; +export { defineNitroErrorHandler as defineErrorHandler } from "./internal/error/utils.ts"; + +// H3 +export { + defineHandler, + defineMiddleware, + defineWebSocketHandler, + html, + HTTPError, + HTTPResponse, +} from "h3"; +export type { H3Event } from "h3"; + +// Runtime +export function serverFetch( + resource: string | URL | Request, + init?: RequestInit, + context?: ServerRequestContext | H3EventContext +): Promise { + const nitro = + globalThis.__nitro__?.default || + globalThis.__nitro__?.prerender || + globalThis.__nitro_builder__; + if (!nitro) { + return Promise.reject(new Error("Nitro instance is not available.")); + } + const req = toRequest(resource, init); + req.context = { ...req.context, ...context }; + try { + return Promise.resolve(nitro.fetch(req)); + } catch (error) { + return Promise.reject(error); + } +} + +export function fetch( + resource: string | URL | Request, + init?: RequestInit, + context?: ServerRequestContext | H3EventContext +): Promise { + if (typeof resource === "string" && resource.charCodeAt(0) === 47) { + return serverFetch(resource, init, context); + } + resource = (resource as any)._request || resource; // unwrap srvx request + return globalThis.fetch(resource, init); +} diff --git a/src/runtime/plugin.ts b/src/runtime/plugin.ts deleted file mode 100644 index 88821df27c..0000000000 --- a/src/runtime/plugin.ts +++ /dev/null @@ -1,3 +0,0 @@ -// Backward compatibility for imports from "#internal/nitro/*" or "nitropack/runtime/*" - -export { defineNitroPlugin, nitroPlugin } from "./internal/plugin"; diff --git a/src/runtime/runtime-config.ts b/src/runtime/runtime-config.ts new file mode 100644 index 0000000000..67d5aac4a3 --- /dev/null +++ b/src/runtime/runtime-config.ts @@ -0,0 +1 @@ +export { useRuntimeConfig } from "./internal/runtime-config.ts"; diff --git a/src/runtime/storage.ts b/src/runtime/storage.ts index bf822b763a..d6a3050149 100644 --- a/src/runtime/storage.ts +++ b/src/runtime/storage.ts @@ -1,3 +1 @@ -// Backward compatibility for imports from "#internal/nitro/*" or "nitropack/runtime/*" - -export { useStorage } from "./internal/storage"; +export { useStorage } from "./internal/storage.ts"; diff --git a/src/runtime/task.ts b/src/runtime/task.ts index 6e7cce97b2..b46d8182a4 100644 --- a/src/runtime/task.ts +++ b/src/runtime/task.ts @@ -1,3 +1 @@ -// Backward compatibility for imports from "#internal/nitro/*" or "nitropack/runtime/*" - -export { defineTask, runTask } from "./internal/task"; +export { defineTask, runTask } from "./internal/task.ts"; diff --git a/src/runtime/utils.ts b/src/runtime/utils.ts deleted file mode 100644 index 153c191d41..0000000000 --- a/src/runtime/utils.ts +++ /dev/null @@ -1,77 +0,0 @@ -// Backward compatibility for imports from "#internal/nitro/*" or "nitropack/runtime/*" -import type { H3Event } from "h3"; -import { getRequestHeader } from "h3"; - -/** - * @deprecated This util is only provided for backward compatibility and will be removed in v3. - */ -export function isJsonRequest(event: H3Event) { - // If the client specifically requests HTML, then avoid classifying as JSON. - if (hasReqHeader(event, "accept", "text/html")) { - return false; - } - return ( - hasReqHeader(event, "accept", "application/json") || - hasReqHeader(event, "user-agent", "curl/") || - hasReqHeader(event, "user-agent", "httpie/") || - hasReqHeader(event, "sec-fetch-mode", "cors") || - event.path.startsWith("/api/") || - event.path.endsWith(".json") - ); -} - -/** - * Internal - */ -function hasReqHeader(event: H3Event, name: string, includes: string) { - const value = getRequestHeader(event, name); - return ( - value && typeof value === "string" && value.toLowerCase().includes(includes) - ); -} - -/** - * @deprecated This util is only provided for backward compatibility and will be removed in v3. - */ -export function normalizeError(error: any, isDev?: boolean) { - // temp fix for https://github.com/nitrojs/nitro/issues/759 - // TODO: investigate vercel-edge not using unenv pollyfill - const cwd = typeof process.cwd === "function" ? process.cwd() : "/"; - - const stack = - !isDev && !import.meta.prerender && (error.unhandled || error.fatal) - ? [] - : ((error.stack as string) || "") - .split("\n") - .splice(1) - .filter((line) => line.includes("at ")) - .map((line) => { - const text = line - .replace(cwd + "/", "./") - .replace("webpack:/", "") - .replace("file://", "") - .trim(); - return { - text, - internal: - (line.includes("node_modules") && !line.includes(".cache")) || - line.includes("internal") || - line.includes("new Promise"), - }; - }); - - const statusCode = error.statusCode || 500; - const statusMessage = - error.statusMessage ?? (statusCode === 404 ? "Not Found" : ""); - const message = - !isDev && error.unhandled - ? "internal server error" - : error.message || error.toString(); - - return { - stack, - statusCode, - statusMessage, - message, - }; -} diff --git a/src/runtime/virtual/_runtime_warn.ts b/src/runtime/virtual/_runtime_warn.ts new file mode 100644 index 0000000000..ad6a06f2de --- /dev/null +++ b/src/runtime/virtual/_runtime_warn.ts @@ -0,0 +1,8 @@ +import consola from "consola"; +import { isTest } from "std-env"; + +if (!isTest) { + consola.warn( + "Nitro runtime imports detected without a builder or Nitro plugin. A stub implementation will be used." + ); +} diff --git a/src/types/virtual/database.d.ts b/src/runtime/virtual/database.ts similarity index 63% rename from src/types/virtual/database.d.ts rename to src/runtime/virtual/database.ts index f191e3b335..dbbeeafa65 100644 --- a/src/types/virtual/database.d.ts +++ b/src/runtime/virtual/database.ts @@ -1,8 +1,9 @@ +import "./_runtime_warn.ts"; import type { Connector } from "db0"; -export declare const connectionConfigs: { +export const connectionConfigs: { [name: string]: { connector: (options: any) => Connector; options: any; }; -}; +} = {}; diff --git a/src/runtime/virtual/error-handler.ts b/src/runtime/virtual/error-handler.ts new file mode 100644 index 0000000000..f02d9b7fa6 --- /dev/null +++ b/src/runtime/virtual/error-handler.ts @@ -0,0 +1,15 @@ +import "./_runtime_warn.ts"; +import { H3Event, toResponse } from "h3"; +import type { NitroErrorHandler } from "nitro/types"; + +type EParams = Parameters; +type EReturn = ReturnType; + +const errorHandler: (error: EParams[0], event: EParams[1]) => EReturn = (error, event) => { + if (error.status !== 404) { + console.error(error as any); + } + return toResponse(error, event as H3Event); +}; + +export default errorHandler; diff --git a/src/runtime/virtual/feature-flags.ts b/src/runtime/virtual/feature-flags.ts new file mode 100644 index 0000000000..75c8ca6748 --- /dev/null +++ b/src/runtime/virtual/feature-flags.ts @@ -0,0 +1,8 @@ +import "./_runtime_warn.ts"; + +export const hasRoutes: boolean = true; +export const hasRouteRules: boolean = true; +export const hasGlobalMiddleware: boolean = true; +export const hasRoutedMiddleware: boolean = true; +export const hasPlugins: boolean = true; +export const hasHooks: boolean = true; diff --git a/src/runtime/virtual/plugins.ts b/src/runtime/virtual/plugins.ts new file mode 100644 index 0000000000..f77a96cccd --- /dev/null +++ b/src/runtime/virtual/plugins.ts @@ -0,0 +1,4 @@ +import "./_runtime_warn.ts"; +import type { NitroAppPlugin } from "nitro/types"; + +export const plugins: NitroAppPlugin[] = []; diff --git a/src/runtime/virtual/polyfills.ts b/src/runtime/virtual/polyfills.ts new file mode 100644 index 0000000000..e01315c156 --- /dev/null +++ b/src/runtime/virtual/polyfills.ts @@ -0,0 +1,3 @@ +import "./_runtime_warn.ts"; + +export default {}; diff --git a/src/runtime/virtual/public-assets.ts b/src/runtime/virtual/public-assets.ts new file mode 100644 index 0000000000..bbca6a7e0c --- /dev/null +++ b/src/runtime/virtual/public-assets.ts @@ -0,0 +1,14 @@ +import "./_runtime_warn.ts"; +import type { PublicAsset } from "nitro/types"; + +export const publicAssetBases: string[] = []; + +export const isPublicAssetURL: (id: string) => boolean = () => false; + +export const getPublicAssetMeta: (id: string) => { maxAge?: number } | null = () => null; + +export const readAsset: (id: string) => Promise = async () => { + throw new Error("Asset not found"); +}; + +export const getAsset: (id: string) => PublicAsset | null = () => null; diff --git a/src/runtime/virtual/renderer-template.ts b/src/runtime/virtual/renderer-template.ts new file mode 100644 index 0000000000..dd0add08a4 --- /dev/null +++ b/src/runtime/virtual/renderer-template.ts @@ -0,0 +1,9 @@ +import "./_runtime_warn.ts"; + +export function rendererTemplate(_req: Request): string | Promise { + return ``; +} + +// dev only +export const rendererTemplateFile: string | undefined = undefined; +export const isStaticTemplate: boolean | undefined = undefined; diff --git a/src/runtime/virtual/routing-meta.ts b/src/runtime/virtual/routing-meta.ts new file mode 100644 index 0000000000..07e4f3c588 --- /dev/null +++ b/src/runtime/virtual/routing-meta.ts @@ -0,0 +1,8 @@ +import "./_runtime_warn.ts"; +import type { NitroRouteMeta } from "nitro/types"; + +export const handlersMeta: { + route?: string; + method?: string; + meta?: NitroRouteMeta; +}[] = []; diff --git a/src/runtime/virtual/routing.ts b/src/runtime/virtual/routing.ts new file mode 100644 index 0000000000..747d8751ed --- /dev/null +++ b/src/runtime/virtual/routing.ts @@ -0,0 +1,19 @@ +import "./_runtime_warn.ts"; + +import type { Middleware, H3Route } from "h3"; +import type { MatchedRoute } from "rou3"; +import type { MatchedRouteRule } from "nitro/types"; + +export function findRoute(_method: string, _path: string): MatchedRoute | undefined { + return undefined; +} + +export function findRouteRules(_method: string, _path: string): MatchedRoute[] { + return []; +} + +export const globalMiddleware: Middleware[] = []; + +export function findRoutedMiddleware(_method: string, _path: string): MatchedRoute[] { + return []; +} diff --git a/src/runtime/virtual/runtime-config.ts b/src/runtime/virtual/runtime-config.ts new file mode 100644 index 0000000000..bf741a7765 --- /dev/null +++ b/src/runtime/virtual/runtime-config.ts @@ -0,0 +1,7 @@ +import "./_runtime_warn.ts"; +import type { NitroRuntimeConfig } from "nitro/types"; + +export const runtimeConfig: NitroRuntimeConfig = { + app: {}, + nitro: {}, +}; diff --git a/src/runtime/virtual/server-assets.ts b/src/runtime/virtual/server-assets.ts new file mode 100644 index 0000000000..b39db89118 --- /dev/null +++ b/src/runtime/virtual/server-assets.ts @@ -0,0 +1,18 @@ +import "./_runtime_warn.ts"; +import { createStorage, type Storage } from "unstorage"; + +import type { AssetMeta } from "nitro/types"; + +export const assets: Storage = createStorage(); + +export function readAsset(_id: string): Promise { + return Promise.resolve({} as T); +} + +export function statAsset(_id: string): Promise { + return Promise.resolve({}); +} + +export function getKeys(): Promise { + return Promise.resolve([]); +} diff --git a/src/runtime/virtual/storage.ts b/src/runtime/virtual/storage.ts new file mode 100644 index 0000000000..973215b9eb --- /dev/null +++ b/src/runtime/virtual/storage.ts @@ -0,0 +1,6 @@ +import "./_runtime_warn.ts"; +import { type Storage, createStorage } from "unstorage"; + +export function initStorage(): Storage { + return createStorage(); +} diff --git a/src/runtime/virtual/tasks.ts b/src/runtime/virtual/tasks.ts new file mode 100644 index 0000000000..c46ecb2774 --- /dev/null +++ b/src/runtime/virtual/tasks.ts @@ -0,0 +1,6 @@ +import "./_runtime_warn.ts"; +import type { Task, TaskMeta } from "nitro/types"; + +export const tasks: Record Promise; meta: TaskMeta }> = {}; + +export const scheduledTasks: false | { cron: string; tasks: string[] }[] = []; diff --git a/src/runtime/vite.ts b/src/runtime/vite.ts new file mode 100644 index 0000000000..240d1165da --- /dev/null +++ b/src/runtime/vite.ts @@ -0,0 +1,22 @@ +import { HTTPError, toRequest } from "h3"; + +type FetchableEnv = { + fetch: (request: Request) => Response | Promise; +}; + +declare global { + var __nitro_vite_envs__: Record; +} + +export function fetchViteEnv( + viteEnvName: string, + input: RequestInfo | URL, + init?: RequestInit +): Promise { + const envs = globalThis.__nitro_vite_envs__ || {}; + const viteEnv = envs[viteEnvName as keyof typeof envs] as FetchableEnv; + if (!viteEnv) { + throw HTTPError.status(404); + } + return Promise.resolve(viteEnv.fetch(toRequest(input, init))); +} diff --git a/src/core/scan.ts b/src/scan.ts similarity index 80% rename from src/core/scan.ts rename to src/scan.ts index d5f53cf1ed..ca076ed25a 100644 --- a/src/core/scan.ts +++ b/src/scan.ts @@ -1,5 +1,5 @@ -import { globby } from "globby"; -import type { Nitro } from "nitropack/types"; +import { glob } from "tinyglobby"; +import type { Nitro } from "nitro/types"; import { join, relative } from "pathe"; import { withBase, withLeadingSlash, withoutTrailingSlash } from "ufo"; @@ -53,26 +53,21 @@ export async function scanHandlers(nitro: Nitro) { const middleware = await scanMiddleware(nitro); const handlers = await Promise.all([ - scanServerRoutes( - nitro, - nitro.options.apiDir || "api", - nitro.options.apiBaseURL || "/api" - ), + scanServerRoutes(nitro, nitro.options.apiDir || "api", nitro.options.apiBaseURL || "/api"), scanServerRoutes(nitro, nitro.options.routesDir || "routes"), ]).then((r) => r.flat()); + const seenHandlers = new Set(); nitro.scannedHandlers = [ ...middleware, - ...handlers.filter((h, index, array) => { - return ( - array.findIndex( - (h2) => - h.route === h2.route && h.method === h2.method && h.env === h2.env - ) === index - ); + ...handlers.filter((h) => { + const key = `${h.route}\0${h.method}\0${h.env}`; + return seenHandlers.has(key) ? false : (seenHandlers.add(key), true); }), ]; + nitro.routing.sync(); + return handlers; } @@ -80,25 +75,22 @@ export async function scanMiddleware(nitro: Nitro) { const files = await scanFiles(nitro, "middleware"); return files.map((file) => { return { + route: "/**", middleware: true, handler: file.fullPath, }; }); } -export async function scanServerRoutes( - nitro: Nitro, - dir: string, - prefix = "/" -) { +export async function scanServerRoutes(nitro: Nitro, dir: string, prefix = "/") { const files = await scanFiles(nitro, dir); return files.map((file) => { let route = file.path .replace(/\.[A-Za-z]+$/, "") .replace(/\(([^(/\\]+)\)[/\\]/g, "") .replace(/\[\.{3}]/g, "**") - .replace(/\[\.{3}(\w+)]/g, "**:$1") - .replace(/\[([^/\]]+)]/g, ":$1"); + .replace(/\[\.{3}([^\]]+)]/g, (_, p) => "**:" + p.replace(/[^\w-]/g, "_")) + .replace(/\[([^/\]]+)]/g, (_, p) => ":" + p.replace(/[^\w-]/g, "_")); route = withLeadingSlash(withoutTrailingSlash(withBase(route, prefix))); const suffixMatch = route.match(suffixRegex); @@ -151,16 +143,18 @@ async function scanFiles(nitro: Nitro, name: string): Promise { return files; } -async function scanDir( - nitro: Nitro, - dir: string, - name: string -): Promise { - const fileNames = await globby(join(name, GLOB_SCAN_PATTERN), { +async function scanDir(nitro: Nitro, dir: string, name: string): Promise { + const fileNames = await glob(join(name, GLOB_SCAN_PATTERN), { cwd: dir, dot: true, ignore: nitro.options.ignore, absolute: true, + }).catch((error) => { + if (error?.code === "ENOTDIR") { + nitro.logger.warn(`Ignoring \`${join(dir, name)}\`. It must be a directory.`); + return []; + } + throw error; }); return fileNames .map((fullPath) => { diff --git a/src/task.ts b/src/task.ts new file mode 100644 index 0000000000..0344a4c3fe --- /dev/null +++ b/src/task.ts @@ -0,0 +1,120 @@ +import http from "node:http"; +import { existsSync } from "node:fs"; +import { readFile } from "node:fs/promises"; +import { resolve } from "pathe"; +import { withBase, withQuery } from "ufo"; + +import type { QueryObject } from "ufo"; +import type { RequestOptions } from "node:http"; +import type { NitroBuildInfo, TaskEvent, TaskRunnerOptions } from "nitro/types"; + +/** @experimental */ +export async function runTask( + taskEvent: TaskEvent, + opts?: TaskRunnerOptions +): Promise<{ result: unknown }> { + const ctx = await _getTasksContext(opts); + const result = await ctx.devFetch(`/_nitro/tasks/${taskEvent.name}`, { + method: "POST", + body: taskEvent, + }); + return result; +} + +/** @experimental */ +export async function listTasks(opts?: TaskRunnerOptions) { + const ctx = await _getTasksContext(opts); + const res = (await ctx.devFetch("/_nitro/tasks")) as { + tasks: Record; + }; + return res.tasks; +} + +// --- module internal --- + +const _devHint = `(is dev server running?)`; + +async function _getTasksContext(opts?: TaskRunnerOptions) { + const cwd = resolve(process.cwd(), opts?.cwd || "."); + const buildDir = resolve(cwd, opts?.buildDir || "node_modules/.nitro"); + + const buildInfoPath = resolve(buildDir, "nitro.dev.json"); + if (!existsSync(buildInfoPath)) { + throw new Error(`Missing info file: \`${buildInfoPath}\` ${_devHint}`); + } + + const buildInfo = JSON.parse(await readFile(buildInfoPath, "utf8")) as NitroBuildInfo; + + if (!buildInfo.dev?.pid || !buildInfo.dev?.workerAddress) { + throw new Error(`Missing dev server info in: \`${buildInfoPath}\` ${_devHint}`); + } + + if (!_pidIsRunning(buildInfo.dev.pid)) { + throw new Error(`Dev server is not running (pid: ${buildInfo.dev.pid})`); + } + + const baseURL = `http://${buildInfo.dev.workerAddress.host || "localhost"}:${buildInfo.dev.workerAddress.port || "3000"}`; + const socketPath = buildInfo.dev.workerAddress.socketPath; + + const devFetch = ( + path: string, + options?: { + method?: RequestOptions["method"]; + query?: QueryObject; + body?: unknown; + } + ) => { + return new Promise((resolve, reject) => { + let url = withBase(path, baseURL); + if (options?.query) { + url = withQuery(url, options.query); + } + + const request = http.request( + url, + { + socketPath, + method: options?.method, + headers: { + Accept: "application/json", + "Content-Type": "application/json", + }, + }, + (response) => { + if (!response.statusCode || (response.statusCode >= 400 && response.statusCode < 600)) { + reject(new Error(response.statusMessage)); + return; + } + + let data = ""; + response + .on("data", (chunk) => (data += chunk)) + // Response of tasks is always JSON + .on("end", () => resolve(JSON.parse(data))) + .on("error", (e) => reject(e)); + } + ); + + request.on("error", (e) => reject(e)); + + if (options?.body) { + request.write(JSON.stringify(options.body)); + } + request.end(); + }); + }; + + return { + buildInfo, + devFetch, + }; +} + +function _pidIsRunning(pid: number) { + try { + process.kill(pid, 0); + return true; + } catch { + return false; + } +} diff --git a/src/types/_utils.ts b/src/types/_utils.ts index 2586cffad9..2cfebcfbcc 100644 --- a/src/types/_utils.ts +++ b/src/types/_utils.ts @@ -1,14 +1,8 @@ -export type Enumerate< - N extends number, - Acc extends number[] = [], -> = Acc["length"] extends N +export type Enumerate = Acc["length"] extends N ? Acc[number] : Enumerate; -export type IntRange = Exclude< - Enumerate, - Enumerate ->; +export type IntRange = Exclude, Enumerate>; export type ExcludeFunctions> = Pick< G, @@ -16,14 +10,6 @@ export type ExcludeFunctions> = Pick< { [P in keyof G]: NonNullable extends Function ? never : P }[keyof G] >; -// prettier-ignore -export type DeepPartial = T extends Record - ? { [P in keyof T]?: DeepPartial | T[P] } - : T; - -export type KebabCase< - T extends string, - A extends string = "", -> = T extends `${infer F}${infer R}` +export type KebabCase = T extends `${infer F}${infer R}` ? KebabCase ? "" : "-"}${Lowercase}`> : A; diff --git a/src/types/build.ts b/src/types/build.ts new file mode 100644 index 0000000000..1efc10b414 --- /dev/null +++ b/src/types/build.ts @@ -0,0 +1,26 @@ +import type { + InputOptions as RollupInputOptions, + OutputOptions as RollupOutputOptions, +} from "rollup"; + +import type { + InputOptions as RolldownInputOptions, + OutputOptions as RolldownOutputOptions, + MinifyOptions as RolldownMinifyOptions, + TransformOptions as RolldownTransformOptions, +} from "rolldown"; + +export type RollupConfig = RollupInputOptions & { + output?: RollupOutputOptions; +}; + +export type RolldownConfig = RolldownInputOptions & { + output?: RolldownOutputOptions; +}; + +export interface OXCOptions { + minify?: RolldownMinifyOptions; + transform?: Omit & { + jsx?: Exclude; + }; +} diff --git a/src/types/config.ts b/src/types/config.ts index 21a5a3aed5..81dc7a21b6 100644 --- a/src/types/config.ts +++ b/src/types/config.ts @@ -1,5 +1,5 @@ -import type { RollupCommonJSOptions } from "@rollup/plugin-commonjs"; -import type { C12InputConfig, ConfigWatcher, ResolvedConfig } from "c12"; +import type commonjs from "@rollup/plugin-commonjs"; +import type { C12InputConfig, ConfigWatcher, DotenvOptions, ResolvedConfig } from "c12"; import type { WatchConfigOptions } from "c12"; import type { ChokidarOptions } from "chokidar"; import type { CompatibilityDateSpec, CompatibilityDates } from "compatx"; @@ -7,37 +7,30 @@ import type { LogLevel } from "consola"; import type { ConnectorName } from "db0"; import type { NestedHooks } from "hookable"; import type { ProxyServerOptions } from "httpxy"; -import type { - NitroRuntimeConfigApp as NitroTypesRuntimeConfigApp, - NitroRuntimeConfig as NitroTypeskRuntimeConfig, -} from "nitropack"; -import type { - PresetName, - PresetNameInput, - PresetOptions, -} from "nitropack/presets"; +import type { PresetName, PresetNameInput, PresetOptions } from "../presets/index.ts"; import type { TSConfig } from "pkg-types"; -import type { PluginVisualizerOptions } from "rollup-plugin-visualizer"; import type { Preset as UnenvPreset } from "unenv"; import type { UnimportPluginOptions } from "unimport/unplugin"; import type { BuiltinDriverName } from "unstorage"; import type { UnwasmPluginOptions } from "unwasm/plugin"; -import type { DeepPartial } from "./_utils"; -import type { DevServerOptions } from "./dev"; +import type { RunnerName } from "env-runner"; import type { + EventHandlerFormat, NitroDevEventHandler, NitroErrorHandler, NitroEventHandler, -} from "./handler"; -import type { NitroHooks } from "./hooks"; -import type { NitroModuleInput } from "./module"; -import type { NitroFrameworkInfo } from "./nitro"; -import type { NitroOpenAPIConfig } from "./openapi"; -export type { NitroOpenAPIConfig } from "./openapi"; -import type { NitroPreset } from "./preset"; -import type { EsbuildOptions, NodeExternalsOptions } from "./rollup"; -import type { RollupConfig } from "./rollup"; -import type { NitroRouteConfig, NitroRouteRules } from "./route-rules"; +} from "./handler.ts"; +import type { NitroHooks } from "./hooks.ts"; +import type { NitroModuleInput } from "./module.ts"; +import type { NitroFrameworkInfo } from "./nitro.ts"; +import type { NitroOpenAPIConfig } from "./openapi.ts"; +export type { NitroOpenAPIConfig } from "./openapi.ts"; +import type { NitroPreset } from "./preset.ts"; +import type { OXCOptions, RolldownConfig } from "./build.ts"; +import type { RollupConfig } from "./build.ts"; +import type { NitroRouteConfig, NitroRouteRules } from "./route-rules.ts"; + +type RollupCommonJSOptions = NonNullable[0]>; /** * Nitro normalized options (nitro.options) @@ -59,13 +52,11 @@ export interface NitroOptions extends PresetOptions { static: boolean; logLevel: LogLevel; runtimeConfig: NitroRuntimeConfig; - appConfig: AppConfig; - appConfigFiles: string[]; // Dirs workspaceDir: string; rootDir: string; - srcDir: string; + serverDir: string | false; scanDirs: string[]; apiDir: string; routesDir: string; @@ -76,53 +67,55 @@ export interface NitroOptions extends PresetOptions { publicDir: string; }; + /** @deprecated migrate to `serverDir` */ + srcDir: string; + // Features storage: StorageMounts; devStorage: StorageMounts; database: DatabaseConnectionConfigs; devDatabase: DatabaseConnectionConfigs; - bundledStorage: string[]; - timing: boolean; - renderer?: string; + renderer?: { handler?: string; static?: boolean; template?: string }; + ssrRoutes: string[]; serveStatic: boolean | "node" | "deno" | "inline"; noPublicDir: boolean; + manifest?: { + deploymentId?: string; + }; + features: { + /** + * Enable runtime hooks for request and response. + * + * By default this feature will be enabled if there is at least one nitro plugin. + */ + runtimeHooks?: boolean; + + /** + * Enable WebSocket support + */ + websocket?: boolean; + }; /** - * @experimental Requires `experimental.wasm` to work * * @see https://github.com/unjs/unwasm */ - wasm?: UnwasmPluginOptions; + wasm?: false | UnwasmPluginOptions; openAPI?: NitroOpenAPIConfig; experimental: { - legacyExternals?: boolean; openAPI?: boolean; /** * See https://github.com/microsoft/TypeScript/pull/51669 */ typescriptBundlerResolution?: boolean; /** - * Enable native async context support for useEvent() + * Enable native async context support for useRequest() */ asyncContext?: boolean; - /** - * Enable Experimental WebAssembly Support - * - * @see https://github.com/unjs/unwasm - */ - wasm?: boolean; - /** - * Disable Experimental bundling of Nitro Runtime Dependencies - */ - bundleRuntimeDependencies?: false; /** * Disable Experimental Sourcemap Minification */ sourcemapMinify?: false; - /** - * Backward compatibility support for Node fetch (required for Node < 18) - */ - nodeFetchCompat?: boolean; /** * Allow env expansion in runtime config * @@ -130,9 +123,11 @@ export interface NitroOptions extends PresetOptions { */ envExpansion?: boolean; /** - * Enable experimental WebSocket support + * Enable WebSocket support * * @see https://nitro.build/guide/websocket + * + * @deprecated use `features.websocket` instead. */ websocket?: boolean; /** @@ -149,15 +144,15 @@ export interface NitroOptions extends PresetOptions { tasks?: boolean; }; future: { - nativeSWR: boolean; + nativeSWR?: boolean; }; serverAssets: ServerAssetDir[]; publicAssets: PublicAssetDir[]; - imports: UnimportPluginOptions | false; + imports: Partial | false; modules?: NitroModuleInput[]; plugins: string[]; - tasks: { [name: string]: { handler: string; description: string } }; + tasks: { [name: string]: { handler?: string; description?: string } }; scheduledTasks: { [cron: string]: string | string[] }; virtual: Record string | Promise)>; compressPublicAssets: boolean | CompressOptions; @@ -165,85 +160,102 @@ export interface NitroOptions extends PresetOptions { // Dev dev: boolean; - devServer: DevServerOptions; + devServer: { + port?: number; + hostname?: string; + watch?: string[]; + runner?: RunnerName; + }; watchOptions: ChokidarOptions; devProxy: Record; // Logging logging: { - compressedSizes: boolean; - buildSuccess: boolean; + compressedSizes?: boolean; + buildSuccess?: boolean; }; // Routing baseURL: string; apiBaseURL: string; + + serverEntry: false | { handler: string; format?: EventHandlerFormat }; handlers: NitroEventHandler[]; - routeRules: { [path: string]: NitroRouteRules }; devHandlers: NitroDevEventHandler[]; + routeRules: { [path: string]: NitroRouteRules }; + routes: Record>; + errorHandler: string | string[]; devErrorHandler: NitroErrorHandler; + prerender: { /** * Prerender HTML routes within subfolders (`/test` would produce `/test/index.html`) */ - autoSubfolderIndex: boolean; - concurrency: number; - interval: number; - crawlLinks: boolean; - failOnError: boolean; - ignore: Array< - string | RegExp | ((path: string) => undefined | null | boolean) - >; - ignoreUnprefixedPublicAssets: boolean; - routes: string[]; + autoSubfolderIndex?: boolean; + concurrency?: number; + interval?: number; + crawlLinks?: boolean; + failOnError?: boolean; + ignore?: Array undefined | null | boolean)>; + ignoreUnprefixedPublicAssets?: boolean; + routes?: string[]; /** * Amount of retries. Pass Infinity to retry indefinitely. * @default 3 */ - retry: number; + retry?: number; /** * Delay between each retry in ms. * @default 500 */ - retryDelay: number; + retryDelay?: number; }; // Rollup + builder?: "rollup" | "rolldown" | "vite"; rollupConfig?: RollupConfig; + rolldownConfig?: RolldownConfig; entry: string; unenv: UnenvPreset[]; alias: Record; minify: boolean; inlineDynamicImports: boolean; - sourceMap: boolean | "inline" | "hidden"; + sourcemap: boolean; node: boolean; moduleSideEffects: string[]; - esbuild?: { - options?: Partial; - }; - noExternals: boolean; - externals: NodeExternalsOptions; - analyze: false | PluginVisualizerOptions; + oxc?: OXCOptions; replace: Record string)>; commonJS?: RollupCommonJSOptions; exportConditions?: string[]; + noExternals?: boolean | (string | RegExp)[]; + traceDeps?: (string | RegExp)[]; // Advanced typescript: { strict?: boolean; - internalPaths?: boolean; generateRuntimeConfigTypes?: boolean; generateTsConfig?: boolean; - /** the path of the generated `tsconfig.json`, relative to buildDir */ - tsconfigPath: string; tsConfig?: Partial; + + /** + * Path of the generated types directory. + * + * Default is `node_modules/.nitro/types` + */ + generatedTypesDir?: string; + + /** + * Path of the generated `tsconfig.json` relative to `typescript.generatedTypesDir` + * + * Default is `tsconfig.json` (`node_modules/.nitro/types/tsconfig.json`) + */ + tsconfigPath?: string; }; hooks: NestedHooks; - nodeModulesDirs: string[]; commands: { - preview: string; - deploy: string; + preview?: string; + deploy?: string; }; // Framework @@ -260,10 +272,21 @@ export interface NitroOptions extends PresetOptions { * Nitro input config (nitro.config) */ export interface NitroConfig - extends DeepPartial< + extends + Partial< Omit< NitroOptions, - "routeRules" | "rollupConfig" | "preset" | "compatibilityDate" | "unenv" + | "routeRules" + | "rollupConfig" + | "preset" + | "compatibilityDate" + | "unenv" + | "serverDir" + | "_config" + | "_c12" + | "serverEntry" + | "renderer" + | "output" > >, C12InputConfig { @@ -273,6 +296,10 @@ export interface NitroConfig rollupConfig?: Partial; compatibilityDate?: CompatibilityDateSpec; unenv?: UnenvPreset | UnenvPreset[]; + serverDir?: boolean | "./" | "./server" | (string & {}); + serverEntry?: string | NitroOptions["serverEntry"]; + renderer?: false | NitroOptions["renderer"]; + output?: Partial; } // ------------------------------------------------------------ @@ -283,29 +310,32 @@ export interface LoadConfigOptions { watch?: boolean; c12?: WatchConfigOptions; compatibilityDate?: CompatibilityDateSpec; + dotenv?: boolean | DotenvOptions; } // ------------------------------------------------------------ // Partial types // ------------------------------------------------------------ -// App config -export interface AppConfig { - [key: string]: any; -} - // Public assets export interface PublicAssetDir { baseURL?: string; fallthrough?: boolean; maxAge: number; dir: string; + /** + * Pass false to disable ignore patterns when scanning the directory, or + * pass an array of glob patterns to ignore (which will override global + * nitro.ignore patterns). + */ + ignore?: false | string[]; } // Public assets compression export interface CompressOptions { gzip?: boolean; brotli?: boolean; + zstd?: boolean; } // Server assets @@ -333,13 +363,22 @@ export type DatabaseConnectionConfig = { [key: string]: any; }; }; -export type DatabaseConnectionConfigs = Record< - DatabaseConnectionName, - DatabaseConnectionConfig ->; +export type DatabaseConnectionConfigs = Record; // Runtime config -export interface NitroRuntimeConfigApp extends NitroTypesRuntimeConfigApp {} +export interface NitroRuntimeConfigApp { + [key: string]: any; +} -export interface NitroRuntimeConfig extends NitroTypeskRuntimeConfig {} +export interface NitroRuntimeConfig { + nitro?: { + envPrefix?: string; + envExpansion?: boolean; + routeRules?: { + [path: string]: NitroRouteConfig; + }; + openAPI?: NitroOpenAPIConfig; + }; + [key: string]: any; +} diff --git a/src/types/dev.ts b/src/types/dev.ts deleted file mode 100644 index a9a13655f2..0000000000 --- a/src/types/dev.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { IncomingMessage, OutgoingMessage } from "node:http"; -import type { Duplex } from "node:stream"; -import type { Worker } from "node:worker_threads"; -import type { FSWatcher } from "chokidar"; -import type { App } from "h3"; -import type { ListenOptions, Listener } from "listhen"; - -export interface DevServerOptions { - watch: string[]; -} - -export interface NitroWorker { - worker: Worker | null; - address: { host: string; port: number; socketPath?: string }; -} - -export interface NitroDevServer { - reload: () => void; - listen: ( - port: ListenOptions["port"], - opts?: Partial - ) => Promise; - app: App; - close: () => Promise; - watcher?: FSWatcher; - upgrade: ( - req: IncomingMessage, - socket: OutgoingMessage | Duplex, - head: Buffer - ) => void; -} diff --git a/src/types/fetch/_match.ts b/src/types/fetch/_match.ts index 4c097a1955..1cc48f6951 100644 --- a/src/types/fetch/_match.ts +++ b/src/types/fetch/_match.ts @@ -1,4 +1,4 @@ -import type { InternalApi } from "./fetch"; +import type { InternalApi } from "./fetch.ts"; type MatchResult< Key extends string, @@ -9,20 +9,18 @@ type MatchResult< [k in Key]: { key: k; exact: Exact; score: Score; catchAll: catchAll }; }[Key]; -type Subtract< - Minuend extends any[] = [], - Subtrahend extends any[] = [], -> = Minuend extends [...Subtrahend, ...infer Remainder] ? Remainder : never; +type Subtract = Minuend extends [ + ...Subtrahend, + ...infer Remainder, +] + ? Remainder + : never; type TupleIfDiff< First extends string, Second extends string, Tuple extends any[] = [], -> = First extends `${Second}${infer Diff}` - ? Diff extends "" - ? [] - : Tuple - : []; +> = First extends `${Second}${infer Diff}` ? (Diff extends "" ? [] : Tuple) : []; type MaxTuple = { current: T; @@ -37,10 +35,7 @@ type CalcMatchScore< FirstKeySegMatcher extends string = Init extends true ? ":Invalid:" : "", > = `${Key}/` extends `${infer KeySeg}/${infer KeyRest}` ? KeySeg extends FirstKeySegMatcher // return score if `KeySeg` is empty string (except first pass) - ? Subtract< - [...Score, ...TupleIfDiff], - TupleIfDiff - > + ? Subtract<[...Score, ...TupleIfDiff], TupleIfDiff> : `${Route}/` extends `${infer RouteSeg}/${infer RouteRest}` ? `${RouteSeg}?` extends `${infer RouteSegWithoutQuery}?${string}` ? RouteSegWithoutQuery extends KeySeg @@ -58,9 +53,7 @@ type CalcMatchScore< type _MatchedRoutes< Route extends string, - MatchedResultUnion extends MatchResult = MatchResult< - keyof InternalApi - >, + MatchedResultUnion extends MatchResult = MatchResult, > = MatchedResultUnion["key"] extends infer MatchedKeys // spread union type ? MatchedKeys extends string ? Route extends MatchedKeys @@ -70,35 +63,19 @@ type _MatchedRoutes< ? Route extends `${Root}/${string}` ? MatchResult : never // catchAll match - : MatchResult< - MatchedKeys, - false, - CalcMatchScore - > // glob match - : MatchResult< - MatchedKeys, - false, - CalcMatchScore - > // partial match + : MatchResult> // glob match + : MatchResult> // partial match : never : never; export type MatchedRoutes< Route extends string, - MatchedKeysResult extends MatchResult = MatchResult< - keyof InternalApi - >, - Matches extends MatchResult = _MatchedRoutes< - Route, - MatchedKeysResult - >, + MatchedKeysResult extends MatchResult = MatchResult, + Matches extends MatchResult = _MatchedRoutes, > = Route extends "/" ? keyof InternalApi // root middleware : Extract extends never - ? - | Extract< - Exclude, - { score: MaxTuple } - >["key"] + ? // @ts-ignore + | Extract, { score: MaxTuple }>["key"] | Extract["key"] // partial, glob and catchAll matches : Extract["key"]; // exact matches diff --git a/src/types/fetch/_serialize.ts b/src/types/fetch/_serialize.ts index be87b30e58..16cc83e539 100644 --- a/src/types/fetch/_serialize.ts +++ b/src/types/fetch/_serialize.ts @@ -1,14 +1,7 @@ /** * @link https://github.com/remix-run/remix/blob/2248669ed59fd716e267ea41df5d665d4781f4a9/packages/remix-server-runtime/serialize.ts */ -type JsonPrimitive = - | string - | number - | boolean - | string - | number - | boolean - | null; +type JsonPrimitive = string | number | boolean | string | number | boolean | null; // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type type NonJsonPrimitive = undefined | Function | symbol; diff --git a/src/types/fetch/fetch.ts b/src/types/fetch/fetch.ts index 28751405b5..2f0e2dd704 100644 --- a/src/types/fetch/fetch.ts +++ b/src/types/fetch/fetch.ts @@ -1,10 +1,13 @@ -import type { RouterMethod } from "h3"; +import type { HTTPMethod } from "h3"; import type { FetchOptions, FetchRequest, FetchResponse } from "ofetch"; -import type { MatchedRoutes } from "./_match"; +import type { MatchedRoutes } from "./_match.ts"; // An interface to extend in a local project export interface InternalApi {} +// TODO: upgrade to uppercase for h3 v2 types and web consistency +type RouterMethod = Lowercase; + export type NitroFetchRequest = | Exclude | Exclude @@ -35,17 +38,13 @@ export type TypedInternalResponse< // Extracts the available http methods based on the route. // Defaults to all methods if there aren't any methods available or if there is a catch-all route. -export type AvailableRouterMethod = - R extends string - ? keyof InternalApi[MatchedRoutes] extends undefined - ? RouterMethod - : Extract< - keyof InternalApi[MatchedRoutes], - "default" - > extends undefined - ? Extract]> - : RouterMethod - : RouterMethod; +export type AvailableRouterMethod = R extends string + ? keyof InternalApi[MatchedRoutes] extends undefined + ? RouterMethod + : Extract], "default"> extends undefined + ? Extract]> + : RouterMethod + : RouterMethod; // Argumented fetch options to include the correct request methods. // This overrides the default, which is only narrowed to a string. @@ -77,11 +76,7 @@ export type Base$Fetch< request: R, opts?: O ) => Promise< - TypedInternalResponse< - R, - T, - NitroFetchOptions extends O ? "get" : ExtractedRouteMethod - > + TypedInternalResponse extends O ? "get" : ExtractedRouteMethod> >; export interface $Fetch< @@ -109,15 +104,5 @@ export interface $Fetch< ): $Fetch; } -declare global { - // eslint-disable-next-line no-var - var $fetch: $Fetch; - // eslint-disable-next-line @typescript-eslint/no-namespace - namespace NodeJS { - interface Global { - $fetch: $Fetch; - } - } -} - +// eslint-disable-next-line unicorn/require-module-specifiers export type {}; diff --git a/src/types/fetch/index.ts b/src/types/fetch/index.ts index 30b5946621..036619bb9a 100644 --- a/src/types/fetch/index.ts +++ b/src/types/fetch/index.ts @@ -1,3 +1,3 @@ -export * from "./_match"; -export * from "./_serialize"; -export * from "./fetch"; +export * from "./_match.ts"; +export * from "./_serialize.ts"; +export * from "./fetch.ts"; diff --git a/src/types/global.ts b/src/types/global.ts index 3a384a4c4f..3af8907827 100644 --- a/src/types/global.ts +++ b/src/types/global.ts @@ -1,34 +1,22 @@ -import type { NitroConfig, NitroOptions } from "./config"; -import type { NitroModule } from "./module"; +import type { NitroOptions } from "./config.ts"; -export interface NitroStaticBuildFlags { - _asyncContext?: boolean; - _websocket?: boolean; - _tasks?: boolean; +export interface NitroImportMeta { dev?: boolean; - client?: boolean; - nitro?: boolean; - baseURL?: string; - prerender?: boolean; preset?: NitroOptions["preset"]; + prerender?: boolean; + nitro?: boolean; server?: boolean; - versions?: { - nitro?: string; - }; -} - -declare global { - // eslint-disable-next-line @typescript-eslint/no-namespace - namespace NodeJS { - interface Process extends NitroStaticBuildFlags {} - } - - interface ImportMeta extends NitroStaticBuildFlags {} + client?: boolean; + baseURL?: string; + runtimeConfig?: Record; + _asyncContext?: boolean; + _tasks?: boolean; + _websocket?: boolean; } declare global { - const defineNitroConfig: (config: NitroConfig) => NitroConfig; - const defineNitroModule: (definition: NitroModule) => NitroModule; + interface ImportMeta extends NitroImportMeta {} } +// eslint-disable-next-line unicorn/require-module-specifiers export type {}; diff --git a/src/types/h3.ts b/src/types/h3.ts index 9316b93e79..3cf5f45ae8 100644 --- a/src/types/h3.ts +++ b/src/types/h3.ts @@ -1,38 +1,25 @@ -import type { - CacheOptions, - CaptureError, - CapturedErrorContext, -} from "nitropack/types"; -import type { Base$Fetch, NitroFetchRequest } from "./fetch/fetch"; +import type { H3Event as _H3Event } from "h3"; +import type { CacheOptions, CapturedErrorContext } from "./runtime/index.ts"; +import type { Base$Fetch, NitroFetchRequest } from "./fetch/fetch.ts"; +import type { NitroRuntimeConfig } from "./config.ts"; +import type { MatchedRouteRules } from "./route-rules.ts"; -export type H3EventFetch = ( - request: NitroFetchRequest, - init?: RequestInit -) => Promise; +export type H3EventFetch = (request: NitroFetchRequest, init?: RequestInit) => Promise; export type H3Event$Fetch = Base$Fetch; -declare module "h3" { - interface H3Event { - /** @experimental Calls fetch with same context and request headers */ - fetch: H3EventFetch; - /** @experimental Calls fetch with same context and request headers */ - $fetch: H3Event$Fetch; - waitUntil: (promise: Promise) => void; - /** @experimental */ - captureError: CaptureError; - } - interface H3Context { - nitro: { - _waitUntilPromises?: Promise[]; - /** @experimental */ - errors: { error?: Error; context: CapturedErrorContext }[]; +declare module "srvx" { + interface ServerRequestContext { + routeRules?: MatchedRouteRules; + nitro?: { + runtimeConfig?: NitroRuntimeConfig; + errors?: { error?: Error; context: CapturedErrorContext }[]; }; - - cache: { - options: CacheOptions; + cache?: { + options?: CacheOptions; }; } } +// eslint-disable-next-line unicorn/require-module-specifiers export type {}; diff --git a/src/types/handler.ts b/src/types/handler.ts index 9e782970d1..42d9b78dfb 100644 --- a/src/types/handler.ts +++ b/src/types/handler.ts @@ -1,30 +1,43 @@ -import type { EventHandler, H3Error, H3Event, RouterMethod } from "h3"; -import type { PresetName } from "nitropack/presets"; -import type { OperationObject, OpenAPI3 } from "openapi-typescript"; +import type { HTTPError, HTTPMethod, HTTPEvent, HTTPHandler } from "h3"; +import type { PresetName } from "../presets/index.ts"; +import type { OperationObject, OpenAPI3, Extensable } from "../types/openapi-ts.ts"; type MaybeArray = T | T[]; -/** @exprerimental */ +/** @experimental */ export interface NitroRouteMeta { openAPI?: OperationObject & { - $global?: Pick; + $global?: Pick & Extensable; }; } -export interface NitroEventHandler { +interface NitroHandlerCommon { /** - * Path prefix or route + * HTTP pathname pattern to match * - * If an empty string used, will be used as a middleware + * Examples: `/test`, `/api/:id`, `/blog/**` */ - route?: string; + route: string; /** - * Specifies this is a middleware handler. - * Middleware are called on every route and should normally return nothing to pass to the next handlers + * HTTP method to match + */ + method?: HTTPMethod; + + /** + * Run handler as a middleware before other route handlings */ middleware?: boolean; + /** + * Extra Meta + */ + meta?: NitroRouteMeta; +} + +export type EventHandlerFormat = "web" | "node"; + +export interface NitroEventHandler extends NitroHandlerCommon { /** * Use lazy loading to import handler */ @@ -32,54 +45,44 @@ export interface NitroEventHandler { /** * Path to event handler - * */ handler: string; /** - * Router method matcher - */ - method?: RouterMethod; - - /** - * Meta + * Event handler type. + * + * Default is `"web"`. If set to `"node"`, the handler will be converted into a web compatible handler. */ - meta?: NitroRouteMeta; + format?: EventHandlerFormat; /* - * Environments to include this handler + * Environments to include and bundle this handler */ env?: MaybeArray<"dev" | "prod" | "prerender" | PresetName | (string & {})>; } -export interface NitroDevEventHandler { +export interface NitroDevEventHandler extends NitroHandlerCommon { /** - * Path prefix or route - */ - route?: string; - - /** - * Event handler - * + * Event handler function */ - handler: EventHandler; + handler: HTTPHandler; } type MaybePromise = T | Promise; export type NitroErrorHandler = ( - error: H3Error, - event: H3Event, + error: HTTPError, + event: HTTPEvent, _: { defaultHandler: ( - error: H3Error, - event: H3Event, + error: HTTPError, + event: HTTPEvent, opts?: { silent?: boolean; json?: boolean } ) => MaybePromise<{ - status: number; - statusText: string; - headers: Record; - body: string | Record; + status?: number; + statusText?: string; + headers?: HeadersInit; + body?: string | Record; }>; } -) => void | Promise; +) => MaybePromise; diff --git a/src/types/hooks.ts b/src/types/hooks.ts index 38259357c3..8368afcc2e 100644 --- a/src/types/hooks.ts +++ b/src/types/hooks.ts @@ -1,7 +1,8 @@ -import type { NitroConfig } from "./config"; -import type { Nitro, NitroTypes } from "./nitro"; -import type { PrerenderRoute } from "./prerender"; -import type { RollupConfig } from "./rollup"; +import type { EnvRunnerData } from "env-runner"; +import type { NitroConfig } from "./config.ts"; +import type { Nitro, NitroTypes } from "./nitro.ts"; +import type { PrerenderRoute } from "./prerender.ts"; +import type { RollupConfig } from "./build.ts"; type HookResult = void | Promise; @@ -10,7 +11,7 @@ export interface NitroHooks { "build:before": (nitro: Nitro) => HookResult; "rollup:before": (nitro: Nitro, config: RollupConfig) => HookResult; compiled: (nitro: Nitro) => HookResult; - "dev:reload": () => HookResult; + "dev:reload": (payload?: { entry?: string; workerData?: EnvRunnerData }) => HookResult; "dev:start": () => HookResult; "dev:error": (cause?: unknown) => HookResult; "rollup:reload": () => HookResult; diff --git a/src/types/index.ts b/src/types/index.ts index 45dc101941..c0ccee5d42 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,14 +1,25 @@ -export * from "./fetch"; -export * from "./runtime"; -export * from "./config"; -export * from "./dev"; -export * from "./global"; -export * from "./h3"; -export * from "./handler"; -export * from "./hooks"; -export * from "./module"; -export * from "./nitro"; -export * from "./prerender"; -export * from "./preset"; -export * from "./rollup"; -export * from "./route-rules"; +import "nitro"; +import "nitro/app"; +import "nitro/cache"; +import "nitro/context"; +import "nitro/database"; +import "nitro/h3"; +import "nitro/runtime-config"; +import "nitro/storage"; +import "nitro/task"; + +export * from "./fetch/index.ts"; +export * from "./runtime/index.ts"; +export * from "./config.ts"; +export * from "./runner.ts"; +export * from "./global.ts"; +export * from "./h3.ts"; +export * from "./handler.ts"; +export * from "./hooks.ts"; +export * from "./module.ts"; +export * from "./nitro.ts"; +export * from "./prerender.ts"; +export * from "./preset.ts"; +export * from "./build.ts"; +export * from "./route-rules.ts"; +export * from "./srvx.ts"; diff --git a/src/types/module.ts b/src/types/module.ts index 030536499c..265ab43fef 100644 --- a/src/types/module.ts +++ b/src/types/module.ts @@ -1,6 +1,6 @@ -import type { Nitro } from "./nitro"; +import type { Nitro } from "./nitro.ts"; -export type NitroModuleInput = string | NitroModule | NitroModule["setup"]; +export type NitroModuleInput = string | NitroModule | NitroModule["setup"] | { nitro: NitroModule }; export interface NitroModule { name?: string; diff --git a/src/types/nitro.ts b/src/types/nitro.ts index 65106da025..bb26574c5b 100644 --- a/src/types/nitro.ts +++ b/src/types/nitro.ts @@ -1,37 +1,47 @@ import type { ConsolaInstance } from "consola"; -import type { RouterMethod } from "h3"; +import type { HTTPMethod } from "h3"; import type { Hookable } from "hookable"; -import type { PresetName, PresetOptions } from "nitropack/presets"; +import type { PresetName, PresetOptions } from "../presets/index.ts"; import type { Unimport } from "unimport"; -import type { Storage } from "unstorage"; -import type { NitroConfig, NitroOptions } from "./config"; -import type { NitroEventHandler } from "./handler"; -import type { NitroHooks } from "./hooks"; -import type { PrerenderRoute } from "./prerender"; +import type { NitroConfig, NitroOptions } from "./config.ts"; +import type { NitroEventHandler } from "./handler.ts"; +import type { NitroHooks } from "./hooks.ts"; +import type { PrerenderRoute } from "./prerender.ts"; +import type { TSConfig } from "pkg-types"; +import type { Router } from "../routing.ts"; +import type { NitroRouteRules } from "./route-rules.ts"; +import type { WorkerAddress } from "./runner.ts"; + +type MaybeArray = T | T[]; export interface Nitro { options: NitroOptions; scannedHandlers: NitroEventHandler[]; - vfs: Record; + vfs: Map string | Promise }>; hooks: Hookable; unimport?: Unimport; logger: ConsolaInstance; - storage: Storage; + fetch: (input: Request) => Response | Promise; close: () => Promise; updateConfig: (config: NitroDynamicConfig) => void | Promise; + routing: Readonly<{ + sync: () => void; + routeRules: Router; + routes: Router>; + globalMiddleware: (NitroEventHandler & { _importHash: string })[]; + routedMiddleware: Router; + }>; /* @internal */ _prerenderedRoutes?: PrerenderRoute[]; _prerenderMeta?: Record; } -export type NitroDynamicConfig = Pick< - NitroConfig, - "runtimeConfig" | "routeRules" ->; +export type NitroDynamicConfig = Pick; export type NitroTypes = { - routes: Record>>; + routes: Record>>; + tsConfig?: TSConfig; }; export interface NitroFrameworkInfo { @@ -52,9 +62,11 @@ export interface NitroBuildInfo { preview?: string; deploy?: string; }; + serverEntry?: string; + publicDir?: string; dev?: { pid: number; - workerAddress?: { host: string; port: number; socketPath?: string }; + workerAddress?: WorkerAddress; }; config?: Partial; } diff --git a/src/types/openapi-ts.ts b/src/types/openapi-ts.ts new file mode 100644 index 0000000000..42ce3e5eaa --- /dev/null +++ b/src/types/openapi-ts.ts @@ -0,0 +1,642 @@ +/** +Source: (inlined because of install size concernes) + +https://github.com/openapi-ts/openapi-typescript/blob/fc3f7/packages/openapi-typescript/src/types.ts + +MIT License + +Copyright (c) 2020 Drew Powers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ + +// Many types allow for true “any” for inheritance to work + +export interface Extensable { + [key: `x-${string}`]: any; +} + +// Note: these OpenAPI types are meant only for internal use, not external +// consumption. Some formatting may be better in other libraries meant for +// consumption. Some typing may be “loose” or “incorrect” in order to guarantee +// that all logical paths are handled. In other words, these are built more +// for ways schemas _can_ be written, not necessarily how they _should_ be. + +/** + * [4.8] Schema + * @see https://spec.openapis.org/oas/v3.1.0#schema + */ +export interface OpenAPI3 extends Extensable { + /** REQUIRED. This string MUST be the version number of the OpenAPI Specification that the OpenAPI document uses. The openapi field SHOULD be used by tooling to interpret the OpenAPI document. This is not related to the API info.version string. */ + openapi: string; + /** REQUIRED. Provides metadata about the API. The metadata MAY be used by tooling as required. */ + info: InfoObject; // required + /** The default value for the $schema keyword within Schema Objects contained within this OAS document. This MUST be in the form of a URI. */ + jsonSchemaDialect?: string; + /** An array of Server Objects, which provide connectivity information to a target server. If the servers property is not provided, or is an empty array, the default value would be a Server Object with a url value of /. */ + servers?: ServerObject[]; + /** The available paths and operations for the API. */ + paths?: PathsObject; + /** The incoming webhooks that MAY be received as part of this API and that the API consumer MAY choose to implement. Closely related to the callbacks feature, this section describes requests initiated other than by an API call, for example by an out of band registration. The key name is a unique string to refer to each webhook, while the (optionally referenced) Path Item Object describes a request that may be initiated by the API provider and the expected responses. An example is available. */ + webhooks?: { [id: string]: PathItemObject | ReferenceObject }; + /** An element to hold various schemas for the document. */ + components?: ComponentsObject; + /** A declaration of which security mechanisms can be used across the API. The list of values includes alternative security requirement objects that can be used. Only one of the security requirement objects need to be satisfied to authorize a request. Individual operations can override this definition. To make security optional, an empty security requirement ({}) can be included in the array. */ + security?: SecurityRequirementObject[]; + /** A list of tags used by the document with additional metadata. The order of the tags can be used to reflect on their order by the parsing tools. Not all tags that are used by the Operation Object must be declared. The tags that are not declared MAY be organized randomly or based on the tools’ logic. Each tag name in the list MUST be unique. */ + tags?: TagObject[]; + /** Additional external documentation. */ + externalDocs?: ExternalDocumentationObject; + $defs?: $defs; +} + +/** + * [4.8.2] Info Object + * The object provides metadata about the API. + */ +export interface InfoObject extends Extensable { + /** REQUIRED. The title of the API. */ + title: string; + /** A short summary of the API. */ + summary?: string; + /** A description of the API. CommonMark syntax MAY be used for rich text representation. */ + description?: string; + /** A URL to the Terms of Service for the API. This MUST be in the form of a URL. */ + termsOfService?: string; + /** The contact information for the exposed API. */ + contact?: ContactObject; + /** The license information for the exposed API. */ + license?: LicenseObject; + /** REQUIRED. The version of the OpenAPI document (which is distinct from the OpenAPI Specification version or the API implementation version). */ + version: string; +} + +/** + * [4.8.3] Contact Object + * Contact information for the exposed API. + */ +export interface ContactObject extends Extensable { + /** The identifying name of the contact person/organization. */ + name?: string; + /** The URL pointing to the contact information. This MUST be in the form of a URL. */ + url?: string; + /** The email address of the contact person/organization. This MUST be in the form of an email address. */ + email?: string; +} + +/** + * [4.8.4] License object + * License information for the exposed API. + */ +export interface LicenseObject extends Extensable { + /** REQUIRED. The license name used for the API. */ + name: string; + /** An SPDX license expression for the API. The identifier field is mutually exclusive of the url field. */ + identifier: string; + /** A URL to the license used for the API. This MUST be in the form of a URL. The url field is mutually exclusive of the identifier field. */ + url: string; +} + +/** + * [4.8.5] Server Object + * An object representing a Server. + */ +export interface ServerObject extends Extensable { + /** REQUIRED. A URL to the target host. This URL supports Server Variables and MAY be relative, to indicate that the host location is relative to the location where the OpenAPI document is being served. Variable substitutions will be made when a variable is named in {brackets}. */ + url: string; + /** An optional string describing the host designated by the URL. CommonMark syntax MAY be used for rich text representation. */ + description: string; + /** A map between a variable name and its value. The value is used for substitution in the server’s URL template. */ + variables: { [name: string]: ServerVariableObject }; +} + +/** + * [4.8.6] Server Variable Object + * An object representing a Server Variable for server URL template substitution. + */ +export interface ServerVariableObject extends Extensable { + /** An enumeration of string values to be used if the substitution options are from a limited set. The array MUST NOT be empty. */ + enum?: string[]; + /** REQUIRED. The default value to use for substitution, which SHALL be sent if an alternate value is not supplied. Note this behavior is different than the Schema Object’s treatment of default values, because in those cases parameter values are optional. If the enum is defined, the value MUST exist in the enum’s values. */ + default: string; + /** An optional description for the server variable. CommonMark syntax MAY be used for rich text representation. */ + description?: string; +} + +/** + * [4.8.7] Components Object + * Holds a set of reusable objects for different aspects of the OAS. + */ +export interface ComponentsObject extends Extensable { + /** An object to hold reusable Schema Objects.*/ + schemas?: Record; + /** An object to hold reusable Response Objects. */ + responses?: Record; + /** An object to hold reusable Parameter Objects. */ + parameters?: Record; + /** An object to hold reusable Example Objects. */ + examples?: Record; + /** An object to hold reusable Request Body Objects. */ + requestBodies?: Record; + /** An object to hold reusable Header Objects. */ + headers?: Record; + /** An object to hold reusable Security Scheme Objects. */ + securitySchemes?: Record; + /** An object to hold reusable Link Objects. */ + links?: Record; + /** An object to hold reusable Callback Objects. */ + callbacks?: Record; + /** An object to hold reusable Path Item Objects. */ + pathItems?: Record; +} + +/** + * [4.8.8] Paths Object + * Holds the relative paths to the individual endpoints and their operations. The path is appended to the URL from the Server Object in order to construct the full URL. The Paths MAY be empty, due to Access Control List (ACL) constraints. + */ +export interface PathsObject { + [pathname: string]: PathItemObject | ReferenceObject; // note: paths object does support $refs; the schema just defines it in a weird way +} + +/** + * [x.x.x] Webhooks Object + * Holds the webhooks definitions, indexed by their names. A webhook is defined by a Path Item Object; the only difference is that the request is initiated by the API provider. + */ +export interface WebhooksObject { + [name: string]: PathItemObject; +} + +/** + * [4.8.9] Path Item Object + * Describes the operations available on a single path. A Path Item MAY be empty, due to ACL constraints. The path itself is still exposed to the documentation viewer but they will not know which operations and parameters are available. + */ +export interface PathItemObject extends Extensable { + /** A definition of a GET operation on this path. */ + get?: OperationObject | ReferenceObject; + /** A definition of a PUT operation on this path. */ + put?: OperationObject | ReferenceObject; + /** A definition of a POST operation on this path. */ + post?: OperationObject | ReferenceObject; + /** A definition of a DELETE operation on this path. */ + delete?: OperationObject | ReferenceObject; + /** A definition of a OPTIONS operation on this path. */ + options?: OperationObject | ReferenceObject; + /** A definition of a HEAD operation on this path. */ + head?: OperationObject | ReferenceObject; + /** A definition of a PATCH operation on this path. */ + patch?: OperationObject | ReferenceObject; + /** A definition of a TRACE operation on this path. */ + trace?: OperationObject | ReferenceObject; + /** An alternative server array to service all operations in this path. */ + servers?: ServerObject[]; + /** A list of parameters that are applicable for all the operations described under this path. These parameters can be overridden at the operation level, but cannot be removed there. The list MUST NOT include duplicated parameters. A unique parameter is defined by a combination of a name and location. The list can use the Reference Object to link to parameters that are defined at the OpenAPI Object’s components/parameters. */ + parameters?: (ParameterObject | ReferenceObject)[]; +} + +/** + * [4.8.10] Operation Object + * Describes a single API operation on a path. + */ +export interface OperationObject extends Extensable { + /** A list of tags for API documentation control. Tags can be used for logical grouping of operations by resources or any other qualifier. */ + tags?: string[]; + /** A short summary of what the operation does. */ + summary?: string; + /** A verbose explanation of the operation behavior. CommonMark syntax MAY be used for rich text representation. */ + description?: string; + /** Additional external documentation for this operation. */ + externalDocs?: ExternalDocumentationObject; + /** Unique string used to identify the operation. The id MUST be unique among all operations described in the API. The operationId value is case-sensitive. Tools and libraries MAY use the operationId to uniquely identify an operation, therefore, it is RECOMMENDED to follow common programming naming conventions. */ + operationId?: string; + /** A list of parameters that are applicable for this operation. If a parameter is already defined at the Path Item, the new definition will override it but can never remove it. The list MUST NOT include duplicated parameters. A unique parameter is defined by a combination of a name and location. The list can use the Reference Object to link to parameters that are defined at the OpenAPI Object’s components/parameters. */ + parameters?: (ParameterObject | ReferenceObject)[]; + /** The request body applicable for this operation. The requestBody is fully supported in HTTP methods where the HTTP 1.1 specification [RFC7231] has explicitly defined semantics for request bodies. In other cases where the HTTP spec is vague (such as GET, HEAD and DELETE), requestBody is permitted but does not have well-defined semantics and SHOULD be avoided if possible. */ + requestBody?: RequestBodyObject | ReferenceObject; + /** The list of possible responses as they are returned from executing this operation. */ + responses?: ResponsesObject; + /** A map of possible out-of band callbacks related to the parent operation. The key is a unique identifier for the Callback Object. Each value in the map is a Callback Object that describes a request that may be initiated by the API provider and the expected responses. */ + callbacks?: Record; + /** Declares this operation to be deprecated. Consumers SHOULD refrain from usage of the declared operation. Default value is false. */ + deprecated?: boolean; + /** A declaration of which security mechanisms can be used for this operation. The list of values includes alternative security requirement objects that can be used. Only one of the security requirement objects need to be satisfied to authorize a request. To make security optional, an empty security requirement ({}) can be included in the array. This definition overrides any declared top-level security. To remove a top-level security declaration, an empty array can be used. */ + security?: SecurityRequirementObject[]; + /** An alternative server array to service this operation. If an alternative server object is specified at the Path Item Object or Root level, it will be overridden by this value. */ + servers?: ServerObject[]; +} + +/** + * [4.8.11] External Documentation Object + * Allows referencing an external resource for extended documentation. + */ +export interface ExternalDocumentationObject extends Extensable { + /** A description of the target documentation. CommonMark syntax MAY be used for rich text representation. */ + description?: string; + /** REQUIRED. The URL for the target documentation. This MUST be in the form of a URL. */ + url: string; +} + +/** + * [4.8.12] Parameter Object + * Describes a single operation parameter. + * A unique parameter is defined by a combination of a name and location. + */ +export interface ParameterObject extends Extensable { + /** + * REQUIRED. The name of the parameter. Parameter names are case sensitive. + * + * - If `in` is `"path"`, the `name` field MUST correspond to a template expression occurring within the path field in the Paths Object. See Path Templating for further information. + * - If `in` is `"header"` and the `name` field is `"Accept"`, `"Content-Type"` or `"Authorization"`, the parameter definition SHALL be ignored. + * - For all other cases, the `name` corresponds to the parameter name used by the `in` property. + */ + name: string; + /** REQUIRED. The location of the parameter. Possible values are "query", "header", "path" or "cookie".*/ + in: "query" | "header" | "path" | "cookie"; + /** A brief description of the parameter. This could contain examples of use. CommonMark syntax MAY be used for rich text representation. */ + description?: string; + /** Determines whether this parameter is mandatory. If the parameter location is "path", this property is REQUIRED and its value MUST be true. Otherwise, the property MAY be included and its default value is false. */ + required?: boolean; + /** Specifies that a parameter is deprecated and SHOULD be transitioned out of usage. Default value is false. */ + deprecated?: boolean; + /** Sets the ability to pass empty-valued parameters. This is valid only for query parameters and allows sending a parameter with an empty value. Default value is false. If style is used, and if behavior is n/a (cannot be serialized), the value of allowEmptyValue SHALL be ignored. Use of this property is NOT RECOMMENDED, as it is likely to be removed in a later revision. */ + allowEmptyValue?: boolean; + /** Describes how the parameter value will be serialized depending on the type of the parameter value. Default values (based on value of in): for query - form; for path - simple; for header - simple; for cookie - form. */ + style?: string; + /** When this is true, parameter values of type `array` or `object` generate separate parameters for each value of the array or key-value pair of the map. For other types of parameters this property has no effect. When `style` is `form`, the default value is `true`. For all other styles, the default value is `false`. */ + explode?: boolean; + /** Determines whether the parameter value SHOULD allow reserved characters, as defined by [RFC3986] `:/?#[]@!$&'()*+,;=` to be included without percent-encoding. This property only applies to parameters with an `in` value of `query`. The default value is `false`. */ + allowReserved?: boolean; + /** The schema defining the type used for the parameter. */ + schema?: SchemaObject; + /** Example of the parameter’s potential value. */ + example?: any; + /** Examples of the parameter’s potential value. */ + examples?: { [name: string]: ExampleObject | ReferenceObject }; + /** A map containing the representations for the parameter. */ + content?: { [contentType: string]: MediaTypeObject | ReferenceObject }; +} + +/** + * [4.8.13] Request Body Object + * Describes a single request body. + */ +export interface RequestBodyObject extends Extensable { + /** A brief description of the request body. This could contain examples of use. CommonMark syntax MAY be used for rich text representation. */ + description?: string; + /** REQUIRED. The content of the request body. The key is a media type or media type range and the value describes it. For requests that match multiple keys, only the most specific key is applicable. e.g. text/plain overrides text */ + content: { [contentType: string]: MediaTypeObject | ReferenceObject }; + /** Determines if the request body is required in the request. Defaults to false. */ + required?: boolean; +} + +/** + * [4.8.14] Media Type Object + */ +export interface MediaTypeObject extends Extensable { + /** The schema defining the content of the request, response, or parameter. */ + schema?: SchemaObject | ReferenceObject; + /** Example of the media type. The example object SHOULD be in the correct format as specified by the media type. The example field is mutually exclusive of the examples field. Furthermore, if referencing a schema which contains an example, the example value SHALL override the example provided by the schema. */ + example?: any; + /** Examples of the media type. Each example object SHOULD match the media type and specified schema if present. The examples field is mutually exclusive of the example field. Furthermore, if referencing a schema which contains an example, the examples value SHALL override the example provided by the schema. */ + examples?: { [name: string]: ExampleObject | ReferenceObject }; + /** A map between a property name and its encoding information. The key, being the property name, MUST exist in the schema as a property. The encoding object SHALL only apply to requestBody objects when the media type is multipart or application/x-www-form-urlencoded. */ + encoding?: { [propertyName: string]: EncodingObject }; +} + +/** + * [4.8.15] Encoding Object + * A single encoding definition applied to a single schema property. + */ +export interface EncodingObject extends Extensable { + /** The Content-Type for encoding a specific property. Default value depends on the property type: for object - application/json; for array – the default is defined based on the inner type; for all other cases the default is application/octet-stream. The value can be a specific media type (e.g. application/json), a wildcard media type (e.g. image/*), or a comma-separated list of the two types. */ + contentType?: string; + /** A map allowing additional information to be provided as headers, for example Content-Disposition. Content-Type is described separately and SHALL be ignored in this section. This property SHALL be ignored if the request body media type is not a multipart. */ + headers?: { [name: string]: HeaderObject | ReferenceObject }; + /** Describes how a specific property value will be serialized depending on its type. See Parameter Object for details on the style property. The behavior follows the same values as query parameters, including default values. This property SHALL be ignored if the request body media type is not application/x-www-form-urlencoded or multipart/form-data. If a value is explicitly defined, then the value of contentType (implicit or explicit) SHALL be ignored. */ + style?: string; + /** When this is true, property values of type array or object generate separate parameters for each value of the array, or key-value-pair of the map. For other types of properties this property has no effect. When style is form, the default value is true. For all other styles, the default value is false. This property SHALL be ignored if the request body media type is not application/x-www-form-urlencoded or multipart/form-data. If a value is explicitly defined, then the value of contentType (implicit or explicit) SHALL be ignored. */ + explode?: string; + /** Determines whether the parameter value SHOULD allow reserved characters, as defined by [RFC3986] :/?#[]@!$&'()*+,;= to be included without percent-encoding. The default value is false. This property SHALL be ignored if the request body media type is not application/x-www-form-urlencoded or multipart/form-data. If a value is explicitly defined, then the value of contentType (implicit or explicit) SHALL be ignored. */ + allowReserved?: string; +} + +/** + * [4.8.16] Responses Object + * A container for the expected responses of an operation. The container maps a HTTP response code to the expected response. + */ +export type ResponsesObject = { + [responseCode: string]: ResponseObject | ReferenceObject; +} & { + /** The documentation of responses other than the ones declared for specific HTTP response codes. Use this field to cover undeclared responses. */ + default?: ResponseObject | ReferenceObject; +}; + +/** + * [4.8.17] Response Object + * Describes a single response from an API Operation, including design-time, static links to operations based on the response. + */ +export interface ResponseObject extends Extensable { + /** REQUIRED. A description of the response. CommonMark syntax MAY be used for rich text representation. */ + description: string; + /** Maps a header name to its definition. [RFC7230] states header names are case insensitive. If a response header is defined with the name "Content-Type", it SHALL be ignored. */ + headers?: { [name: string]: HeaderObject | ReferenceObject }; + /** A map containing descriptions of potential response payloads. The key is a media type or media type range and the value describes it. For responses that match multiple keys, only the most specific key is applicable. e.g. text/plain overrides text */ + content?: { [contentType: string]: MediaTypeObject }; + /** A map of operations links that can be followed from the response. The key of the map is a short name for the link, following the naming constraints of the names for Component Objects. */ + links?: { [name: string]: LinkObject | ReferenceObject }; +} + +/** + * [4.8.18] Callback Object + * A map of possible out-of band callbacks related to the parent operation. Each value in the map is a Path Item Object that describes a set of requests that may be initiated by the API provider and the expected responses. The key value used to identify the path item object is an expression, evaluated at runtime, that identifies a URL to use for the callback operation. + */ +export type CallbackObject = Record; + +/** + * [4.8.19[ Example Object + */ +export interface ExampleObject extends Extensable { + /** Short description for the example. */ + summary?: string; + /** Long description for the example. CommonMark syntax MAY be used for rich text representation. */ + description?: string; + /** Embedded literal example. The value field and externalValue field are mutually exclusive. To represent examples of media types that cannot naturally represented in JSON or YAML, use a string value to contain the example, escaping where necessary. */ + value?: any; + /** A URI that points to the literal example. This provides the capability to reference examples that cannot easily be included in JSON or YAML documents. The value field and externalValue field are mutually exclusive. See the rules for resolving Relative References. */ + externalValue?: string; +} + +/** + * [4.8.20] Link Object + * The Link object represents a possible design-time link for a response. The presence of a link does not guarantee the caller’s ability to successfully invoke it, rather it provides a known relationship and traversal mechanism between responses and other operations. + */ +export interface LinkObject extends Extensable { + /** A relative or absolute URI reference to an OAS operation. This field is mutually exclusive of the operationId field, and MUST point to an Operation Object. Relative operationRef values MAY be used to locate an existing Operation Object in the OpenAPI definition. See the rules for resolving Relative References. */ + operationRef?: string; + /** The name of an existing, resolvable OAS operation, as defined with a unique operationId. This field is mutually exclusive of the operationRef field. */ + operationId?: string; + /** A map representing parameters to pass to an operation as specified with operationId or identified via operationRef. The key is the parameter name to be used, whereas the value can be a constant or an expression to be evaluated and passed to the linked operation. The parameter name can be qualified using the parameter location [{in}.]{name} for operations that use the same parameter name in different locations (e.g. path.id). */ + parameters?: { [name: string]: `$${string}` }; + /** A literal value or {expression} to use as a request body when calling the target operation. */ + requestBody?: `$${string}`; + /** A description of the link. CommonMark syntax MAY be used for rich text representation. */ + description?: string; + /** A server object to be used by the target operation. */ + server?: ServerObject; +} + +/** + * [4.8.21] Header Object + * The Header Object follows the structure of the Parameter Object with the following changes: + * + * 1. `name` MUST NOT be specified, it is given in the corresponding `headers` map. + * 2. `in` MUST NOT be specified, it is implicitly in `header`. + * 3. All traits that are affected by the location MUST be applicable to a location of `heade`r (for example, `style`). + */ +export type HeaderObject = Omit; + +/** + * [4.8.22] Tag Object + * Adds metadata to a single tag that is used by the Operation Object. It is not mandatory to have a Tag Object per tag defined in the Operation Object instances. + */ +export interface TagObject extends Extensable { + /** REQUIRED. The name of the tag. */ + name: string; + /** A description for the tag. CommonMark syntax MAY be used for rich text representation. */ + description?: string; + /** Additional external documentation for this tag. */ + externalDocs?: ExternalDocumentationObject; +} + +/** + * [4.8.23] Reference Object + * A simple object to allow referencing other components in the OpenAPI document, internally and externally. The $ref string value contains a URI [RFC3986], which identifies the location of the value being referenced. See the rules for resolving Relative References. + */ +export interface ReferenceObject extends Extensable { + /** REQUIRED. The reference identifier. This MUST be in the form of a URI. */ + $ref: string; + /** A short summary which by default SHOULD override that of the referenced component. If the referenced object-type does not allow a summary field, then this field has no effect. */ + summary?: string; + /** A description which by default SHOULD override that of the referenced component. CommonMark syntax MAY be used for rich text representation. If the referenced object-type does not allow a description field, then this field has no effect. */ + description?: string; +} + +/** + * [4.8.24] Schema Object + * The Schema Object allows the definition of input and output data types. These types can be objects, but also primitives and arrays. This object is a superset of the JSON Schema Specification Draft 2020-12. + */ +export type SchemaObject = { + /** The Schema Object allows the definition of input and output data types. These types can be objects, but also primitives and arrays. This object is a superset of the JSON Schema Specification Draft 2020-12. */ + discriminator?: DiscriminatorObject; + /** MAY be used only on properties schemas. It has no effect on root schemas. Adds additional metadata to describe the XML representation of this property. */ + xml?: XMLObject; + /** Additional external documentation for this schema. */ + externalDocs?: ExternalDocumentationObject; + /** @deprecated */ + example?: any; + title?: string; + description?: string; + $comment?: string; + deprecated?: boolean; + readOnly?: boolean; + writeOnly?: boolean; + enum?: unknown[]; + /** Use of this keyword is functionally equivalent to an "enum" (Section 6.1.2) with a single value. */ + const?: unknown; + default?: unknown; + format?: string; + /** @deprecated in 3.1 (still valid for 3.0) */ + nullable?: boolean; + oneOf?: (SchemaObject | ReferenceObject)[]; + allOf?: (SchemaObject | ReferenceObject)[]; + anyOf?: (SchemaObject | ReferenceObject)[]; + required?: string[]; + [key: `x-${string}`]: any; +} & ( + | StringSubtype + | NumberSubtype + | IntegerSubtype + | ArraySubtype + | BooleanSubtype + | NullSubtype + | ObjectSubtype + | { + type: ("string" | "number" | "integer" | "array" | "boolean" | "null" | "object")[]; + } +); + +export interface StringSubtype { + type: "string" | ["string", "null"]; + enum?: (string | ReferenceObject)[]; +} + +export interface NumberSubtype { + type: "number" | ["number", "null"]; + minimum?: number; + maximum?: number; + enum?: (number | ReferenceObject)[]; +} + +export interface IntegerSubtype { + type: "integer" | ["integer", "null"]; + minimum?: number; + maximum?: number; + enum?: (number | ReferenceObject)[]; +} + +export interface ArraySubtype { + type: "array" | ["array", "null"]; + prefixItems?: (SchemaObject | ReferenceObject)[]; + items?: SchemaObject | ReferenceObject | (SchemaObject | ReferenceObject)[]; + minItems?: number; + maxItems?: number; + enum?: (SchemaObject | ReferenceObject)[]; +} + +export interface BooleanSubtype { + type: "boolean" | ["boolean", "null"]; + enum?: (boolean | ReferenceObject)[]; +} + +export interface NullSubtype { + type: "null"; +} + +export interface ObjectSubtype { + type: "object" | ["object", "null"]; + properties?: { [name: string]: SchemaObject | ReferenceObject }; + additionalProperties?: boolean | Record | SchemaObject | ReferenceObject; + required?: string[]; + allOf?: (SchemaObject | ReferenceObject)[]; + anyOf?: (SchemaObject | ReferenceObject)[]; + enum?: (SchemaObject | ReferenceObject)[]; + $defs?: $defs; +} + +/** + * [4.8.25] Discriminator Object + * When request bodies or response payloads may be one of a number of different schemas, a discriminator object can be used to aid in serialization, deserialization, and validation. The discriminator is a specific object in a schema which is used to inform the consumer of the document of an alternative schema based on the value associated with it. + */ +export interface DiscriminatorObject { + /** REQUIRED. The name of the property in the payload that will hold the discriminator value. */ + propertyName: string; + /** An object to hold mappings between payload values and schema names or references. */ + mapping?: Record; + /** If this exists, then a discriminator type should be added to objects matching this path */ + oneOf?: string[]; +} + +/** + * [4.8.26] XML Object + * A metadata object that allows for more fine-tuned XML model definitions. When using arrays, XML element names are not inferred (for singular/plural forms) and the `name` property SHOULD be used to add that information. See examples for expected behavior. + */ +export interface XMLObject extends Extensable { + /** Replaces the name of the element/attribute used for the described schema property. When defined within `items`, it will affect the name of the individual XML elements within the list. When defined alongside `type` being `array` (outside the `items`), it will affect the wrapping element and only if `wrapped` is `true`. If `wrapped` is `false`, it will be ignored. */ + name?: string; + /** The URI of the namespace definition. This MUST be in the form of an absolute URI. */ + namespace?: string; + /** The prefix to be used for the name. */ + prefix?: string; + /** Declares whether the property definition translates to an attribute instead of an element. Default value is `false`. */ + attribute?: boolean; + /** MAY be used only for an array definition. Signifies whether the array is wrapped (for example, ``) or unwrapped (``). Default value is `false`. The definition takes effect only when defined alongside `type` being `array` (outside the `items`). */ + wrapped?: boolean; +} + +/** + * [4.8.27] Security Scheme Object + * Defines a security scheme that can be used by the operations. + */ +export type SecuritySchemeObject = { + /** A description for security scheme. CommonMark syntax MAY be used for rich text representation. */ + description?: string; + [key: `x-${string}`]: any; +} & ( + | { + /** REQUIRED. The type of the security scheme. */ + type: "apiKey"; + /** REQUIRED. The name of the header, query or cookie parameter to be used. */ + name: string; + /** REQUIRED. The location of the API key. */ + in: "query" | "header" | "cookie"; + } + | { + /** REQUIRED. The type of the security scheme. */ + type: "http"; + /** REQUIRED. The name of the HTTP Authorization scheme to be used in the Authorization header as defined in [RFC7235]. The values used SHOULD be registered in the IANA Authentication Scheme registry. */ + scheme: string; + /** A hint to the client to identify how the bearer token is formatted. Bearer tokens are usually generated by an authorization server, so this information is primarily for documentation purposes. */ + bearer?: string; + } + | { + /** REQUIRED. The type of the security scheme. */ + type: "mutualTLS"; + } + | { + /** REQUIRED. Tye type of the security scheme. */ + type: "oauth2"; + /** REQUIRED. An object containing configuration information for the flow types supported. */ + flows: OAuthFlowsObject; + } + | { + /** REQUIRED. Tye type of the security scheme. */ + type: "openIdConnect"; + /** REQUIRED. OpenId Connect URL to discover OAuth2 configuration values. This MUST be in the form of a URL. The OpenID Connect standard requires the use of TLS. */ + openIdConnectUrl: string; + } +); + +/** + * [4.8.26] OAuth Flows Object + * Allows configuration of the supported OAuth Flows. + */ +export interface OAuthFlowsObject extends Extensable { + /** Configuration for the OAuth Implicit flow */ + implicit?: OAuthFlowObject; + /** Configuration for the OAuth Resource Owner Password flow */ + password?: OAuthFlowObject; + /** Configuration for the OAuth Client Credentials flow. Previously called `application` in OpenAPI 2.0. */ + clientCredentials?: OAuthFlowObject; + /** Configuration for the OAuth Authorization Code flow. Previously called `accessCode` in OpenAPI 2.0. */ + authorizationCode?: OAuthFlowObject; +} + +/** + * [4.8.29] OAuth Flow Object + * Configuration details for a supported OAuth Flow + */ +export interface OAuthFlowObject extends Extensable { + /** REQUIRED. The authorization URL to be used for this flow. This MUST be in the form of a URL. The OAuth2 standard requires the use of TLS. */ + authorizationUrl: string; + /** REQUIRED. The token URL to be used for this flow. This MUST be in the form of a URL. The OAuth2 standard requires the use of TLS. */ + tokenUrl: string; + /** The URL to be used for obtaining refresh tokens. This MUST be in the form of a URL. The OAuth2 standard requires the use of TLS. */ + refreshUrl: string; + /** REQUIRED. The available scopes for the OAuth2 security scheme. A map between the scope name and a short description for it. The map MAY be empty. */ + scopes: { [name: string]: string }; +} + +/** + * [4.8.30] Security Requirements Object + * Lists the required security schemes to execute this operation. The name used for each property MUST correspond to a security scheme declared in the Security Schemes under the Components Object. + */ +export type SecurityRequirementObject = { + [P in keyof ComponentsObject["securitySchemes"]]?: string[]; +}; + +export type $defs = Record; diff --git a/src/types/openapi.ts b/src/types/openapi.ts index 6e232b8c7c..3dbdca4bd9 100644 --- a/src/types/openapi.ts +++ b/src/types/openapi.ts @@ -1,4 +1,4 @@ -import type { ReferenceConfiguration as ScalarConfig } from "@scalar/api-reference"; +// import type { ApiReferenceConfiguration as ScalarConfig } from "@scalar/api-reference"; /** * Nitro OpenAPI configuration @@ -34,7 +34,7 @@ export interface NitroOpenAPIConfig { */ scalar?: | false - | (ScalarConfig & { + | (Partial & { /** * Scalar UI route * diff --git a/src/types/prerender.ts b/src/types/prerender.ts index 7ea0c5afef..f30f248eeb 100644 --- a/src/types/prerender.ts +++ b/src/types/prerender.ts @@ -1,9 +1,11 @@ +import type { HTTPError } from "h3"; + export interface PrerenderRoute { route: string; contents?: string; data?: ArrayBuffer; fileName?: string; - error?: Error & { statusCode: number; statusMessage: string }; + error?: Partial; generateTimeMS?: number; skip?: boolean; contentType?: string; diff --git a/src/types/preset.ts b/src/types/preset.ts index 9f9744f03a..b92ac9b783 100644 --- a/src/types/preset.ts +++ b/src/types/preset.ts @@ -1,14 +1,14 @@ import type { DateString } from "compatx"; import type { ProviderName } from "std-env"; -import type { NitroConfig } from "./config"; +import type { NitroConfig } from "./config.ts"; export type NitroPreset = NitroConfig | (() => NitroConfig); export interface NitroPresetMeta { - url: string; name: string; stdName?: ProviderName; aliases?: string[]; static?: boolean; + dev?: boolean; compatibilityDate?: DateString; } diff --git a/src/types/rollup.ts b/src/types/rollup.ts deleted file mode 100644 index 7ace692e7d..0000000000 --- a/src/types/rollup.ts +++ /dev/null @@ -1,66 +0,0 @@ -import type { FilterPattern } from "unplugin-utils"; -import type { NodeFileTraceOptions } from "@vercel/nft"; -import type { Loader as ESBuildLoader } from "esbuild"; -import type { TransformOptions as ESBuildTransformOptions } from "esbuild"; -import type { - InputOptions as RollupInputOptions, - OutputOptions as RollupOutputOptions, -} from "rollup"; - -export type RollupConfig = RollupInputOptions & { - output: RollupOutputOptions; -}; - -export type VirtualModule = string | (() => string | Promise); - -export interface RollupVirtualOptions { - [id: string]: VirtualModule; -} - -export interface EsbuildOptions extends ESBuildTransformOptions { - include?: FilterPattern; - exclude?: FilterPattern; - sourceMap?: boolean | "inline" | "hidden"; - /** - * Map extension to esbuild loader - * Note that each entry (the extension) needs to start with a dot - */ - loaders?: { - [ext: string]: ESBuildLoader | false; - }; -} - -export interface NodeExternalsOptions { - inline?: Array< - | string - | RegExp - | ((id: string, importer?: string) => Promise | boolean) - >; - external?: Array< - | string - | RegExp - | ((id: string, importer?: string) => Promise | boolean) - >; - rootDir?: string; - outDir: string; - trace?: boolean; - traceOptions?: NodeFileTraceOptions; - moduleDirectories?: string[]; - exportConditions?: string[]; - traceInclude?: string[]; - traceAlias?: Record; -} - -export interface ServerAssetOptions { - inline: boolean; - dirs: { - [assetdir: string]: { - dir: string; - meta?: boolean; - }; - }; -} - -export interface RawOptions { - extensions?: string[]; -} diff --git a/src/types/route-rules.ts b/src/types/route-rules.ts index 50771724b6..a158b5a3ac 100644 --- a/src/types/route-rules.ts +++ b/src/types/route-rules.ts @@ -1,16 +1,17 @@ -import type { ProxyOptions, RouterMethod } from "h3"; -import type { ExcludeFunctions, IntRange } from "./_utils"; -import type { CachedEventHandlerOptions } from "./runtime"; +import type { Middleware, ProxyOptions, BasicAuthOptions } from "h3"; +import type { ExcludeFunctions, IntRange } from "./_utils.ts"; +import type { CachedEventHandlerOptions } from "./runtime/index.ts"; -export type HTTPStatusCode = IntRange<100, 600>; +export type HTTPstatus = IntRange<100, 600>; export interface NitroRouteConfig { cache?: ExcludeFunctions | false; headers?: Record; - redirect?: string | { to: string; statusCode?: HTTPStatusCode }; + redirect?: string | { to: string; status?: HTTPstatus }; prerender?: boolean; proxy?: string | ({ to: string } & ProxyOptions); isr?: number /* expiration */ | boolean | VercelISRConfig; + basicAuth?: Pick | false; // Shortcuts cors?: boolean; @@ -18,13 +19,29 @@ export interface NitroRouteConfig { static?: boolean | number; } -export interface NitroRouteRules - extends Omit { - redirect?: { to: string; statusCode: HTTPStatusCode }; +export interface NitroRouteRules extends Omit< + NitroRouteConfig, + "redirect" | "cors" | "swr" | "static" +> { + redirect?: { to: string; status: HTTPstatus }; proxy?: { to: string } & ProxyOptions; + [key: string]: any; } -interface VercelISRConfig { +export type MatchedRouteRule = { + name: K; + options: Exclude; + route: string; + params?: Record; + handler?: (opts: unknown) => Middleware; +}; + +export type MatchedRouteRules = { + [K in keyof NitroRouteRules]: MatchedRouteRule; +}; + +// https://vercel.com/docs/build-output-api/primitives#prerender-configuration-file +export interface VercelISRConfig { /** * (vercel) * Expiration time (in seconds) before the cached asset will be re-generated by invoking the Serverless Function. @@ -53,4 +70,11 @@ interface VercelISRConfig { * When `true`, the query string will be present on the `request` argument passed to the invoked function. The `allowQuery` filter still applies. */ passQuery?: boolean; + + /** + * (vercel) + * + * When `true`, expose the response body regardless of status code including error status codes. (default `false`) + */ + exposeErrBody?: boolean; } diff --git a/src/types/runner.ts b/src/types/runner.ts new file mode 100644 index 0000000000..21adf1b309 --- /dev/null +++ b/src/types/runner.ts @@ -0,0 +1,9 @@ +export type { + FetchHandler, + RunnerMessageListener, + UpgradeHandler, + RunnerRPCHooks, + WorkerAddress, + WorkerHooks, + EnvRunner, +} from "env-runner"; diff --git a/src/types/runtime/cache.ts b/src/types/runtime/cache.ts index 5cc6b39a82..ee6459c007 100644 --- a/src/types/runtime/cache.ts +++ b/src/types/runtime/cache.ts @@ -1,41 +1,8 @@ -import type { H3Event } from "h3"; +import type { HTTPEvent } from "h3"; -export interface CacheEntry { - value?: T; - expires?: number; - mtime?: number; - integrity?: string; -} +export type { CacheEntry, CacheOptions, ResponseCacheEntry } from "ocache"; -export interface CacheOptions { - name?: string; - getKey?: (...args: ArgsT) => string | Promise; - transform?: (entry: CacheEntry, ...args: ArgsT) => any; - validate?: (entry: CacheEntry, ...args: ArgsT) => boolean; - shouldInvalidateCache?: (...args: ArgsT) => boolean | Promise; - shouldBypassCache?: (...args: ArgsT) => boolean | Promise; - group?: string; - integrity?: any; - /** - * Number of seconds to cache the response. Defaults to 1. - */ - maxAge?: number; - swr?: boolean; - staleMaxAge?: number; - base?: string; -} - -export interface ResponseCacheEntry { - body: T | undefined; - code: number; - headers: Record; -} - -export interface CachedEventHandlerOptions - extends Omit< - CacheOptions, [H3Event]>, - "transform" | "validate" - > { - headersOnly?: boolean; - varies?: string[] | readonly string[]; -} +export interface CachedEventHandlerOptions extends Omit< + import("ocache").CachedEventHandlerOptions, + "toResponse" | "createResponse" | "handleCacheHeaders" +> {} diff --git a/src/types/runtime/index.ts b/src/types/runtime/index.ts index 8aa208516e..618ddf5dd6 100644 --- a/src/types/runtime/index.ts +++ b/src/types/runtime/index.ts @@ -1,4 +1,4 @@ -export * from "./asset"; -export * from "./cache"; -export * from "./nitro"; -export * from "./task"; +export * from "./asset.ts"; +export * from "./cache.ts"; +export * from "./nitro.ts"; +export * from "./task.ts"; diff --git a/src/types/runtime/nitro.ts b/src/types/runtime/nitro.ts index 73e1834184..963f13d11c 100644 --- a/src/types/runtime/nitro.ts +++ b/src/types/runtime/nitro.ts @@ -1,53 +1,53 @@ -import type { App as H3App, H3Event, Router } from "h3"; -import type { Hookable } from "hookable"; -import type { NitroRuntimeHooks as NitroTypesRuntimeHooks } from "nitropack"; -import type { AbstractRequest, AbstractResponse } from "node-mock-http"; +import type { H3Core, HTTPEvent } from "h3"; +import type { HookableCore } from "hookable"; +import type { ServerRequest } from "srvx"; export interface NitroApp { - h3App: H3App; - router: Router; - hooks: Hookable; - localCall: (aRequest: AbstractRequest) => Promise; - localFetch: ( - req: string | URL | Request, - init?: RequestInit & AbstractRequest - ) => Promise; - captureError: CaptureError; + fetch: (req: Request) => Response | Promise; + h3?: H3Core; + hooks?: HookableCore; + captureError?: CaptureError; } export interface NitroAppPlugin { - (nitro: NitroApp): void; + ( + nitro: NitroApp & { + hooks: NonNullable; + } + ): void; } export interface NitroAsyncContext { - event: H3Event; + request: ServerRequest; } export interface RenderResponse { body: any; - statusCode: number; - statusMessage: string; + status: number; + statusText: string; headers: Record; } export type RenderHandler = ( - event: H3Event + event: HTTPEvent ) => Partial | Promise>; export interface RenderContext { - event: H3Event; + event: HTTPEvent; render: RenderHandler; response?: Partial; } export interface CapturedErrorContext { - event?: H3Event; - [key: string]: unknown; + event?: HTTPEvent; + tags?: string[]; } -export type CaptureError = ( - error: Error, - context: CapturedErrorContext -) => void; +export type CaptureError = (error: Error, context: CapturedErrorContext) => void; -export interface NitroRuntimeHooks extends NitroTypesRuntimeHooks {} +export interface NitroRuntimeHooks { + close: () => void; + error: CaptureError; + request: (event: HTTPEvent) => void | Promise; + response: (res: Response, event: HTTPEvent) => void | Promise; +} diff --git a/src/types/srvx.ts b/src/types/srvx.ts new file mode 100644 index 0000000000..4d2866bf14 --- /dev/null +++ b/src/types/srvx.ts @@ -0,0 +1 @@ +export type { ServerRequest } from "srvx"; diff --git a/src/types/virtual/app-config.d.ts b/src/types/virtual/app-config.d.ts deleted file mode 100644 index cdc35895ae..0000000000 --- a/src/types/virtual/app-config.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -import type { AppConfig } from "nitropack"; - -export const appConfig: AppConfig; diff --git a/src/types/virtual/error-handler.d.ts b/src/types/virtual/error-handler.d.ts deleted file mode 100644 index a307e918b7..0000000000 --- a/src/types/virtual/error-handler.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { NitroErrorHandler } from "nitropack/types"; - -type EParams = Parameters; -type EReturn = ReturnType; - -const errorHandler: (error: EParams[0], event: EParams[1]) => EReturn; - -export default errorHandler; diff --git a/src/types/virtual/plugins.d.ts b/src/types/virtual/plugins.d.ts deleted file mode 100644 index 505e8888ec..0000000000 --- a/src/types/virtual/plugins.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -import type { NitroAppPlugin } from "../plugin"; - -export const plugins: NitroAppPlugin[] = []; diff --git a/src/types/virtual/polyfills.ts b/src/types/virtual/polyfills.ts deleted file mode 100644 index ff8b4c5632..0000000000 --- a/src/types/virtual/polyfills.ts +++ /dev/null @@ -1 +0,0 @@ -export default {}; diff --git a/src/types/virtual/public-assets.d.ts b/src/types/virtual/public-assets.d.ts deleted file mode 100644 index 9f07b0dfa7..0000000000 --- a/src/types/virtual/public-assets.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const publicAssetBases: string[]; -export const isPublicAssetURL: (id: string) => boolean; -export const getPublicAssetMeta: (id: string) => { maxAge?: number }; -export const readAsset: (id: string) => Promise; -export const getAsset: (id: string) => PublicAsset; diff --git a/src/types/virtual/server-assets.d.ts b/src/types/virtual/server-assets.d.ts deleted file mode 100644 index b710273313..0000000000 --- a/src/types/virtual/server-assets.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function readAsset(id: string): Promise; -export function statAsset(id: string): Promise; -export function getKeys(): Promise; diff --git a/src/types/virtual/server-handlers-meta.d.ts b/src/types/virtual/server-handlers-meta.d.ts deleted file mode 100644 index 1422da668e..0000000000 --- a/src/types/virtual/server-handlers-meta.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { OperationObject } from "openapi-typescript"; -import { NitroRouteMeta } from "nitropack/types"; - -export const handlersMeta: { - route?: string; - method?: string; - meta?: NitroRouteMeta; -}[]; diff --git a/src/types/virtual/server-handlers.d.ts b/src/types/virtual/server-handlers.d.ts deleted file mode 100644 index e224ed54c6..0000000000 --- a/src/types/virtual/server-handlers.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { H3EventHandler, LazyEventHandler, RouterMethod } from "h3"; - -type HandlerDefinition = { - route: string; - lazy?: boolean; - middleware?: boolean; - handler: H3EventHandler; - method?: RouterMethod; -} & { - lazy: true; - handler: LazyEventHandler; -}; - -export const handlers: HandlerDefinition[]; diff --git a/src/types/virtual/storage.d.ts b/src/types/virtual/storage.d.ts deleted file mode 100644 index 9df4f48cb7..0000000000 --- a/src/types/virtual/storage.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -import type { Storage } from "unstorage"; - -export declare const storage: Storage; diff --git a/src/types/virtual/tasks.ts b/src/types/virtual/tasks.ts deleted file mode 100644 index dffef60f64..0000000000 --- a/src/types/virtual/tasks.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { Task, TaskMeta } from "nitropack/types"; - -export const tasks: Record< - string, - { resolve?: () => Promise; meta: TaskMeta } -> = {}; - -export const scheduledTasks: false | { cron: string; tasks: string[] }[] = []; diff --git a/src/core/utils/compress.ts b/src/utils/compress.ts similarity index 63% rename from src/core/utils/compress.ts rename to src/utils/compress.ts index 8df6251287..2c6aa69b41 100644 --- a/src/core/utils/compress.ts +++ b/src/utils/compress.ts @@ -1,24 +1,43 @@ import { existsSync } from "node:fs"; import fsp from "node:fs/promises"; import zlib from "node:zlib"; -import { globby } from "globby"; +import { glob } from "tinyglobby"; import mime from "mime"; -import type { Nitro } from "nitropack/types"; +import type { Nitro } from "nitro/types"; import { resolve } from "pathe"; +const EncodingMap = { gzip: ".gz", br: ".br", zstd: ".zst" } as const; + export async function compressPublicAssets(nitro: Nitro) { - const publicFiles = await globby("**", { + const publicFiles = await glob("**", { cwd: nitro.options.output.publicDir, absolute: false, dot: true, - ignore: ["**/*.gz", "**/*.br"], + ignore: ["**/*.gz", "**/*.br", "**/*.zst"], }); await Promise.all( publicFiles.map(async (fileName) => { + const compressPublicAssets = nitro.options.compressPublicAssets; + if (compressPublicAssets === false) { + return; + } + + const { + gzip = false, + brotli = false, + zstd = false, + } = compressPublicAssets === true + ? { gzip: true, brotli: true, zstd: true } + : compressPublicAssets; + const zstdSupported = zlib.zstdCompress !== undefined; const filePath = resolve(nitro.options.output.publicDir, fileName); - if (existsSync(filePath + ".gz") || existsSync(filePath + ".br")) { + if ( + (gzip && existsSync(filePath + EncodingMap.gzip)) || + (brotli && existsSync(filePath + EncodingMap.br)) || + (zstd && zstdSupported && existsSync(filePath + EncodingMap.zstd)) + ) { return; } @@ -33,41 +52,37 @@ export async function compressPublicAssets(nitro: Nitro) { return; } - const { gzip, brotli } = - nitro.options.compressPublicAssets || ({} as any); - const encodings = [ - gzip !== false && "gzip", - brotli !== false && "br", - ].filter(Boolean); + gzip && ("gzip" as const), + brotli && ("br" as const), + zstd && zstdSupported && ("zstd" as const), + ].filter((v): v is keyof typeof EncodingMap => v !== false); await Promise.all( encodings.map(async (encoding) => { - const suffix = "." + (encoding === "gzip" ? "gz" : "br"); + const suffix = EncodingMap[encoding]; const compressedPath = filePath + suffix; if (existsSync(compressedPath)) { return; } - const gzipOptions = { level: zlib.constants.Z_BEST_COMPRESSION }; const brotliOptions = { [zlib.constants.BROTLI_PARAM_MODE]: isTextMime(mimeType) ? zlib.constants.BROTLI_MODE_TEXT : zlib.constants.BROTLI_MODE_GENERIC, - [zlib.constants.BROTLI_PARAM_QUALITY]: - zlib.constants.BROTLI_MAX_QUALITY, + [zlib.constants.BROTLI_PARAM_QUALITY]: zlib.constants.BROTLI_DEFAULT_QUALITY, [zlib.constants.BROTLI_PARAM_SIZE_HINT]: fileContents.length, }; - const compressedBuff: Buffer = await new Promise( - (resolve, reject) => { - const cb = (error: Error | null, result: Buffer) => - error ? reject(error) : resolve(result); - if (encoding === "gzip") { - zlib.gzip(fileContents, gzipOptions, cb); - } else { - zlib.brotliCompress(fileContents, brotliOptions, cb); - } + const compressedBuff: Buffer = await new Promise((resolve, reject) => { + const cb = (error: Error | null, result: Buffer) => + error ? reject(error) : resolve(result); + if (encoding === "gzip") { + zlib.gzip(fileContents, cb); + } else if (encoding === "br") { + zlib.brotliCompress(fileContents, brotliOptions, cb); + } else if (zstdSupported) { + zlib.zstdCompress(fileContents, cb); } - ); + }); await fsp.writeFile(compressedPath, compressedBuff); }) ); diff --git a/src/utils/dep.ts b/src/utils/dep.ts new file mode 100644 index 0000000000..136ab93fb4 --- /dev/null +++ b/src/utils/dep.ts @@ -0,0 +1,51 @@ +import { consola } from "consola"; +import { resolveModulePath } from "exsolve"; +import { isCI, isTest } from "std-env"; + +export async function importDep( + opts: { + id: string; + dir: string; + reason: string; + }, + _retry?: boolean +): Promise { + const resolved = resolveModulePath(opts.id, { + from: [opts.dir, import.meta.url], + cache: _retry ? false : true, + try: true, + }); + + if (resolved) { + return (await import(resolved)) as Promise; + } + + let shouldInstall: boolean | undefined; + if (_retry || isTest) { + shouldInstall = false; // Do not install dependencies in test mode + } else if (isCI) { + consola.info( + `\`${opts.id}\` is required for ${opts.reason}. Installing automatically in CI environment...` + ); + shouldInstall = true; // Auto install in CI environments + } else { + shouldInstall = await consola.prompt( + `\`${opts.id}\` is required for ${opts.reason}, but it is not installed. Would you like to install it?`, + { type: "confirm", default: true, cancel: "undefined" } + ); + } + + if (!shouldInstall) { + throw new Error( + `\`${opts.id}\` is not installed. Please add it to your dependencies for ${opts.reason}.` + ); + } + + const start = Date.now(); + consola.start(`Installing \`${opts.id}\` in \`${opts.dir}\`...`); + const { addDevDependency } = await import("nypm"); + await addDevDependency(opts.id, { cwd: opts.dir }); + consola.success(`Installed \`${opts.id}\` in ${opts.dir} (${Date.now() - start}ms).`); + + return importDep(opts, true); +} diff --git a/src/core/utils/fs-tree.ts b/src/utils/fs-tree.ts similarity index 77% rename from src/core/utils/fs-tree.ts rename to src/utils/fs-tree.ts index 0622e455f7..92acdc7e82 100644 --- a/src/core/utils/fs-tree.ts +++ b/src/utils/fs-tree.ts @@ -1,24 +1,20 @@ import { promises as fsp } from "node:fs"; import { colors } from "consola/utils"; -import { globby } from "globby"; +import { glob } from "tinyglobby"; import { gzipSize } from "gzip-size"; import { dirname, relative, resolve } from "pathe"; import prettyBytes from "pretty-bytes"; import { isTest } from "std-env"; -import { runParallel } from "./parallel"; +import { runParallel } from "./parallel.ts"; -export async function generateFSTree( - dir: string, - options: { compressedSizes?: boolean } = {} -) { +export async function generateFSTree(dir: string, options: { compressedSizes?: boolean } = {}) { if (isTest) { return; } - const files = await globby("**/*.*", { cwd: dir, ignore: ["*.map"] }); + const files = await glob("**/*.*", { cwd: dir, ignore: ["*.map"] }); - const items: { file: string; path: string; size: number; gzip: number }[] = - []; + const items: { file: string; path: string; size: number; gzip: number }[] = []; await runParallel( new Set(files), @@ -58,9 +54,7 @@ export async function generateFSTree( continue; } - treeText += colors.gray( - ` ${treeChar} ${rpath} (${prettyBytes(item.size)})` - ); + treeText += colors.gray(` ${treeChar} ${rpath} (${prettyBytes(item.size)})`); if (options.compressedSizes) { treeText += colors.gray(` (${prettyBytes(item.gzip)} gzip)`); } @@ -69,9 +63,7 @@ export async function generateFSTree( totalGzip += item.gzip; } - treeText += `${colors.cyan("Σ Total size:")} ${prettyBytes( - totalSize + totalNodeModulesSize - )}`; + treeText += `${colors.cyan("Σ Total size:")} ${prettyBytes(totalSize + totalNodeModulesSize)}`; if (options.compressedSizes) { treeText += ` (${prettyBytes(totalGzip + totalNodeModulesGzip)} gzip)`; } diff --git a/src/kit/path.ts b/src/utils/fs.ts similarity index 55% rename from src/kit/path.ts rename to src/utils/fs.ts index 15f23fca0f..abed290336 100644 --- a/src/kit/path.ts +++ b/src/utils/fs.ts @@ -1,7 +1,9 @@ +import type { Nitro } from "nitro/types"; +import { stat, mkdir, writeFile as fspWriteFile } from "node:fs/promises"; +import { dirname } from "pathe"; import consola from "consola"; import { colors } from "consola/utils"; import { getProperty } from "dot-prop"; -import type { Nitro } from "nitropack/types"; import { relative, resolve } from "pathe"; export function prettyPath(p: string, highlight = true) { @@ -26,7 +28,12 @@ export function resolveNitroPath( } } - return resolve(base || nitroOptions.srcDir, path); + // eslint-disable-next-line no-control-regex + if (/^[#\u0000]/.test(path)) { + return path; + } + + return resolve(base || nitroOptions.rootDir, path); } function _compilePathTemplate(contents: string) { @@ -34,10 +41,24 @@ function _compilePathTemplate(contents: string) { contents.replace(/{{ ?([\w.]+) ?}}/g, (_, match) => { const val = getProperty, string>(params, match); if (!val) { - consola.warn( - `cannot resolve template param '${match}' in ${contents.slice(0, 20)}` - ); + consola.warn(`cannot resolve template param '${match}' in ${contents.slice(0, 20)}`); } return val || `${match}`; }); } + +export async function writeFile(file: string, contents: Buffer | string, log = false) { + await mkdir(dirname(file), { recursive: true }); + await fspWriteFile(file, contents, typeof contents === "string" ? "utf8" : undefined); + if (log) { + consola.info("Generated", prettyPath(file)); + } +} + +export async function isDirectory(path: string) { + try { + return (await stat(path)).isDirectory(); + } catch { + return false; + } +} diff --git a/src/core/utils/parallel.ts b/src/utils/parallel.ts similarity index 89% rename from src/core/utils/parallel.ts rename to src/utils/parallel.ts index cc9b5d700e..5832f835c3 100644 --- a/src/core/utils/parallel.ts +++ b/src/utils/parallel.ts @@ -2,7 +2,8 @@ export async function runParallel( inputs: Set, cb: (input: T) => unknown | Promise, opts: { concurrency: number; interval?: number } -) { +): Promise<{ errors: unknown[] }> { + const errors: unknown[] = []; const tasks = new Set>(); function queueNext(): undefined | Promise { @@ -20,6 +21,7 @@ export async function runParallel( .then(() => cb(route)) .catch((error) => { console.error(error); + errors.push(error); }); tasks.add(task); @@ -37,4 +39,6 @@ export async function runParallel( } await refillQueue(); + + return { errors }; } diff --git a/src/utils/regex.ts b/src/utils/regex.ts new file mode 100644 index 0000000000..669d95ef73 --- /dev/null +++ b/src/utils/regex.ts @@ -0,0 +1,26 @@ +import { isWindows } from "std-env"; + +export function escapeRegExp(string: string): string { + return string.replace(/[-\\^$*+?.()|[\]{}]/g, String.raw`\$&`); +} + +export function pathRegExp(string: string): string { + if (isWindows) { + string = string.replace(/\\/g, "/"); + } + let escaped = escapeRegExp(string); + if (isWindows) { + escaped = escaped.replace(/\//g, String.raw`[/\\]`); + } + return escaped; +} + +export function toPathRegExp(input: string | RegExp): RegExp { + if (input instanceof RegExp) { + return input; + } + if (typeof input === "string") { + return new RegExp(pathRegExp(input)); + } + throw new TypeError("Expected a string or RegExp", { cause: input }); +} diff --git a/src/vite.ts b/src/vite.ts new file mode 100644 index 0000000000..be9c3a4851 --- /dev/null +++ b/src/vite.ts @@ -0,0 +1,3 @@ +export { nitro } from "./build/vite/plugin.ts"; + +export type { NitroPluginConfig, ServiceConfig } from "./build/vite/types.ts"; diff --git a/test/examples.test.ts b/test/examples.test.ts new file mode 100644 index 0000000000..75e2eb9224 --- /dev/null +++ b/test/examples.test.ts @@ -0,0 +1,105 @@ +import { join } from "node:path"; +import { readdir } from "node:fs/promises"; +import { fileURLToPath, pathToFileURL } from "node:url"; +import { toRequest } from "h3"; +import { describe, test, expect, beforeAll, afterAll } from "vitest"; + +import type { ViteDevServer } from "vite"; + +const examplesDir = fileURLToPath(new URL("../examples", import.meta.url)); + +const { createServer, createBuilder, rolldownVersion } = (await import( + process.env.NITRO_VITE_PKG || "vite" +)) as typeof import("vite"); + +const isRolldown = !!rolldownVersion; + +const skip = new Set([ + "websocket", + ...(isRolldown + ? [ + // TODO: Cannot read properties of null (reading 'use') + "vite-rsc", + ] + : [ + "vite-rsc", + // No tsConfigPaths support in rollup + "import-alias", + ]), +]); + +const skipDev = new Set(["auto-imports", "cached-handler"]); + +const skipProd = new Set(isRolldown ? [] : []); + +for (const example of await readdir(examplesDir)) { + if (example.startsWith("_")) continue; + setupTest(example); +} + +function setupTest(name: string) { + const rootDir = join(examplesDir, name); + + describe.skipIf(skip.has(name))(name, () => { + type TestContext = { + fetch: typeof globalThis.fetch; + }; + + function registerTests(ctx: TestContext, mode: string) { + test(`${name} (${mode})`, async () => { + const res = await ctx.fetch("/"); + const expectedStatus = name === "custom-error-handler" ? 500 : 200; + expect(res.status, res.statusText).toBe(expectedStatus); + }); + } + + describe.skipIf(skipDev.has(name))(`${name} (dev)`, () => { + let server: ViteDevServer; + const context: TestContext = {} as any; + + beforeAll(async () => { + process.chdir(rootDir); + server = await createServer({ root: rootDir }); + await server.listen("0" as unknown as number); + const addr = server.httpServer?.address() as { + port: number; + address: string; + family: string; + }; + const baseURL = `http://${addr.family === "IPv6" ? `[${addr.address}]` : addr.address}:${addr.port}`; + context.fetch = (url, opts) => fetch(baseURL + url, opts); + }, 30_000); + + afterAll(async () => { + await server?.close(); + }); + + registerTests(context, "dev"); + }); + + describe.skipIf(skipProd.has(name))(`${name} (prod)`, () => { + const context: TestContext = {} as any; + + beforeAll(async () => { + process.chdir(rootDir); + + process.env.NITRO_PRESET = "standard"; + const builder = await createBuilder({ logLevel: "warn" }); + await builder.buildApp(); + + delete globalThis.__nitro__; + + const { default: entryMod } = await import( + pathToFileURL(join(rootDir, ".output/server/index.mjs")).href + ); + + delete (globalThis as any).document; // Set by nano-jsx! + + expect(entryMod?.fetch).toBeInstanceOf(Function); + context.fetch = (input, init) => entryMod.fetch(toRequest(input, init)); + }, 30_000); + + registerTests(context, "prod"); + }); + }); +} diff --git a/test/fixture/.gitignore b/test/fixture/.gitignore index b077006240..cc887db5ab 100644 --- a/test/fixture/.gitignore +++ b/test/fixture/.gitignore @@ -1,2 +1,3 @@ -!node_modules !.env +!node_modules/@fixture +vercel.json diff --git a/test/fixture/api/_ignored.ts b/test/fixture/api/_ignored.ts deleted file mode 100644 index c2c27dadee..0000000000 --- a/test/fixture/api/_ignored.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default eventHandler((event) => { - throw createError("This file should be ignored!"); -}); diff --git a/test/fixture/api/error.ts b/test/fixture/api/error.ts deleted file mode 100644 index 43ae9e4a33..0000000000 --- a/test/fixture/api/error.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { createError } from "h3"; -export default eventHandler(() => { - throw createError({ - statusCode: 503, - statusMessage: "Service Unavailable", - }); -}); diff --git a/test/fixture/api/headers.ts b/test/fixture/api/headers.ts deleted file mode 100644 index b209272691..0000000000 --- a/test/fixture/api/headers.ts +++ /dev/null @@ -1,10 +0,0 @@ -export default defineEventHandler((event) => { - setHeader(event, "x-foo", "bar"); - setHeader(event, "x-array", ["foo", "bar"]); - - setHeader(event, "Set-Cookie", "foo=bar, bar=baz"); - setCookie(event, "test", "value"); - setCookie(event, "test2", "value"); - - return "headers sent"; -}); diff --git a/test/fixture/api/hello.ts b/test/fixture/api/hello.ts deleted file mode 100644 index 390fa94c35..0000000000 --- a/test/fixture/api/hello.ts +++ /dev/null @@ -1 +0,0 @@ -export default eventHandler(() => ({ message: "Hello API" })); diff --git a/test/fixture/api/hey/index.get.ts b/test/fixture/api/hey/index.get.ts deleted file mode 100644 index d350af5d02..0000000000 --- a/test/fixture/api/hey/index.get.ts +++ /dev/null @@ -1 +0,0 @@ -export default eventHandler(() => "Hey API"); diff --git a/test/fixture/api/import-meta.ts b/test/fixture/api/import-meta.ts deleted file mode 100644 index 4e87c387d7..0000000000 --- a/test/fixture/api/import-meta.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { fileURLToPath } from "node:url"; - -export default eventHandler(() => { - return { - testFile: fileURLToPath(new URL("test.txt", import.meta.url)), - // @ts-ignore - hasEnv: typeof import.meta.env === "object", - }; -}); diff --git a/test/fixture/api/kebab.ts b/test/fixture/api/kebab.ts deleted file mode 100644 index 9a1750ff47..0000000000 --- a/test/fixture/api/kebab.ts +++ /dev/null @@ -1 +0,0 @@ -export default eventHandler(() => kebabCase("HelloWorld")); diff --git a/test/fixture/api/methods/default.post.ts b/test/fixture/api/methods/default.post.ts deleted file mode 100644 index 88b496d976..0000000000 --- a/test/fixture/api/methods/default.post.ts +++ /dev/null @@ -1 +0,0 @@ -export default defineEventHandler<"Default override">(() => "Default override"); diff --git a/test/fixture/api/methods/default.ts b/test/fixture/api/methods/default.ts deleted file mode 100644 index 18b11db137..0000000000 --- a/test/fixture/api/methods/default.ts +++ /dev/null @@ -1 +0,0 @@ -export default defineEventHandler<"Default route">(() => "Default route"); diff --git a/test/fixture/api/methods/foo.get.get.ts b/test/fixture/api/methods/foo.get.get.ts deleted file mode 100644 index 5aee955bc3..0000000000 --- a/test/fixture/api/methods/foo.get.get.ts +++ /dev/null @@ -1 +0,0 @@ -export default defineEventHandler(() => "foo.get"); diff --git a/test/fixture/api/methods/get.ts b/test/fixture/api/methods/get.ts deleted file mode 100644 index 99cff5f8e0..0000000000 --- a/test/fixture/api/methods/get.ts +++ /dev/null @@ -1 +0,0 @@ -export default defineEventHandler(() => "get"); diff --git a/test/fixture/api/methods/index.get.ts b/test/fixture/api/methods/index.get.ts deleted file mode 100644 index d161d1bc23..0000000000 --- a/test/fixture/api/methods/index.get.ts +++ /dev/null @@ -1 +0,0 @@ -export default defineEventHandler<"Index get">(() => "Index get"); diff --git a/test/fixture/api/methods/index.post.ts b/test/fixture/api/methods/index.post.ts deleted file mode 100644 index 00d66fe12c..0000000000 --- a/test/fixture/api/methods/index.post.ts +++ /dev/null @@ -1 +0,0 @@ -export default defineEventHandler<"Index post">(() => "Index post"); diff --git a/test/fixture/api/param/[test-id].ts b/test/fixture/api/param/[test-id].ts deleted file mode 100644 index 4ec687eaa9..0000000000 --- a/test/fixture/api/param/[test-id].ts +++ /dev/null @@ -1,4 +0,0 @@ -export default eventHandler((event) => { - setHeader(event, "Content-Type", "text/plain; charset=utf-16"); - return event.context.params!["test-id"]; -}); diff --git a/test/fixture/api/serialized/date.ts b/test/fixture/api/serialized/date.ts deleted file mode 100644 index f8447d04f0..0000000000 --- a/test/fixture/api/serialized/date.ts +++ /dev/null @@ -1 +0,0 @@ -export default defineEventHandler(() => ({ createdAt: new Date() })); diff --git a/test/fixture/api/serialized/error.ts b/test/fixture/api/serialized/error.ts deleted file mode 100644 index 6b795fdff7..0000000000 --- a/test/fixture/api/serialized/error.ts +++ /dev/null @@ -1,5 +0,0 @@ -export default defineEventHandler(() => { - return createError({ - statusCode: 400, - }); -}); diff --git a/test/fixture/api/serialized/function.ts b/test/fixture/api/serialized/function.ts deleted file mode 100644 index edaae97595..0000000000 --- a/test/fixture/api/serialized/function.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default defineEventHandler(() => { - return { foo: () => "foo" }; -}); diff --git a/test/fixture/api/serialized/map.ts b/test/fixture/api/serialized/map.ts deleted file mode 100644 index 950e92e007..0000000000 --- a/test/fixture/api/serialized/map.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default defineEventHandler(() => { - return { foo: new Map([["key", 2]]) }; -}); diff --git a/test/fixture/api/serialized/null.ts b/test/fixture/api/serialized/null.ts deleted file mode 100644 index 3fd586da85..0000000000 --- a/test/fixture/api/serialized/null.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default defineEventHandler(() => { - return null; -}); diff --git a/test/fixture/api/serialized/set.ts b/test/fixture/api/serialized/set.ts deleted file mode 100644 index 0a4225bdf4..0000000000 --- a/test/fixture/api/serialized/set.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default defineEventHandler(() => { - return { foo: new Set(["item"]) }; -}); diff --git a/test/fixture/api/serialized/tuple.ts b/test/fixture/api/serialized/tuple.ts deleted file mode 100644 index 791d05cc28..0000000000 --- a/test/fixture/api/serialized/tuple.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default defineEventHandler(() => { - return ["foo", new Date()] as [string, Date]; -}); diff --git a/test/fixture/api/serialized/void.ts b/test/fixture/api/serialized/void.ts deleted file mode 100644 index 8756ea1b2d..0000000000 --- a/test/fixture/api/serialized/void.ts +++ /dev/null @@ -1 +0,0 @@ -export default defineEventHandler(() => {}); diff --git a/test/fixture/api/storage/dev.dev.ts b/test/fixture/api/storage/dev.dev.ts deleted file mode 100644 index 807abd17b7..0000000000 --- a/test/fixture/api/storage/dev.dev.ts +++ /dev/null @@ -1,6 +0,0 @@ -export default defineEventHandler(async (event) => { - const storage = useStorage(); - return { - keys: await storage.getKeys("/src/public"), - }; -}); diff --git a/test/fixture/api/storage/item.get.ts b/test/fixture/api/storage/item.get.ts deleted file mode 100644 index 24ee602aca..0000000000 --- a/test/fixture/api/storage/item.get.ts +++ /dev/null @@ -1,11 +0,0 @@ -export default eventHandler(async (event) => { - const { base = "", key = "" } = getQuery(event) as Record; - const storage = useStorage(`test:${base}`); - - if (!key || key.endsWith(":")) { - return await storage.getKeys(); - } - - const value = await storage.getItem(key); - return value; -}); diff --git a/test/fixture/api/storage/item.put.ts b/test/fixture/api/storage/item.put.ts deleted file mode 100644 index 8e106dd859..0000000000 --- a/test/fixture/api/storage/item.put.ts +++ /dev/null @@ -1,7 +0,0 @@ -export default eventHandler(async (event) => { - const { base = "", key = "" } = getQuery(event) as Record; - const storage = useStorage(`test:${base}`); - const value = await readBody(event); - await storage.setItem(key, value); - return value; -}); diff --git a/test/fixture/api/typed/catchall/[slug]/[...another].ts b/test/fixture/api/typed/catchall/[slug]/[...another].ts deleted file mode 100644 index 2cd8654f58..0000000000 --- a/test/fixture/api/typed/catchall/[slug]/[...another].ts +++ /dev/null @@ -1,3 +0,0 @@ -export default eventHandler(() => ({ - internalApiKey: "/api/typed/catchall/:slug/**:another" as const, -})); diff --git a/test/fixture/api/typed/catchall/some/[...test].ts b/test/fixture/api/typed/catchall/some/[...test].ts deleted file mode 100644 index 5fd62ce5f0..0000000000 --- a/test/fixture/api/typed/catchall/some/[...test].ts +++ /dev/null @@ -1,3 +0,0 @@ -export default eventHandler(() => ({ - internalApiKey: "/api/typed/catchall/some/**:test" as const, -})); diff --git a/test/fixture/api/typed/todos/[...].ts b/test/fixture/api/typed/todos/[...].ts deleted file mode 100644 index 8ce3daf39d..0000000000 --- a/test/fixture/api/typed/todos/[...].ts +++ /dev/null @@ -1,3 +0,0 @@ -export default eventHandler(() => ({ - internalApiKey: "/api/typed/todos/**" as const, -})); diff --git a/test/fixture/api/typed/todos/[todoId]/comments/[...commentId].ts b/test/fixture/api/typed/todos/[todoId]/comments/[...commentId].ts deleted file mode 100644 index 31891838ca..0000000000 --- a/test/fixture/api/typed/todos/[todoId]/comments/[...commentId].ts +++ /dev/null @@ -1,3 +0,0 @@ -export default eventHandler(() => ({ - internalApiKey: "/api/typed/todos/:todoId/comments/**:commentId" as const, -})); diff --git a/test/fixture/api/typed/user/[userId]/[userExtends].ts b/test/fixture/api/typed/user/[userId]/[userExtends].ts deleted file mode 100644 index 35bfae15da..0000000000 --- a/test/fixture/api/typed/user/[userId]/[userExtends].ts +++ /dev/null @@ -1,3 +0,0 @@ -export default eventHandler(() => ({ - internalApiKey: "/api/typed/user/:userId/:userExtends" as const, -})); diff --git a/test/fixture/api/typed/user/[userId]/index.ts b/test/fixture/api/typed/user/[userId]/index.ts deleted file mode 100644 index dad6b3aac9..0000000000 --- a/test/fixture/api/typed/user/[userId]/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default eventHandler(() => ({ - internalApiKey: "/api/typed/user/:userId" as const, -})); diff --git a/test/fixture/api/typed/user/[userId]/post/[postId].ts b/test/fixture/api/typed/user/[userId]/post/[postId].ts deleted file mode 100644 index 1fcd9d71ee..0000000000 --- a/test/fixture/api/typed/user/[userId]/post/[postId].ts +++ /dev/null @@ -1,3 +0,0 @@ -export default eventHandler(() => ({ - internalApiKey: "/api/typed/user/:userId/post/:postId" as const, -})); diff --git a/test/fixture/api/typed/user/[userId]/post/firstPost.ts b/test/fixture/api/typed/user/[userId]/post/firstPost.ts deleted file mode 100644 index 7d6bbf2e8f..0000000000 --- a/test/fixture/api/typed/user/[userId]/post/firstPost.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default eventHandler(() => ({ - internalApiKey: "/api/typed/user/:userId/post/firstPost" as const, -})); diff --git a/test/fixture/api/typed/user/john/[johnExtends].ts b/test/fixture/api/typed/user/john/[johnExtends].ts deleted file mode 100644 index ff0c3b3365..0000000000 --- a/test/fixture/api/typed/user/john/[johnExtends].ts +++ /dev/null @@ -1,3 +0,0 @@ -export default eventHandler(() => ({ - internalApiKey: "/api/typed/user/john/:johnExtends" as const, -})); diff --git a/test/fixture/api/typed/user/john/index.ts b/test/fixture/api/typed/user/john/index.ts deleted file mode 100644 index 7ea55de263..0000000000 --- a/test/fixture/api/typed/user/john/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default eventHandler(() => ({ - internalApiKey: "/api/typed/user/john" as const, -})); diff --git a/test/fixture/api/typed/user/john/post/[postId].ts b/test/fixture/api/typed/user/john/post/[postId].ts deleted file mode 100644 index fcecb9cde4..0000000000 --- a/test/fixture/api/typed/user/john/post/[postId].ts +++ /dev/null @@ -1,3 +0,0 @@ -export default eventHandler(() => ({ - internalApiKey: "/api/typed/user/john/post/:postId" as const, -})); diff --git a/test/fixture/api/typed/user/john/post/coffee.ts b/test/fixture/api/typed/user/john/post/coffee.ts deleted file mode 100644 index 4968d67c88..0000000000 --- a/test/fixture/api/typed/user/john/post/coffee.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default eventHandler(() => ({ - internalApiKey: "/api/typed/user/john/post/coffee" as const, -})); diff --git a/test/fixture/api/upload.post.ts b/test/fixture/api/upload.post.ts deleted file mode 100644 index 0fa7ba7eac..0000000000 --- a/test/fixture/api/upload.post.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default eventHandler((event) => { - return "uploaded!"; -}); diff --git a/test/fixture/api/wildcard/[...param].ts b/test/fixture/api/wildcard/[...param].ts deleted file mode 100644 index f769d76961..0000000000 --- a/test/fixture/api/wildcard/[...param].ts +++ /dev/null @@ -1,3 +0,0 @@ -export default eventHandler((event) => { - return event.context.params!.param as string; -}); diff --git a/test/fixture/app.config.ts b/test/fixture/app.config.ts deleted file mode 100644 index 90fa51c34f..0000000000 --- a/test/fixture/app.config.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default { - "app-config": true, -}; diff --git a/test/fixture/error.ts b/test/fixture/error.ts index 04f6e8f423..993e89e810 100644 --- a/test/fixture/error.ts +++ b/test/fixture/error.ts @@ -1,10 +1,8 @@ -import { defineNitroErrorHandler } from "nitropack/runtime"; -import { send } from "h3"; -export default defineNitroErrorHandler( - async (error, event, { defaultHandler }) => { - if (event.path.includes("?json")) { - const response = await defaultHandler(error, event, { json: true }); - return send(event, JSON.stringify({ json: response.body }, null, 2)); - } +import { defineErrorHandler } from "nitro"; + +export default defineErrorHandler(async (error, event, { defaultHandler }) => { + if (event.req.url.includes("?json")) { + const res = await defaultHandler(error, event, { json: true }); + return Response.json({ json: res.body }); } -); +}); diff --git a/test/fixture/exports.cloudflare.ts b/test/fixture/exports.cloudflare.ts new file mode 100644 index 0000000000..8124319864 --- /dev/null +++ b/test/fixture/exports.cloudflare.ts @@ -0,0 +1,3 @@ +export function myScheduled() { + console.log("scheduled!"); +} diff --git a/test/fixture/middleware/_ignored.ts b/test/fixture/middleware/_ignored.ts deleted file mode 100644 index c2c27dadee..0000000000 --- a/test/fixture/middleware/_ignored.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default eventHandler((event) => { - throw createError("This file should be ignored!"); -}); diff --git a/test/fixture/middleware/config.ts b/test/fixture/middleware/config.ts deleted file mode 100644 index 28158e4dad..0000000000 --- a/test/fixture/middleware/config.ts +++ /dev/null @@ -1,6 +0,0 @@ -process.env.NITRO_DYNAMIC = "from-env"; - -export default eventHandler((event) => { - const appConfig = useAppConfig(event); - appConfig.dynamic = "from-middleware"; -}); diff --git a/test/fixture/nitro.config.ts b/test/fixture/nitro.config.ts index 97da3f1ae0..53fdb7b36b 100644 --- a/test/fixture/nitro.config.ts +++ b/test/fixture/nitro.config.ts @@ -1,14 +1,16 @@ -import { fileURLToPath } from "node:url"; -import { defineNitroConfig } from "nitropack/config"; +import { defineConfig } from "nitro"; + import { dirname, resolve } from "node:path"; +import { existsSync } from "node:fs"; -export default defineNitroConfig({ +export default defineConfig({ compressPublicAssets: true, - compatibilityDate: "2025-03-01", - framework: { - name: "nitro", - version: "2.x", - }, + compatibilityDate: "latest", + serverDir: "server", + builder: (process.env.NITRO_BUILDER as any) || "rolldown", + // @ts-expect-error + __vitePkg__: process.env.NITRO_VITE_PKG, + framework: { name: "nitro", version: "3.x" }, imports: { presets: [ { @@ -18,58 +20,54 @@ export default defineNitroConfig({ }, ], }, + sourcemap: true, rollupConfig: { output: { - // TODO: when output.dir is outside of src, rollup emits wrong relative sourcemap paths sourcemapPathTransform: (relativeSourcePath, sourcemapPath) => { const sourcemapDir = dirname(sourcemapPath); const sourcePath = resolve(sourcemapDir, relativeSourcePath); - return sourcePath; + return existsSync(sourcePath) ? sourcePath : relativeSourcePath; }, }, }, + virtual: { + "#virtual-route": () => `export default () => new Response("Hello from virtual entry!")`, + }, handlers: [ { route: "/api/test/*/foo", - handler: "~/api/hello.ts", - // @ts-expect-error #2382 + handler: "./server/routes/api/hello.ts", method: "GET", }, { route: "/api/hello2", - handler: "~/api/hello.ts", + handler: "./server/routes/api/hello.ts", + middleware: true, + }, + { + route: "/virtual", + handler: "#virtual-route", }, ], devProxy: { - "/proxy/example": { target: "https://example.com", changeOrigin: true }, - }, - alias: { - "#fixture-nitro-utils-extra-absolute": fileURLToPath( - new URL("node_modules/@fixture/nitro-utils/extra2.mjs", import.meta.url) - ), + "/proxy/example": { + target: "https://icanhazip.com", + changeOrigin: true, + ignorePath: true, + }, }, + traceDeps: ["@fixture"], serverAssets: [ { baseName: "files", - dir: "files", + dir: "server/files", }, ], - ignore: [ - "api/**/_*", - "middleware/_ignored.ts", - "routes/_*.ts", - "**/_*.txt", - "!**/_unignored.txt", - ], - appConfig: { - "nitro-config": true, - dynamic: "initial", - }, + ignore: ["routes/api/**/_*", "middleware/_ignored.ts", "routes/_*.ts", "**/_*.txt"], runtimeConfig: { dynamic: "initial", url: "https://{{APP_DOMAIN}}", }, - appConfigFiles: ["~/server.config.ts"], publicAssets: [ { baseURL: "build", @@ -81,7 +79,7 @@ export default defineNitroConfig({ "db:migrate": { description: "Migrate database" }, "db:seed": { description: "Seed database" }, }, - errorHandler: "~/error.ts", + errorHandler: "error.ts", routeRules: { "/api/param/prerender4": { prerender: true }, "/api/param/prerender2": { prerender: false }, @@ -97,7 +95,7 @@ export default defineNitroConfig({ "/rules/swr/**": { swr: true }, "/rules/swr-ttl/**": { swr: 60 }, "/rules/redirect/obj": { - redirect: { to: "https://nitro.build/", statusCode: 308 }, + redirect: { to: "https://nitro.build/", status: 308 }, }, "/rules/redirect/wildcard/**": { redirect: "https://nitro.build/**" }, "/rules/nested/**": { redirect: "/base", headers: { "x-test": "test" } }, @@ -107,6 +105,11 @@ export default defineNitroConfig({ "/rules/_/cached/noncached": { cache: false, swr: false, isr: false }, "/rules/_/cached/**": { swr: true }, "/api/proxy/**": { proxy: "/api/echo" }, + "/cdn/**": { proxy: "https://cdn.jsdelivr.net/**" }, + "/rules/basic-auth/**": { + basicAuth: { username: "admin", password: "secret", realm: "Secure Area" }, + }, + "/rules/basic-auth/no-auth/**": { basicAuth: false }, "**": { headers: { "x-test": "test" } }, }, prerender: { @@ -119,7 +122,6 @@ export default defineNitroConfig({ experimental: { openAPI: true, asyncContext: true, - wasm: true, envExpansion: true, database: true, tasks: true, @@ -138,6 +140,10 @@ export default defineNitroConfig({ compatibility_date: "2024-01-01", }, }, + typescript: { + generateRuntimeConfigTypes: true, + generateTsConfig: true, + }, openAPI: { production: "prerender", meta: { @@ -145,10 +151,5 @@ export default defineNitroConfig({ description: "Nitro Test Fixture API", version: "2.0", }, - ui: { - scalar: { - theme: "purple", - }, - }, }, }); diff --git a/test/fixture/package.json b/test/fixture/package.json new file mode 100644 index 0000000000..01d0b70c60 --- /dev/null +++ b/test/fixture/package.json @@ -0,0 +1,14 @@ +{ + "name": "nitro-test-fixture", + "version": "1.0.0", + "type": "module", + "scripts": { + "build": "nitro build", + "preview": "nitro preview", + "dev": "nitro dev" + }, + "devDependencies": { + "mono-jsx": "^0.8.2", + "nitro": "latest" + } +} diff --git a/test/fixture/plugins/vary.ts b/test/fixture/plugins/vary.ts deleted file mode 100644 index d1dcd40d17..0000000000 --- a/test/fixture/plugins/vary.ts +++ /dev/null @@ -1,10 +0,0 @@ -export default defineNitroPlugin((app) => { - app.hooks.hook("request", (event) => { - if (event.path.endsWith(".css")) { - setResponseHeader(event, "Vary", "Origin"); - } - if (event.path.endsWith(".js")) { - setResponseHeader(event, "Vary", ["Origin"]); - } - }); -}); diff --git a/test/fixture/routes/(route-group)/route-group.ts b/test/fixture/routes/(route-group)/route-group.ts deleted file mode 100644 index 627b83a70b..0000000000 --- a/test/fixture/routes/(route-group)/route-group.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default defineEventHandler((event) => { - return "Hi from inside group"; -}); diff --git a/test/fixture/routes/500.ts b/test/fixture/routes/500.ts deleted file mode 100644 index 6d2e6ab40c..0000000000 --- a/test/fixture/routes/500.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default defineEventHandler((event) => { - throw createError({ statusCode: 500, statusMessage: "Test Error" }); -}); diff --git a/test/fixture/routes/assets/[id].ts b/test/fixture/routes/assets/[id].ts deleted file mode 100644 index 1c4e92f782..0000000000 --- a/test/fixture/routes/assets/[id].ts +++ /dev/null @@ -1,27 +0,0 @@ -export default eventHandler(async (event) => { - const serverAssets = useStorage("assets/server"); - - const id = event.context.params.id; - - if (!(await serverAssets.hasItem(id))) { - throw createError({ message: `Asset ${id} not found`, statusCode: 404 }); - } - - const meta = (await serverAssets.getMeta( - event.context.params.id - )) as unknown as { type: string; etag: string; mtime: string }; - - if (meta.type) { - setResponseHeader(event, "content-type", meta.type); - } - - if (meta.etag) { - setResponseHeader(event, "etag", meta.etag); - } - - if (meta.mtime) { - setResponseHeader(event, "last-modified", meta.mtime); - } - - return serverAssets.getItemRaw(event.context.params.id); -}); diff --git a/test/fixture/routes/assets/md.ts b/test/fixture/routes/assets/md.ts deleted file mode 100644 index 6de27f6fe5..0000000000 --- a/test/fixture/routes/assets/md.ts +++ /dev/null @@ -1,6 +0,0 @@ -export default eventHandler(async (event) => { - const md = await import("../../assets/test.md" as string).then( - (r) => r.default - ); - return md; -}); diff --git a/test/fixture/routes/config.ts b/test/fixture/routes/config.ts deleted file mode 100644 index 9097e19f5c..0000000000 --- a/test/fixture/routes/config.ts +++ /dev/null @@ -1,14 +0,0 @@ -const sharedAppConfig = useAppConfig(); -const sharedRuntimeConfig = useRuntimeConfig(); - -export default eventHandler((event) => { - const appConfig = useAppConfig(event); - const runtimeConfig = useRuntimeConfig(event); - - return { - sharedAppConfig, - appConfig, - runtimeConfig, - sharedRuntimeConfig, - }; -}); diff --git a/test/fixture/routes/env/index.dev.ts b/test/fixture/routes/env/index.dev.ts deleted file mode 100644 index bf10ab56bb..0000000000 --- a/test/fixture/routes/env/index.dev.ts +++ /dev/null @@ -1 +0,0 @@ -export default eventHandler(() => "dev env"); diff --git a/test/fixture/routes/env/index.get.prod.ts b/test/fixture/routes/env/index.get.prod.ts deleted file mode 100644 index c46bb5d9bd..0000000000 --- a/test/fixture/routes/env/index.get.prod.ts +++ /dev/null @@ -1 +0,0 @@ -export default eventHandler(() => "prod env"); diff --git a/test/fixture/routes/error-stack.ts b/test/fixture/routes/error-stack.ts deleted file mode 100644 index 9d782d718b..0000000000 --- a/test/fixture/routes/error-stack.ts +++ /dev/null @@ -1,5 +0,0 @@ -export default eventHandler(async (event) => { - return { - stack: new Error("testing error").stack.replace(/\\/g, "/"), - }; -}); diff --git a/test/fixture/routes/fetch.ts b/test/fixture/routes/fetch.ts deleted file mode 100644 index 30e2609fe7..0000000000 --- a/test/fixture/routes/fetch.ts +++ /dev/null @@ -1,14 +0,0 @@ -export default eventHandler(async (event) => { - const nitroApp = useNitroApp(); - return { - $fetch: await fetch("/api/hey").then((r) => r.text()), - "event.fetch": await event.fetch("/api/hey").then((r) => r.text()), - "event.$fetch": await event.$fetch("/api/hey"), - "nitroApp.localFetch": await nitroApp - .localFetch("/api/hey") - .then((r) => r.text()), - "nitroApp.localCall": await nitroApp - .localCall({ url: "/api/hey" }) - .then((r) => r.body), - }; -}); diff --git a/test/fixture/routes/imports.ts b/test/fixture/routes/imports.ts deleted file mode 100644 index be04c44283..0000000000 --- a/test/fixture/routes/imports.ts +++ /dev/null @@ -1,6 +0,0 @@ -export default defineEventHandler(() => { - return { - testUtil: testUtil(), - testNestedUtil: testFooUtil() + testBarUtil(), - }; -}); diff --git a/test/fixture/routes/json-string.ts b/test/fixture/routes/json-string.ts deleted file mode 100644 index 96780eed44..0000000000 --- a/test/fixture/routes/json-string.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default eventHandler(() => { - return '{"foo":"bar"}'; -}); diff --git a/test/fixture/routes/jsx.tsx b/test/fixture/routes/jsx.tsx deleted file mode 100644 index 71ed98395c..0000000000 --- a/test/fixture/routes/jsx.tsx +++ /dev/null @@ -1,10 +0,0 @@ -const h = (tag: string, props: any, ...children: any[]) => { - return `<${tag} ${Object.keys(props || {}) - .map((key) => `${key}="${props[key]}"`) - .join(" ") - .trim()}>${children.join("")}`; -}; - -export default eventHandler(() => { - return

Hello JSX!

; -}); diff --git a/test/fixture/routes/prerender.ts b/test/fixture/routes/prerender.ts deleted file mode 100644 index a09f6bf8be..0000000000 --- a/test/fixture/routes/prerender.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { appendHeader } from "h3"; - -export default defineEventHandler((event) => { - const links = [ - "/404", - "https://about.google/products/", - "/api/hello?bar=baz", - "/api/hello?bar=baz&bing=bap", - "/api/hello?bar=baz&foo=qux", - "/prerender#foo", - "../api/hey", - "/json-string", - event.path.includes("?") ? "/api/param/hidden" : "/prerender?withQuery", - ]; - - appendHeader( - event, - "x-nitro-prerender", - "/api/param/prerender1, /api/param/prerender2" - ); - appendHeader(event, "x-nitro-prerender", "/api/param/prerender3"); - - return ` - - - - Prerendered routes test - - -

Prerendered routes test:

-
    -${links.map((link) => `
  • ${link}
  • `).join("\n")} -
- - - /* Bad Link Examples */ - - x-href attr - <a href="/500</a> - #a - #b - -`; -}); diff --git a/test/fixture/routes/rules/[...slug].ts b/test/fixture/routes/rules/[...slug].ts deleted file mode 100644 index 1e8eacb84f..0000000000 --- a/test/fixture/routes/rules/[...slug].ts +++ /dev/null @@ -1 +0,0 @@ -export default defineEventHandler((event) => event.path); diff --git a/test/fixture/routes/static-flags.ts b/test/fixture/routes/static-flags.ts deleted file mode 100644 index be91c49034..0000000000 --- a/test/fixture/routes/static-flags.ts +++ /dev/null @@ -1,12 +0,0 @@ -export default eventHandler(async (event) => { - return { - dev: [process.dev, import.meta.dev], - preset: [process.preset, import.meta.preset], - prerender: [process.prerender, import.meta.prerender], - server: [process.server, import.meta.server], - client: [process.client, import.meta.client], - nitro: [process.nitro, import.meta.nitro], - "versions.nitro": [process.versions.nitro, import.meta.versions.nitro], - "versions?.nitro": [process.versions?.nitro, import.meta.versions?.nitro], - }; -}); diff --git a/test/fixture/routes/tasks/[...name].ts b/test/fixture/routes/tasks/[...name].ts deleted file mode 100644 index 81e834b509..0000000000 --- a/test/fixture/routes/tasks/[...name].ts +++ /dev/null @@ -1,10 +0,0 @@ -export default eventHandler(async (event) => { - const name = getRouterParam(event, "name"); - const payload = { ...getQuery(event) }; - const { result } = await runTask(name, { payload }); - return { - name, - payload, - result, - }; -}); diff --git a/test/fixture/server.ts b/test/fixture/server.ts new file mode 100644 index 0000000000..78183a7ec8 --- /dev/null +++ b/test/fixture/server.ts @@ -0,0 +1,9 @@ +export default { + async fetch(req: Request) { + const url = new URL(req.url); + if (url.pathname === "/") { + return new Response("server entry works!"); + } + return new Response("404 Not Found", { status: 404 }); + }, +}; diff --git a/test/fixture/assets/cat.jpg b/test/fixture/server/assets/cat.jpg similarity index 100% rename from test/fixture/assets/cat.jpg rename to test/fixture/server/assets/cat.jpg diff --git a/test/fixture/assets/test.json b/test/fixture/server/assets/test.json similarity index 100% rename from test/fixture/assets/test.json rename to test/fixture/server/assets/test.json diff --git a/test/fixture/assets/test.md b/test/fixture/server/assets/test.md similarity index 100% rename from test/fixture/assets/test.md rename to test/fixture/server/assets/test.md diff --git a/test/fixture/files/index.html b/test/fixture/server/files/index.html similarity index 100% rename from test/fixture/files/index.html rename to test/fixture/server/files/index.html diff --git a/test/fixture/files/sql.sql b/test/fixture/server/files/sql.sql similarity index 100% rename from test/fixture/files/sql.sql rename to test/fixture/server/files/sql.sql diff --git a/test/fixture/files/sqlts.sql.ts b/test/fixture/server/files/sqlts.sql.ts similarity index 100% rename from test/fixture/files/sqlts.sql.ts rename to test/fixture/server/files/sqlts.sql.ts diff --git a/test/fixture/files/test.txt b/test/fixture/server/files/test.txt similarity index 100% rename from test/fixture/files/test.txt rename to test/fixture/server/files/test.txt diff --git a/test/fixture/server/middleware/_ignored.ts b/test/fixture/server/middleware/_ignored.ts new file mode 100644 index 0000000000..66061a31fb --- /dev/null +++ b/test/fixture/server/middleware/_ignored.ts @@ -0,0 +1,5 @@ +import { HTTPError } from "nitro/h3"; + +export default () => { + throw new HTTPError("This file should be ignored!"); +}; diff --git a/test/fixture/plugins/errors.ts b/test/fixture/server/plugins/errors.ts similarity index 67% rename from test/fixture/plugins/errors.ts rename to test/fixture/server/plugins/errors.ts index e181795d51..b449d0085f 100644 --- a/test/fixture/plugins/errors.ts +++ b/test/fixture/server/plugins/errors.ts @@ -1,6 +1,8 @@ +import { definePlugin } from "nitro"; + export const allErrors: { error: Error; context: any }[] = []; -export default defineNitroPlugin((app) => { +export default definePlugin((app) => { app.hooks.hook("error", (error, context) => { allErrors.push({ error, context }); }); diff --git a/test/fixture/server/plugins/vary.ts b/test/fixture/server/plugins/vary.ts new file mode 100644 index 0000000000..d771932ed8 --- /dev/null +++ b/test/fixture/server/plugins/vary.ts @@ -0,0 +1,10 @@ +import { definePlugin } from "nitro"; + +export default definePlugin((app) => { + app.hooks.hook("response", (res, event) => { + const { pathname } = new URL(event.req.url); + if (pathname.endsWith(".css") || pathname.endsWith(".js")) { + res.headers.append("Vary", "Origin"); + } + }); +}); diff --git a/test/fixture/server/routes/(route-group)/route-group.ts b/test/fixture/server/routes/(route-group)/route-group.ts new file mode 100644 index 0000000000..a5224fc706 --- /dev/null +++ b/test/fixture/server/routes/(route-group)/route-group.ts @@ -0,0 +1,3 @@ +export default () => { + return "Hi from inside group"; +}; diff --git a/test/fixture/server/routes/500.ts b/test/fixture/server/routes/500.ts new file mode 100644 index 0000000000..201ba39307 --- /dev/null +++ b/test/fixture/server/routes/500.ts @@ -0,0 +1,5 @@ +import { HTTPError } from "nitro/h3"; + +export default () => { + throw new HTTPError({ status: 500, statusText: "Test Error" }); +}; diff --git a/test/fixture/server/routes/api/_ignored.ts b/test/fixture/server/routes/api/_ignored.ts new file mode 100644 index 0000000000..66061a31fb --- /dev/null +++ b/test/fixture/server/routes/api/_ignored.ts @@ -0,0 +1,5 @@ +import { HTTPError } from "nitro/h3"; + +export default () => { + throw new HTTPError("This file should be ignored!"); +}; diff --git a/test/fixture/api/cached.ts b/test/fixture/server/routes/api/cached.ts similarity index 62% rename from test/fixture/api/cached.ts rename to test/fixture/server/routes/api/cached.ts index 3856e1ef2e..767ac2166c 100644 --- a/test/fixture/api/cached.ts +++ b/test/fixture/server/routes/api/cached.ts @@ -1,4 +1,6 @@ -export default defineCachedEventHandler( +import { defineCachedHandler } from "nitro/cache"; + +export default defineCachedHandler( (event) => { return { timestamp: Date.now(), diff --git a/test/fixture/api/db.ts b/test/fixture/server/routes/api/db.ts similarity index 85% rename from test/fixture/api/db.ts rename to test/fixture/server/routes/api/db.ts index e896d92ba8..1a4d75a445 100644 --- a/test/fixture/api/db.ts +++ b/test/fixture/server/routes/api/db.ts @@ -1,4 +1,6 @@ -export default defineEventHandler(async () => { +import { useDatabase } from "nitro/database"; + +export default async () => { const db = useDatabase(); // Create users table @@ -15,4 +17,4 @@ export default defineEventHandler(async () => { return { rows, }; -}); +}; diff --git a/test/fixture/api/echo.ts b/test/fixture/server/routes/api/echo.ts similarity index 59% rename from test/fixture/api/echo.ts rename to test/fixture/server/routes/api/echo.ts index c2b7b157cb..5e93b3cdba 100644 --- a/test/fixture/api/echo.ts +++ b/test/fixture/server/routes/api/echo.ts @@ -1,4 +1,6 @@ -export default eventHandler((event) => { +import { defineHandler } from "nitro/h3"; + +export default defineHandler((event) => { return { url: event.path, method: event.method, diff --git a/test/fixture/server/routes/api/headers.ts b/test/fixture/server/routes/api/headers.ts new file mode 100644 index 0000000000..44b1592610 --- /dev/null +++ b/test/fixture/server/routes/api/headers.ts @@ -0,0 +1,15 @@ +import { defineHandler, setCookie } from "nitro/h3"; + +export default defineHandler((event) => { + event.res.headers.set("x-foo", "bar"); + event.res.headers.append("x-array", "foo"); + event.res.headers.append("x-array", "bar"); + + // setHeader(event, "Set-Cookie", "foo=bar, bar=baz"); + event.res.headers.append("Set-Cookie", "foo=bar"); + event.res.headers.append("Set-Cookie", "bar=baz"); + setCookie(event, "test", "value"); + setCookie(event, "test2", "value"); + + return "headers sent"; +}); diff --git a/test/fixture/server/routes/api/hello.ts b/test/fixture/server/routes/api/hello.ts new file mode 100644 index 0000000000..a60e00439b --- /dev/null +++ b/test/fixture/server/routes/api/hello.ts @@ -0,0 +1 @@ +export default () => ({ message: "Hello API" }); diff --git a/test/fixture/server/routes/api/hey/index.get.ts b/test/fixture/server/routes/api/hey/index.get.ts new file mode 100644 index 0000000000..04ce79c5cb --- /dev/null +++ b/test/fixture/server/routes/api/hey/index.get.ts @@ -0,0 +1,6 @@ +import { defineHandler } from "nitro/h3"; + +export default defineHandler((event) => { + event.res.headers.set("Content-Type", "text/html"); + return "Hey API"; +}); diff --git a/test/fixture/server/routes/api/kebab.ts b/test/fixture/server/routes/api/kebab.ts new file mode 100644 index 0000000000..5727bf89b6 --- /dev/null +++ b/test/fixture/server/routes/api/kebab.ts @@ -0,0 +1,3 @@ +import { kebabCase } from "scule"; + +export default () => kebabCase("HelloWorld"); diff --git a/test/fixture/api/meta/test.ts b/test/fixture/server/routes/api/meta/test.ts similarity index 70% rename from test/fixture/api/meta/test.ts rename to test/fixture/server/routes/api/meta/test.ts index f58b646dfe..6f7c7b8c6a 100644 --- a/test/fixture/api/meta/test.ts +++ b/test/fixture/server/routes/api/meta/test.ts @@ -1,8 +1,17 @@ +import { defineRouteMeta } from "nitro"; + defineRouteMeta({ openAPI: { tags: ["test"], description: "Test route description", - parameters: [{ in: "query", name: "test", required: true }], + parameters: [ + { in: "query", name: "test", required: true }, + { + in: "query", + name: "val", + schema: { type: "integer", enum: [0, 1] }, + }, + ], responses: { 200: { description: "result", @@ -29,8 +38,8 @@ defineRouteMeta({ }, }); -export default defineEventHandler(() => { +export default () => { return { status: "OK", }; -}); +}; diff --git a/test/fixture/server/routes/api/methods/foo.get.get.ts b/test/fixture/server/routes/api/methods/foo.get.get.ts new file mode 100644 index 0000000000..19ce3fea40 --- /dev/null +++ b/test/fixture/server/routes/api/methods/foo.get.get.ts @@ -0,0 +1 @@ +export default () => "foo.get"; diff --git a/test/fixture/server/routes/api/methods/get.ts b/test/fixture/server/routes/api/methods/get.ts new file mode 100644 index 0000000000..9f690fd9ec --- /dev/null +++ b/test/fixture/server/routes/api/methods/get.ts @@ -0,0 +1 @@ +export default () => "get"; diff --git a/test/fixture/server/routes/api/param/[test-id].ts b/test/fixture/server/routes/api/param/[test-id].ts new file mode 100644 index 0000000000..34345e1f72 --- /dev/null +++ b/test/fixture/server/routes/api/param/[test-id].ts @@ -0,0 +1,6 @@ +import { defineHandler } from "nitro/h3"; + +export default defineHandler((event) => { + event.res.headers.set("Content-Type", "text/plain; custom"); + return event.context.params!["test-id"]; +}); diff --git a/test/fixture/server/routes/api/storage/item.get.ts b/test/fixture/server/routes/api/storage/item.get.ts new file mode 100644 index 0000000000..3b6d7d1611 --- /dev/null +++ b/test/fixture/server/routes/api/storage/item.get.ts @@ -0,0 +1,15 @@ +import { defineHandler } from "nitro/h3"; +import { useStorage } from "nitro/storage"; + +export default defineHandler(async (event) => { + const base = event.url.searchParams.get("base") || ""; + const key = event.url.searchParams.get("key") || ""; + const storage = useStorage(`test:${base}`); + + if (!key || key.endsWith(":")) { + return await storage.getKeys(); + } + + const value = await storage.getItem(key); + return value; +}); diff --git a/test/fixture/server/routes/api/storage/item.put.ts b/test/fixture/server/routes/api/storage/item.put.ts new file mode 100644 index 0000000000..391b104c8b --- /dev/null +++ b/test/fixture/server/routes/api/storage/item.put.ts @@ -0,0 +1,11 @@ +import { defineHandler } from "nitro/h3"; +import { useStorage } from "nitro/storage"; + +export default defineHandler(async (event) => { + const base = event.url.searchParams.get("base") || ""; + const key = event.url.searchParams.get("key") || ""; + const storage = useStorage(`test:${base}`); + const value = await event.req.text(); + await storage.setItem(key, value); + return value; +}); diff --git a/test/fixture/server/routes/api/upload.post.ts b/test/fixture/server/routes/api/upload.post.ts new file mode 100644 index 0000000000..1850a8fb9f --- /dev/null +++ b/test/fixture/server/routes/api/upload.post.ts @@ -0,0 +1,3 @@ +export default () => { + return "uploaded!"; +}; diff --git a/test/fixture/server/routes/api/wildcard/[...param].ts b/test/fixture/server/routes/api/wildcard/[...param].ts new file mode 100644 index 0000000000..4ed517403d --- /dev/null +++ b/test/fixture/server/routes/api/wildcard/[...param].ts @@ -0,0 +1,5 @@ +import { defineHandler } from "nitro/h3"; + +export default defineHandler((event) => { + return event.context.params!.param as string; +}); diff --git a/test/fixture/server/routes/assets/[id].ts b/test/fixture/server/routes/assets/[id].ts new file mode 100644 index 0000000000..27929cc1f5 --- /dev/null +++ b/test/fixture/server/routes/assets/[id].ts @@ -0,0 +1,32 @@ +import { defineHandler, HTTPError } from "nitro/h3"; +import { useStorage } from "nitro/storage"; + +export default defineHandler(async (event) => { + const serverAssets = useStorage("assets/server"); + + const id = event.context.params!.id; + + if (!(await serverAssets.hasItem(id))) { + throw new HTTPError({ message: `Asset ${id} not found`, status: 404 }); + } + + const meta = (await serverAssets.getMeta(event.context.params!.id)) as unknown as { + type: string; + etag: string; + mtime: string; + }; + + if (meta.type) { + event.res.headers.set("content-type", meta.type); + } + + if (meta.etag) { + event.res.headers.set("etag", meta.etag); + } + + if (meta.mtime) { + event.res.headers.set("last-modified", meta.mtime); + } + + return serverAssets.getItemRaw(event.context.params!.id); +}); diff --git a/test/fixture/routes/assets/all.ts b/test/fixture/server/routes/assets/all.ts similarity index 68% rename from test/fixture/routes/assets/all.ts rename to test/fixture/server/routes/assets/all.ts index 58b16b9843..8e3b982660 100644 --- a/test/fixture/routes/assets/all.ts +++ b/test/fixture/server/routes/assets/all.ts @@ -1,4 +1,6 @@ -export default eventHandler(async (event) => { +import { useStorage } from "nitro/storage"; + +export default async () => { const serverAssets = useStorage("assets/server"); const keys = await serverAssets.getKeys(); @@ -16,10 +18,8 @@ export default eventHandler(async (event) => { ); return items; -}); +}; -function isPureObject(value) { - return ( - value !== null && typeof value === "object" && value.constructor === Object - ); +function isPureObject(value: unknown): boolean { + return value !== null && typeof value === "object" && value.constructor === Object; } diff --git a/test/fixture/server/routes/assets/md.ts b/test/fixture/server/routes/assets/md.ts new file mode 100644 index 0000000000..7d72dcdc83 --- /dev/null +++ b/test/fixture/server/routes/assets/md.ts @@ -0,0 +1,4 @@ +export default async () => { + const md = await import("raw:../../assets/test.md" as string).then((r) => r.default); + return md; +}; diff --git a/test/fixture/server/routes/config.ts b/test/fixture/server/routes/config.ts new file mode 100644 index 0000000000..be76a3b466 --- /dev/null +++ b/test/fixture/server/routes/config.ts @@ -0,0 +1,12 @@ +import { useRuntimeConfig } from "nitro/runtime-config"; + +const sharedRuntimeConfig = useRuntimeConfig(); + +export default () => { + const runtimeConfig = useRuntimeConfig(); + + return { + runtimeConfig, + sharedRuntimeConfig, + }; +}; diff --git a/test/fixture/routes/context.ts b/test/fixture/server/routes/context.ts similarity index 52% rename from test/fixture/routes/context.ts rename to test/fixture/server/routes/context.ts index c51deaa0dd..8d1be2da04 100644 --- a/test/fixture/routes/context.ts +++ b/test/fixture/server/routes/context.ts @@ -1,12 +1,16 @@ +import { defineEventHandler } from "nitro/h3"; +import { useRequest } from "nitro/context"; + export default defineEventHandler(async () => { await Promise.resolve(setTimeout(() => {}, 10)); return await useTest(); }); function useTest() { + const url = new URL(useRequest().url); return { context: { - path: useEvent().path, + path: url.pathname + url.search, }, }; } diff --git a/test/fixture/server/routes/env/index.dev.ts b/test/fixture/server/routes/env/index.dev.ts new file mode 100644 index 0000000000..ead6a063b6 --- /dev/null +++ b/test/fixture/server/routes/env/index.dev.ts @@ -0,0 +1 @@ +export default () => "dev env"; diff --git a/test/fixture/server/routes/env/index.get.prod.ts b/test/fixture/server/routes/env/index.get.prod.ts new file mode 100644 index 0000000000..a599488b5a --- /dev/null +++ b/test/fixture/server/routes/env/index.get.prod.ts @@ -0,0 +1 @@ +export default () => "prod env"; diff --git a/test/fixture/api/errors.ts b/test/fixture/server/routes/errors/captured.ts similarity index 53% rename from test/fixture/api/errors.ts rename to test/fixture/server/routes/errors/captured.ts index b1c4cff15c..a690fdfce8 100644 --- a/test/fixture/api/errors.ts +++ b/test/fixture/server/routes/errors/captured.ts @@ -1,9 +1,9 @@ -import { allErrors } from "../plugins/errors"; +import { allErrors } from "../../plugins/errors.ts"; -export default eventHandler((event) => { +export default () => { return { allErrors: allErrors.map((entry) => ({ message: entry.error.message, })), }; -}); +}; diff --git a/test/fixture/server/routes/errors/stack.ts b/test/fixture/server/routes/errors/stack.ts new file mode 100644 index 0000000000..35f415f50e --- /dev/null +++ b/test/fixture/server/routes/errors/stack.ts @@ -0,0 +1,5 @@ +export default async () => { + return { + stack: new Error("testing error").stack!.replace(/\\/g, "/"), + }; +}; diff --git a/test/fixture/server/routes/errors/throw.ts b/test/fixture/server/routes/errors/throw.ts new file mode 100644 index 0000000000..6a77149dcd --- /dev/null +++ b/test/fixture/server/routes/errors/throw.ts @@ -0,0 +1,23 @@ +import { H3Event, HTTPError } from "nitro/h3"; + +export default ({ url }: H3Event) => { + const unhandled = url.searchParams.has("unhandled"); + const shouldThrow = url.searchParams.get("action") === "throw"; + + const error = unhandled + ? new Error("Unhandled error") + : new HTTPError({ + status: 503, + statusText: "Custom Status Text", + message: "Handled error", + headers: { "x-custom-error": "custom-value" }, + data: { custom: "data" }, + body: { custom: "body" }, + }); + + if (shouldThrow) { + throw error; + } + + return error; +}; diff --git a/test/fixture/server/routes/fetch.ts b/test/fixture/server/routes/fetch.ts new file mode 100644 index 0000000000..c3efe92227 --- /dev/null +++ b/test/fixture/server/routes/fetch.ts @@ -0,0 +1,16 @@ +import { serverFetch as runtimeServerFetch, fetch as runtimeFetch, useNitroApp } from "nitro/app"; + +import { serverFetch as nitroServerFetch, fetch as nitroFetch } from "nitro"; + +export default async () => { + const nitroApp = useNitroApp(); + return { + "nitroApp.fetch": await Promise.resolve( + nitroApp.fetch(new Request(new URL("/api/hello", "http://localhost"))) + ).then((res) => res.json()), + "nitro/runtime.serverFetch": await runtimeServerFetch("/api/hello").then((res) => res.json()), + "nitro/runtime.fetch": await runtimeFetch("/api/hello").then((res) => res.json()), + "nitro/serverFetch": await nitroServerFetch("/api/hello").then((res) => res.json()), + "nitro/fetch": await nitroFetch("/api/hello").then((res) => res.json()), + }; +}; diff --git a/test/fixture/routes/file.ts b/test/fixture/server/routes/file.ts similarity index 56% rename from test/fixture/routes/file.ts rename to test/fixture/server/routes/file.ts index 698476fe34..98e255cd4e 100644 --- a/test/fixture/routes/file.ts +++ b/test/fixture/server/routes/file.ts @@ -1,6 +1,8 @@ -import { useStorage } from "nitropack/runtime"; +import { defineHandler, getQuery } from "nitro/h3"; -export default defineEventHandler(async (event) => { +import { useStorage } from "nitro/storage"; + +export default defineHandler(async (event) => { const query = getQuery(event); const filename = query?.filename || "index.html"; const serverAsset = await useStorage().getItem(`assets/files/${filename}`); diff --git a/test/fixture/routes/icon.png.ts b/test/fixture/server/routes/icon.png.ts similarity index 84% rename from test/fixture/routes/icon.png.ts rename to test/fixture/server/routes/icon.png.ts index 5f413f9dc1..122b6ac222 100644 --- a/test/fixture/routes/icon.png.ts +++ b/test/fixture/server/routes/icon.png.ts @@ -1,5 +1,7 @@ -export default defineEventHandler((event) => { - setHeader(event, "Content-Type", "image/png"); +import { defineHandler } from "nitro/h3"; + +export default defineHandler((event) => { + event.res.headers.set("Content-Type", "image/png"); return Buffer.from(_base64ToArray(_getLogoBase64())); }); @@ -11,7 +13,6 @@ function _base64ToArray(base64: string) { const str = atob(base64); const bytes = new Uint8Array(str.length); for (let i = 0; i < str.length; i++) { - // eslint-disable-next-line unicorn/prefer-code-point bytes[i] = str.charCodeAt(i); } return bytes; diff --git a/test/fixture/server/routes/imports.ts b/test/fixture/server/routes/imports.ts new file mode 100644 index 0000000000..746f8681f2 --- /dev/null +++ b/test/fixture/server/routes/imports.ts @@ -0,0 +1,10 @@ +import { testBarUtil } from "../utils/foo/bar/test.ts"; +import { testFooUtil } from "../utils/foo/test.ts"; +import { testUtil } from "../utils/test.ts"; + +export default () => { + return { + testUtil: testUtil(), + testNestedUtil: testFooUtil() + testBarUtil(), + }; +}; diff --git a/test/fixture/server/routes/json-string.ts b/test/fixture/server/routes/json-string.ts new file mode 100644 index 0000000000..2b6129da9f --- /dev/null +++ b/test/fixture/server/routes/json-string.ts @@ -0,0 +1,3 @@ +export default () => { + return '{"foo":"bar"}'; +}; diff --git a/test/fixture/server/routes/jsx.tsx b/test/fixture/server/routes/jsx.tsx new file mode 100644 index 0000000000..6a68e034a7 --- /dev/null +++ b/test/fixture/server/routes/jsx.tsx @@ -0,0 +1,5 @@ +export default () => ( + +

Hello JSX!

+ +); diff --git a/test/fixture/routes/modules.ts b/test/fixture/server/routes/modules.ts similarity index 75% rename from test/fixture/routes/modules.ts rename to test/fixture/server/routes/modules.ts index 67613f548e..b311cefb2e 100644 --- a/test/fixture/routes/modules.ts +++ b/test/fixture/server/routes/modules.ts @@ -8,16 +8,13 @@ import depLib from "@fixture/nitro-lib"; import subpathLib from "@fixture/nitro-lib/subpath"; // @ts-ignore import extraUtils from "@fixture/nitro-utils/extra"; -// @ts-ignore -import extraUtilsAbsolute from "#fixture-nitro-utils-extra-absolute"; -export default defineEventHandler(() => { +export default () => { return { depA, // expected to all be 1.0.0 depB, // expected to all be 2.0.1 depLib, // expected to all be 2.0.0 subpathLib, // expected to 2.0.0 extraUtils, - extraUtilsAbsolute, }; -}); +}; diff --git a/test/fixture/routes/node-compat.ts b/test/fixture/server/routes/node-compat.ts similarity index 74% rename from test/fixture/routes/node-compat.ts rename to test/fixture/server/routes/node-compat.ts index a565588050..d022b437a0 100644 --- a/test/fixture/routes/node-compat.ts +++ b/test/fixture/server/routes/node-compat.ts @@ -1,5 +1,6 @@ import nodeAsyncHooks from "node:async_hooks"; import nodeCrypto from "node:crypto"; +import nodeTLS from "node:tls"; const nodeCompatTests = { globals: { @@ -13,11 +14,7 @@ const nodeCompatTests = { }, crypto: { createHash: () => { - return nodeCrypto - .createHash("sha256") - .update("hello") - .digest("hex") - .startsWith("2cf24"); + return nodeCrypto.createHash("sha256").update("hello").digest("hex").startsWith("2cf24"); }, }, async_hooks: { @@ -33,9 +30,21 @@ const nodeCompatTests = { }); }, }, + tls: { + connect: async () => { + // TODO: Use a local TLS server for testing + if ("Bun" in globalThis || "Deno" in globalThis) { + return true; + } + const socket = nodeTLS.connect(443, "1.1.1.1"); + await new Promise((r) => socket.on("connect", r)); + socket.end(); + return true; + }, + }, }; -export default eventHandler(async (event) => { +export default async () => { const results: Record = {}; for (const [group, groupTests] of Object.entries(nodeCompatTests)) { for (const [name, test] of Object.entries(groupTests)) { @@ -47,7 +56,7 @@ export default eventHandler(async (event) => { "Content-Type": "application/json", }, }); -}); +}; async function testFn(fn: () => any) { try { diff --git a/test/fixture/routes/prerender-custom.html.ts b/test/fixture/server/routes/prerender-custom.html.ts similarity index 89% rename from test/fixture/routes/prerender-custom.html.ts rename to test/fixture/server/routes/prerender-custom.html.ts index cef5c14d0b..b13f361df9 100644 --- a/test/fixture/routes/prerender-custom.html.ts +++ b/test/fixture/server/routes/prerender-custom.html.ts @@ -1,4 +1,4 @@ -export default defineEventHandler((event) => { +export default () => { const links = ["/api/hello", "/api/param/foo.json", "/api/param/foo.css"]; return ` @@ -14,4 +14,4 @@ ${links.map((link) => `
  • ${link}
  • `).join("\n")} `; -}); +}; diff --git a/test/fixture/server/routes/prerender.ts b/test/fixture/server/routes/prerender.ts new file mode 100644 index 0000000000..0a55ce6b0b --- /dev/null +++ b/test/fixture/server/routes/prerender.ts @@ -0,0 +1,39 @@ +import { defineHandler } from "nitro/h3"; + +export default defineHandler((event) => { + const links = [ + "/404", + "https://about.google/products/", + "/api/hello?bar=baz", + "/api/hello?bar=baz&bing=bap", + "/api/hello?bar=baz&foo=qux", + "/prerender#foo", + "../api/hey", + "/json-string", + event.url.href.includes("?") ? "/api/param/hidden" : "/prerender?withQuery", + ]; + + event.res.headers.append("x-nitro-prerender", "/api/param/prerender1, /api/param/prerender2"); + event.res.headers.append("x-nitro-prerender", "/api/param/prerender3"); + + event.res.headers.set("content-type", "text/html"); + return /* html */ ` + + + + Prerendered routes test + + +

    Prerendered routes test:

    +
      +${links.map((link) => `
    • ${link}
    • `).join("\n")} +
    + + + x-href attr + <a href="/500</a> + #a + #b + +`; +}); diff --git a/test/fixture/routes/raw.ts b/test/fixture/server/routes/raw.ts similarity index 65% rename from test/fixture/routes/raw.ts rename to test/fixture/server/routes/raw.ts index 1a9fd878c8..8e90c350f0 100644 --- a/test/fixture/routes/raw.ts +++ b/test/fixture/server/routes/raw.ts @@ -1,12 +1,13 @@ // @ts-ignore -import sql from "../files/sql.sql"; +import sql from "raw:../files/sql.sql"; // https://github.com/nitrojs/nitro/issues/2836 +// @ts-ignore import sqlts from "../files/sqlts.sql"; -export default defineEventHandler(async () => { +export default async () => { return { sql: sql.trim(), sqlts: sqlts.trim(), }; -}); +}; diff --git a/test/fixture/server/routes/replace.ts b/test/fixture/server/routes/replace.ts new file mode 100644 index 0000000000..4e45d2bf17 --- /dev/null +++ b/test/fixture/server/routes/replace.ts @@ -0,0 +1,5 @@ +export default () => { + // #3672 + const { window: window$1 = globalThis } = {}; + return { window: typeof window$1 === "function" }; +}; diff --git a/test/fixture/server/routes/rules/[...slug].ts b/test/fixture/server/routes/rules/[...slug].ts new file mode 100644 index 0000000000..ce64f8c4cc --- /dev/null +++ b/test/fixture/server/routes/rules/[...slug].ts @@ -0,0 +1,3 @@ +import { defineHandler } from "nitro/h3"; + +export default defineHandler((event) => event.url.pathname); diff --git a/test/fixture/server/routes/static-flags.ts b/test/fixture/server/routes/static-flags.ts new file mode 100644 index 0000000000..e15f6ee31d --- /dev/null +++ b/test/fixture/server/routes/static-flags.ts @@ -0,0 +1,13 @@ +export default async () => { + return { + dev: import.meta.dev, + preset: import.meta.preset, + prerender: import.meta.prerender, + nitro: import.meta.nitro, + server: import.meta.server, + client: import.meta.client, + baseURL: import.meta.baseURL, + _asyncContext: import.meta._asyncContext, + _tasks: import.meta._tasks, + }; +}; diff --git a/test/fixture/routes/stream.ts b/test/fixture/server/routes/stream.ts similarity index 88% rename from test/fixture/routes/stream.ts rename to test/fixture/server/routes/stream.ts index 1b82b61355..abfdfc1bef 100644 --- a/test/fixture/routes/stream.ts +++ b/test/fixture/server/routes/stream.ts @@ -1,4 +1,4 @@ -export default eventHandler(() => { +export default () => { const encoder = new TextEncoder(); const stream = new ReadableStream({ start(controller) { @@ -9,4 +9,4 @@ export default eventHandler(() => { }, }); return stream; -}); +}; diff --git a/test/fixture/server/routes/tasks/[...name].ts b/test/fixture/server/routes/tasks/[...name].ts new file mode 100644 index 0000000000..a2c801216e --- /dev/null +++ b/test/fixture/server/routes/tasks/[...name].ts @@ -0,0 +1,13 @@ +import { defineHandler, getQuery } from "nitro/h3"; +import { runTask } from "nitro/task"; + +export default defineHandler(async (event) => { + const name = event.context.params!.name; + const payload = { ...getQuery(event) }; + const { result } = await runTask(name, { payload }); + return { + name, + payload, + result, + }; +}); diff --git a/test/fixture/routes/wait-until.ts b/test/fixture/server/routes/wait-until.ts similarity index 77% rename from test/fixture/routes/wait-until.ts rename to test/fixture/server/routes/wait-until.ts index 7ecfc073e3..d5660b237d 100644 --- a/test/fixture/routes/wait-until.ts +++ b/test/fixture/server/routes/wait-until.ts @@ -1,10 +1,12 @@ +import { defineHandler } from "nitro/h3"; + const timeTakingOperation = async () => { // console.log("wait-until.ts: timeTakingOperation() start"); await new Promise((resolve) => setTimeout(resolve, 100)); // console.log("wait-until.ts: timeTakingOperation() done"); }; -export default eventHandler((event) => { +export default defineHandler((event) => { event.waitUntil(timeTakingOperation()); return "done"; diff --git a/test/fixture/routes/wasm/dynamic-import.ts b/test/fixture/server/routes/wasm/dynamic-import.ts similarity index 59% rename from test/fixture/routes/wasm/dynamic-import.ts rename to test/fixture/server/routes/wasm/dynamic-import.ts index ffb9cb8a5c..c1adc1258f 100644 --- a/test/fixture/routes/wasm/dynamic-import.ts +++ b/test/fixture/server/routes/wasm/dynamic-import.ts @@ -1,9 +1,9 @@ +import { defineLazyEventHandler, defineHandler } from "nitro/h3"; + export default defineLazyEventHandler(async () => { // @ts-ignore - const { sum } = await import("unwasm/examples/sum.wasm").then((r) => - r.default() - ); - return eventHandler(() => { + const { sum } = await import("unwasm/examples/sum.wasm").then((r) => r.default()); + return defineHandler(() => { return `2+3=${sum(2, 3)}`; }); }); diff --git a/test/fixture/routes/wasm/static-import.ts b/test/fixture/server/routes/wasm/static-import.ts similarity index 64% rename from test/fixture/routes/wasm/static-import.ts rename to test/fixture/server/routes/wasm/static-import.ts index 201c687349..f8545483fb 100644 --- a/test/fixture/routes/wasm/static-import.ts +++ b/test/fixture/server/routes/wasm/static-import.ts @@ -1,9 +1,11 @@ +import { defineHandler, defineLazyEventHandler } from "nitro/h3"; + // @ts-ignore import init, { sum } from "unwasm/examples/sum.wasm"; export default defineLazyEventHandler(async () => { await init(); - return eventHandler(() => { + return defineHandler(() => { return `2+3=${sum(2, 3)}`; }); }); diff --git a/test/fixture/tasks/db/migrate.ts b/test/fixture/server/tasks/db/migrate.ts similarity index 81% rename from test/fixture/tasks/db/migrate.ts rename to test/fixture/server/tasks/db/migrate.ts index 2dd0f67a06..bb340ad2d7 100644 --- a/test/fixture/tasks/db/migrate.ts +++ b/test/fixture/server/tasks/db/migrate.ts @@ -1,3 +1,5 @@ +import { defineTask } from "nitro/task"; + export default defineTask({ meta: { description: "Run database migrations", diff --git a/test/fixture/tasks/test.ts b/test/fixture/server/tasks/test.ts similarity index 69% rename from test/fixture/tasks/test.ts rename to test/fixture/server/tasks/test.ts index 2fb0431d08..53411a689d 100644 --- a/test/fixture/tasks/test.ts +++ b/test/fixture/server/tasks/test.ts @@ -1,3 +1,5 @@ +import { defineTask } from "nitro/task"; + export default defineTask({ meta: { description: "task to debug", @@ -5,9 +7,7 @@ export default defineTask({ async run(taskEvent) { console.log("test task", taskEvent); if (taskEvent.payload.wait) { - await new Promise((resolve) => - setTimeout(resolve, Number(taskEvent.payload.wait)) - ); + await new Promise((resolve) => setTimeout(resolve, Number(taskEvent.payload.wait))); } if (taskEvent.payload.error) { throw new Error("test error"); diff --git a/test/fixture/utils/foo/bar/test.ts b/test/fixture/server/utils/foo/bar/test.ts similarity index 100% rename from test/fixture/utils/foo/bar/test.ts rename to test/fixture/server/utils/foo/bar/test.ts diff --git a/test/fixture/utils/foo/test.ts b/test/fixture/server/utils/foo/test.ts similarity index 100% rename from test/fixture/utils/foo/test.ts rename to test/fixture/server/utils/foo/test.ts diff --git a/test/fixture/utils/test.ts b/test/fixture/server/utils/test.ts similarity index 100% rename from test/fixture/utils/test.ts rename to test/fixture/server/utils/test.ts diff --git a/test/fixture/tsconfig.json b/test/fixture/tsconfig.json index dab12a8ca5..211d2c8473 100644 --- a/test/fixture/tsconfig.json +++ b/test/fixture/tsconfig.json @@ -1,55 +1,7 @@ { - "extends": "./.nitro/types/tsconfig.json", + "extends": "nitro/tsconfig", "compilerOptions": { - "noErrorTruncation": true, - "allowSyntheticDefaultImports": true, - "skipLibCheck": true, - "baseUrl": ".", - "strict": false, - "types": ["@cloudflare/workers-types"], - // (currently manually synced with top level tsconfig.json paths) - "paths": { - // CLI - "nitro/cli": ["../../src/cli"], - "nitropack/cli": ["../../src/cli"], - // Config - "nitro/config": ["../../src/config"], - "nitropack/config": ["../../src/config"], - // Core - "nitro/core": ["../../src/core"], - "nitropack/core": ["../../src/core"], - // Core alias - "nitro": ["../../src/core"], - "nitropack": ["../../src/core"], - // Runtime - "nitro/runtime": ["../../src/runtime"], - "nitropack/runtime": ["../../src/runtime"], - "nitro/runtime/meta": ["./runtime-meta"], - "nitropack/runtime/meta": ["./runtime-meta"], - "nitro/runtime/*": ["../../src/runtime/*"], - "nitropack/runtime/*": ["../../src/runtime/*"], - // Kit - "nitro/kit": ["../../src/kit"], - "nitropack/kit": ["../../src/kit"], - // Meta - "nitro/meta": ["../../src/meta"], - "nitropack/meta": ["../../src/meta"], - // Presets - "nitro/presets": ["../../src/presets"], - "nitropack/presets": ["../../src/presets"], - "nitro/presets/*": ["../../src/presets/*"], - "nitropack/presets/*": ["../../src/presets/*"], - // Rollup - "nitro/rollup": ["../../src/rollup"], - "nitropack/rollup": ["../../src/rollup"], - // Types - "nitro/types": ["../../src/types"], - "nitropack/types": ["../../src/types"], - // Virtual files - "#nitro-internal-virtual/*": ["../../src/types/virtual/*"], - // Compatibility (#internal/nitro) - "#internal/nitro": ["../../src/runtime/_compat"], - "#internal/nitro/*": ["../../src/runtime/_compat/*"] - } + "jsx": "react-jsx", + "jsxImportSource": "mono-jsx" } } diff --git a/test/fixture/types.ts b/test/fixture/types.ts deleted file mode 100644 index ff9a520d2b..0000000000 --- a/test/fixture/types.ts +++ /dev/null @@ -1,352 +0,0 @@ -import { expectTypeOf } from "expect-type"; -import { - type EventHandler, - type EventHandlerRequest, - defineEventHandler, -} from "h3"; -import { defineNitroConfig } from "nitropack/config"; -import type { $Fetch } from "nitropack/types"; -import type { Serialize, Simplify } from "nitropack/types"; -import { describe, it } from "vitest"; - -interface TestResponse { - message: string; -} - -const $fetch = {} as $Fetch; - -describe("API routes", () => { - const dynamicString: string = ""; - - it("generates types for middleware, unknown and manual typed routes", () => { - expectTypeOf($fetch("/")).toEqualTypeOf>(); // middleware - expectTypeOf($fetch("/api/unknown")).toEqualTypeOf>(); - expectTypeOf($fetch("/test")).toEqualTypeOf< - Promise - >(); - }); - - it("generates types for routes with exact matches", () => { - expectTypeOf($fetch("/api/hello")).toEqualTypeOf< - Promise<{ message: string }> - >(); - expectTypeOf($fetch("/api/typed/user/john")).toEqualTypeOf< - Promise<{ internalApiKey: "/api/typed/user/john" }> - >(); - expectTypeOf($fetch("/api/typed/user/john/post/coffee")).toEqualTypeOf< - Promise<{ internalApiKey: "/api/typed/user/john/post/coffee" }> - >(); - }); - - it("generates types for routes matching params", () => { - expectTypeOf($fetch("/api/typed/user/{someUserId}")).toEqualTypeOf< - Promise<{ internalApiKey: "/api/typed/user/:userId" }> - >(); - expectTypeOf( - $fetch("/api/typed/user/{someUserId}/{extends}") - ).toEqualTypeOf< - Promise<{ internalApiKey: "/api/typed/user/:userId/:userExtends" }> - >(); - expectTypeOf($fetch("/api/typed/user/john/{extends}")).toEqualTypeOf< - Promise<{ internalApiKey: "/api/typed/user/john/:johnExtends" }> - >(); - expectTypeOf( - $fetch("/api/typed/user/{someUserId}/post/{somePostId}") - ).toEqualTypeOf< - Promise<{ internalApiKey: "/api/typed/user/:userId/post/:postId" }> - >(); - }); - - it("generates types for routes (w/o dynamic template literal) and with param and exact matches", () => { - expectTypeOf( - $fetch("/api/typed/user/john/post/{somePostId}") - ).toEqualTypeOf< - Promise<{ internalApiKey: "/api/typed/user/john/post/:postId" }> - >(); - expectTypeOf( - $fetch(`/api/typed/user/${dynamicString}/post/firstPost`) - ).toEqualTypeOf< - Promise<{ internalApiKey: "/api/typed/user/:userId/post/firstPost" }> - >(); - expectTypeOf($fetch(`/api/typed/user/${dynamicString}`)).toEqualTypeOf< - Promise< - | { internalApiKey: "/api/typed/user/john" } - | { internalApiKey: "/api/typed/user/:userId" } - > - >(); - expectTypeOf( - $fetch(`/api/typed/user/john/post/${dynamicString}`) - ).toEqualTypeOf< - Promise< - | { internalApiKey: "/api/typed/user/john/post/coffee" } - | { internalApiKey: "/api/typed/user/john/post/:postId" } - > - >(); - expectTypeOf( - $fetch(`/api/typed/user/{someUserId}/post/${dynamicString}`) - ).toEqualTypeOf< - Promise< - | { internalApiKey: "/api/typed/user/:userId/post/:postId" } - | { internalApiKey: "/api/typed/user/:userId/post/firstPost" } - > - >(); - expectTypeOf( - $fetch(`/api/typed/user/${dynamicString}/post/${dynamicString}`) - ).toEqualTypeOf< - Promise< - | { internalApiKey: "/api/typed/user/john/post/coffee" } - | { internalApiKey: "/api/typed/user/john/post/:postId" } - | { internalApiKey: "/api/typed/user/:userId/post/:postId" } - | { internalApiKey: "/api/typed/user/:userId/post/firstPost" } - > - >(); - }); - - it("generates types for routes matching prefix", () => { - expectTypeOf($fetch("/api/hey/**")).toEqualTypeOf>(); - expectTypeOf($fetch("/api/param/{id}/**")).toEqualTypeOf>(); - expectTypeOf( - $fetch("/api/typed/user/{someUserId}/post/{somePostId}/**") - ).toEqualTypeOf< - Promise<{ internalApiKey: "/api/typed/user/:userId/post/:postId" }> - >(); - expectTypeOf($fetch("/api/typed/user/john/post/coffee/**")).toEqualTypeOf< - Promise<{ internalApiKey: "/api/typed/user/john/post/coffee" }> - >(); - expectTypeOf( - $fetch(`/api/typed/user/${dynamicString}/post/${dynamicString}/**`) - ).toEqualTypeOf< - Promise< - | { internalApiKey: "/api/typed/user/john/post/coffee" } - | { internalApiKey: "/api/typed/user/john/post/:postId" } - | { internalApiKey: "/api/typed/user/:userId/post/:postId" } - | { internalApiKey: "/api/typed/user/:userId/post/firstPost" } - > - >(); - }); - - it("ignores query suffixes", () => { - expectTypeOf($fetch("/api/hey?test=true")).toEqualTypeOf>(); - expectTypeOf($fetch("/api/hello?")).toEqualTypeOf< - Promise<{ message: string }> - >(); - }); - - it("generates types for routes matching Api keys with /** globs", () => { - expectTypeOf($fetch("/api/wildcard/foo/bar")).toEqualTypeOf< - Promise - >(); - expectTypeOf($fetch("/api/typed/todos/parent/child")).toEqualTypeOf< - Promise<{ internalApiKey: "/api/typed/todos/**" }> - >(); - expectTypeOf( - $fetch(`/api/typed/todos/${dynamicString}/child`) - ).toEqualTypeOf>(); - expectTypeOf( - $fetch(`/api/typed/todos/some/deeply/nest/${dynamicString}/path`) - ).toEqualTypeOf>(); - expectTypeOf( - $fetch("/api/typed/todos/firstTodo/comments/foo") - ).toEqualTypeOf< - Promise< - | { internalApiKey: "/api/typed/todos/**" } - | { internalApiKey: "/api/typed/todos/:todoId/comments/**:commentId" } - > - >(); - expectTypeOf( - $fetch(`/api/typed/todos/firstTodo/comments/${dynamicString}`) - ).toEqualTypeOf< - Promise< - | { internalApiKey: "/api/typed/todos/**" } - | { internalApiKey: "/api/typed/todos/:todoId/comments/**:commentId" } - > - >(); - expectTypeOf( - $fetch(`/api/typed/todos/${dynamicString}/${dynamicString}/foo/bar/baz`) - ).toEqualTypeOf< - Promise< - | { internalApiKey: "/api/typed/todos/**" } - | { internalApiKey: "/api/typed/todos/:todoId/comments/**:commentId" } - > - >(); - expectTypeOf( - $fetch(`/api/typed/catchall/${dynamicString}/foo/bar/baz`) - ).toEqualTypeOf< - Promise< - | { internalApiKey: "/api/typed/catchall/:slug/**:another" } - | { internalApiKey: "/api/typed/catchall/some/**:test" } - > - >(); - expectTypeOf($fetch("/api/typed/catchall/some/foo/bar/baz")).toEqualTypeOf< - Promise<{ internalApiKey: "/api/typed/catchall/some/**:test" }> - >(); - }); - - it("generates the correct type depending on the method used", () => { - expectTypeOf($fetch("/api/methods")).toEqualTypeOf>(); - expectTypeOf($fetch("/api/methods", {})).toEqualTypeOf< - Promise<"Index get"> - >(); - expectTypeOf($fetch("/api/methods", { query: {} })).toEqualTypeOf< - Promise<"Index get"> - >(); - expectTypeOf($fetch("/api/methods", { method: "get" })).toEqualTypeOf< - Promise<"Index get"> - >(); - expectTypeOf($fetch("/api/methods", { method: "post" })).toEqualTypeOf< - Promise<"Index post"> - >(); - expectTypeOf( - $fetch("/api/methods/default", { method: "GET" }) - ).toEqualTypeOf>(); - expectTypeOf( - $fetch("/api/methods/default", { method: "PUT" }) - ).toEqualTypeOf>(); - expectTypeOf( - $fetch("/api/methods/default", { method: "POST" }) - ).toEqualTypeOf>(); - }); - - it("generates types matching JSON serialization output", () => { - expectTypeOf($fetch("/api/serialized/date")).toEqualTypeOf< - Promise<{ - createdAt: string; - }> - >(); - - expectTypeOf($fetch("/api/serialized/error")).toEqualTypeOf< - Promise<{ - statusCode: number; - statusMessage?: string; - data?: NonNullable; - message: string; - }> - >(); - - expectTypeOf($fetch("/api/serialized/void")).toEqualTypeOf< - Promise - >(); - - expectTypeOf($fetch("/api/serialized/null")).toEqualTypeOf>(); - - expectTypeOf($fetch("/api/serialized/function")).toEqualTypeOf< - Promise<{}> - >(); - - expectTypeOf($fetch("/api/serialized/map")).toEqualTypeOf< - Promise<{ - foo: Record; - }> - >(); - - expectTypeOf($fetch("/api/serialized/set")).toEqualTypeOf< - Promise<{ - foo: Record; - }> - >(); - - expectTypeOf($fetch("/api/serialized/tuple")).toEqualTypeOf< - Promise<[string, string]> - >(); - }); -}); - -describe("defineNitroConfig", () => { - it("should not accept functions to routeRules.cache", () => { - defineNitroConfig({ - compatibilityDate: "2025-03-01", - routeRules: { - "/**": { - cache: { - // @ts-expect-error - shouldBypassCache(event) { - return false; - }, - }, - }, - }, - }); - }); -}); - -async function fixture() { - await Promise.resolve(); - return { - message: "Hello world", - }; -} - -describe("defineCachedEventHandler", () => { - it("should infer return type", () => { - const a = defineCachedEventHandler(fixture); - const b = defineEventHandler(fixture); - expectTypeOf(a).toEqualTypeOf(b); - expectTypeOf(b).toEqualTypeOf< - EventHandler< - EventHandlerRequest, - Promise<{ - message: string; - }> - > - >(); - }); - it("should not allow typed input body", () => { - const b = defineCachedEventHandler< - { body: string }, - Promise<{ message: string }> - >(fixture); - expectTypeOf(b).toEqualTypeOf< - EventHandler<{}, Promise<{ message: string }>> - >(); - }); - it("is backwards compatible with old generic signature", () => { - // prettier-ignore - const a = - defineCachedEventHandler< - Promise<{ - message: string; - }> - >(fixture); - const b = defineEventHandler(fixture); - expectTypeOf(a).toEqualTypeOf(b); - expectTypeOf(b).toEqualTypeOf< - EventHandler< - EventHandlerRequest, - Promise<{ - message: string; - }> - > - >(); - }); -}); - -describe("type helpers", () => { - it("Serialize", () => { - expectTypeOf>().toEqualTypeOf(); - expectTypeOf>().toEqualTypeOf<{ - test?: string; - }>(); - expectTypeOf>().toEqualTypeOf<{ test: string }>(); - expectTypeOf>().toEqualTypeOf<{ - test?: string; - }>(); - expectTypeOf }>>().toEqualTypeOf<{ - test: Record; - }>(); - expectTypeOf< - Serialize<{ nested: { test: Map } }> - >().toEqualTypeOf<{ nested: { test: Record } }>(); - }); - - it("Simplify", () => { - expectTypeOf>>().toEqualTypeOf<{ - test: string; - }>(); - expectTypeOf< - Simplify }>> - >().toEqualTypeOf<{ test: Record }>(); - expectTypeOf< - Simplify } }>> - >().toEqualTypeOf<{ nested: { test: Record } }>(); - }); -}); diff --git a/test/fixture/vite.config.ts b/test/fixture/vite.config.ts new file mode 100644 index 0000000000..dc884054e6 --- /dev/null +++ b/test/fixture/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ + plugins: [nitro()], +}); diff --git a/test/fixture/wrangler.toml b/test/fixture/wrangler.toml index 1e79a22a7e..7a01b0b70b 100644 --- a/test/fixture/wrangler.toml +++ b/test/fixture/wrangler.toml @@ -1 +1 @@ -compatibility_flags = [ "nodejs_compat" ] +compatibility_flags = ["nodejs_compat"] diff --git a/test/minimal/minimal.test.ts b/test/minimal/minimal.test.ts new file mode 100644 index 0000000000..7779860c94 --- /dev/null +++ b/test/minimal/minimal.test.ts @@ -0,0 +1,90 @@ +import { afterAll, describe, expect, it } from "vitest"; +import { createNitro, build, prepare } from "nitro/builder"; +import { join } from "node:path"; +import { fileURLToPath } from "node:url"; +import { mkdir, rm, stat } from "node:fs/promises"; +import { glob } from "tinyglobby"; + +const fixtureDir = fileURLToPath(new URL("./", import.meta.url)); +const tmpDir = fileURLToPath(new URL(".tmp", import.meta.url)); + +// Rounded up +const bundleSizes: Record = { + rollup: [16, 8], + rolldown: [16, 8], + vite: [16, 8], + vite7: [16, 8], +}; + +describe("minimal fixture", () => { + const builders = ["rolldown", "rollup", "vite", "vite7"] as const; + const results: any[] = []; + + for (const builder of builders) { + for (const minify of [false, true]) { + describe(`${builder} (${minify ? "minified" : "unminified"})`, () => { + let buildTime: number, outDir: string; + it("build", async () => { + outDir = join(tmpDir, "output", builder + (minify ? "-min" : "")); + await rm(outDir, { recursive: true, force: true }); + await mkdir(outDir, { recursive: true }); + const nitro = await createNitro({ + rootDir: fixtureDir, + minify, + output: { dir: outDir }, + // @ts-expect-error for testing + __vitePkg__: builder, + builder: builder.includes("vite") ? "vite" : (builder as "rollup" | "rolldown"), + }); + await prepare(nitro); + const start = Date.now(); + await build(nitro); + buildTime = Date.now() - start; + }); + + it("server entry works", async () => { + const entry = join(outDir, "server/index.mjs"); + const { fetch } = await import(entry).then((m) => m.default); + const res = await fetch(new Request("http://localhost/")); + expect(res.status).toBe(200); + expect(await res.text()).toBe("ok"); + }); + + it("bundle size", async () => { + const { sizeKB } = await analyzeDir(outDir); + const expectedSize = bundleSizes[builder]![minify ? 1 : 0]; + expect(Math.round(sizeKB)).within(expectedSize - 1, expectedSize + 1); + + results.push({ + builder: builder + (minify ? " (minified)" : ""), + size: sizeKB.toFixed(2) + " kB", + time: `${buildTime}ms`, + }); + }); + }); + } + } + + if (process.env.TEST_DEBUG) { + afterAll(() => { + console.table(results); + }); + } +}); + +async function analyzeDir(cwd: string) { + const files = await glob("**/*", { cwd, dot: true }); + let sizeBytes = 0; + await Promise.all( + files.map(async (file) => { + const { size } = await stat(join(cwd, file)); + sizeBytes += size; + }) + ); + + return { + sizeBytes, + sizeKB: sizeBytes / 1024, + fileCount: files.length, + }; +} diff --git a/test/minimal/nitro.config.ts b/test/minimal/nitro.config.ts new file mode 100644 index 0000000000..b04792d8e6 --- /dev/null +++ b/test/minimal/nitro.config.ts @@ -0,0 +1,6 @@ +import { defineNitroConfig } from "nitro/config"; + +export default defineNitroConfig({ + preset: "standard", + // sourcemap: false, +}); diff --git a/test/minimal/package.json b/test/minimal/package.json new file mode 100644 index 0000000000..b6124e5f53 --- /dev/null +++ b/test/minimal/package.json @@ -0,0 +1,12 @@ +{ + "name": "nitro-test-fixture-minimal", + "version": "1.0.0", + "type": "module", + "scripts": { + "test": "TEST_DEBUG=1 vitest" + }, + "devDependencies": { + "nitro": "latest", + "vite": "beta" + } +} diff --git a/test/minimal/server.ts b/test/minimal/server.ts new file mode 100644 index 0000000000..f60751c04d --- /dev/null +++ b/test/minimal/server.ts @@ -0,0 +1,5 @@ +export default { + fetch(_req: Request) { + return new Response("ok"); + }, +}; diff --git a/test/minimal/tsconfig.json b/test/minimal/tsconfig.json new file mode 100644 index 0000000000..4b886bd47e --- /dev/null +++ b/test/minimal/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "nitro/tsconfig" +} diff --git a/test/minimal/vite.config.mjs b/test/minimal/vite.config.mjs new file mode 100644 index 0000000000..8812d54087 --- /dev/null +++ b/test/minimal/vite.config.mjs @@ -0,0 +1,6 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ + plugins: [!process.env.TEST && nitro()], +}); diff --git a/test/presets/aws-lambda.test.ts b/test/presets/aws-lambda.test.ts index 2717fedd32..43b4a5f7e9 100644 --- a/test/presets/aws-lambda.test.ts +++ b/test/presets/aws-lambda.test.ts @@ -1,77 +1,96 @@ import type { APIGatewayProxyEvent, APIGatewayProxyEventV2 } from "aws-lambda"; -import destr from "destr"; import { resolve } from "pathe"; import { describe } from "vitest"; -import { setupTest, testNitro } from "../tests"; +import { parseURL, parseQuery } from "ufo"; +import { setupTest, testNitro } from "../tests.ts"; -describe("nitro:preset:aws-lambda", async () => { +describe("nitro:preset:aws-lambda-v2", async () => { const ctx = await setupTest("aws-lambda"); - // Lambda v1 paylod - testNitro({ ...ctx, lambdaV1: true }, async () => { - const { handler } = await import(resolve(ctx.outDir, "server/index.mjs")); - return async ({ url: rawRelativeUrl, headers, method, body }) => { - // creating new URL object to parse query easier - const url = new URL(`https://example.com${rawRelativeUrl}`); - const queryStringParameters = Object.fromEntries( - url.searchParams.entries() - ); - const event: Partial = { - resource: "/my/path", - path: url.pathname, - headers: headers || {}, - httpMethod: method || "GET", - queryStringParameters, - body: body || "", - }; - const res = await handler(event); - return makeResponse(res); - }; - }); - // Lambda v2 paylod testNitro(ctx, async () => { const { handler } = await import(resolve(ctx.outDir, "server/index.mjs")); - return async ({ url: rawRelativeUrl, headers, method, body }) => { - // creating new URL object to parse query easier - const url = new URL(`https://example.com${rawRelativeUrl}`); - const queryStringParameters = Object.fromEntries( - url.searchParams.entries() - ); - const event: Partial = { - rawPath: url.pathname, + return async ({ url, headers, method, body }) => { + const { pathname, search } = parseURL(url); + const event = { + rawPath: pathname, headers: headers || {}, + rawQueryString: search.slice(1), + queryStringParameters: parseQuery(search) as Record, + body: body || "", + isBase64Encoded: false, + version: "2", + routeKey: "", requestContext: { - ...Object.fromEntries([ - ["accountId"], - ["apiId"], - ["domainName"], - ["domainPrefix"], - ]), + accountId: "", + apiId: "", + domainName: "", + domainPrefix: "", + requestId: "", + routeKey: "", + stage: "", + time: "", + timeEpoch: 0, http: { path: url.pathname, protocol: "http", - ...Object.fromEntries([["userAgent"], ["sourceIp"]]), + userAgent: "", + sourceIp: "", method: method || "GET", }, }, - queryStringParameters, + } satisfies APIGatewayProxyEventV2; + const res = await handler(event); + return webResponse(res); + }; + }); +}); + +describe("nitro:preset:aws-lambda-v1", async () => { + const ctx = await setupTest("aws-lambda"); + testNitro({ ...ctx, lambdaV1: true }, async () => { + const { handler } = await import(resolve(ctx.outDir, "server/index.mjs")); + return async ({ url, headers, method, body }) => { + const { pathname, search } = parseURL(url); + const event = { + stageVariables: {}, + resource: "", + httpMethod: method || "GET", + path: pathname, + pathParameters: {}, + queryStringParameters: parseQuery(search) as Record, + multiValueQueryStringParameters: {}, + headers: headers || {}, + multiValueHeaders: {}, body: body || "", - }; + isBase64Encoded: false, + requestContext: {} as any, + } satisfies APIGatewayProxyEvent; const res = await handler(event); - return makeResponse(res); + return webResponse(res); }; }); }); -const makeResponse = (response: any) => { - const headers = response.headers; +function webResponse(awsResponse: any) { + const headers = new Headers(awsResponse.headers); + const setCookie = + awsResponse?.cookies /* v2 */ ?? awsResponse?.multiValueHeaders /* v1 */?.["set-cookie"] ?? []; + headers.delete("set-cookie"); + for (const cookie of setCookie) { + if (Array.isArray(cookie)) { + for (const c of cookie) { + headers.append("set-cookie", c); + } + } else { + headers.append("set-cookie", cookie); + } + } - // APIgw v2 uses cookies, v1 uses multiValueHeaders - headers["set-cookie"] = - response?.cookies ?? response?.multiValueHeaders?.["set-cookie"]; + const body = awsResponse.isBase64Encoded + ? Buffer.from(awsResponse.body, "base64") + : (awsResponse.body as string); - return { - data: destr(response.body), - status: response.statusCode, + return new Response(body, { + status: awsResponse.statusCode, headers, - }; -}; + }); +} diff --git a/test/presets/azure.test.ts b/test/presets/azure-swa.test.ts similarity index 95% rename from test/presets/azure.test.ts rename to test/presets/azure-swa.test.ts index 1521d312cd..0b08693ddc 100644 --- a/test/presets/azure.test.ts +++ b/test/presets/azure-swa.test.ts @@ -3,9 +3,9 @@ import { execa } from "execa"; import { getRandomPort, waitForPort } from "get-port-please"; import { resolve } from "pathe"; import { describe, expect, it } from "vitest"; -import { setupTest, testNitro } from "../tests"; +import { setupTest, testNitro } from "../tests.ts"; -describe("nitro:preset:azure", { timeout: 10_000 }, async () => { +describe("nitro:preset:azure-swa", { timeout: 10_000 }, async () => { const customConfig = { routes: [ { @@ -39,7 +39,7 @@ describe("nitro:preset:azure", { timeout: 10_000 }, async () => { }, }; - const ctx = await setupTest("azure", { + const ctx = await setupTest("azure-swa", { config: { azure: { config: customConfig, diff --git a/test/presets/bun.test.ts b/test/presets/bun.test.ts index 95745eca43..1b5bbe556e 100644 --- a/test/presets/bun.test.ts +++ b/test/presets/bun.test.ts @@ -2,18 +2,16 @@ import { execa, execaCommandSync } from "execa"; import { getRandomPort, waitForPort } from "get-port-please"; import { resolve } from "pathe"; import { describe } from "vitest"; -import { setupTest, testNitro } from "../tests"; +import { setupTest, testNitro } from "../tests.ts"; -const hasBun = - execaCommandSync("bun --version", { stdio: "ignore", reject: false }) - .exitCode === 0; +const hasBun = execaCommandSync("bun --version", { stdio: "ignore", reject: false }).exitCode === 0; describe.runIf(hasBun)("nitro:preset:bun", async () => { const ctx = await setupTest("bun"); testNitro(ctx, async () => { const port = await getRandomPort(); process.env.PORT = String(port); - const p = execa("bun", [resolve(ctx.outDir, "server/index.mjs")], { + execa("bun", [resolve(ctx.outDir, "server/index.mjs")], { stdio: "inherit", }); ctx.server = { diff --git a/test/presets/cloudflare-module-legacy.test.ts b/test/presets/cloudflare-module-legacy.test.ts deleted file mode 100644 index 3efd039df6..0000000000 --- a/test/presets/cloudflare-module-legacy.test.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Miniflare } from "miniflare"; -import { resolve } from "pathe"; -import { Response as _Response } from "undici"; -import { describe } from "vitest"; - -import { setupTest, testNitro } from "../tests"; - -describe("nitro:preset:cloudflare-module-legacy", async () => { - const ctx = await setupTest("cloudflare-module-legacy", {}); - - testNitro(ctx, () => { - const mf = new Miniflare({ - modules: true, - scriptPath: resolve(ctx.outDir, "server/index.mjs"), - modulesRules: [{ type: "CompiledWasm", include: ["**/*.wasm"] }], - sitePath: resolve(ctx.outDir, "public"), - compatibilityFlags: ["streams_enable_constructors"], - bindings: { ...ctx.env }, - }); - - return async ({ url, headers, method, body }) => { - const res = await mf.dispatchFetch("http://localhost" + url, { - headers: headers || {}, - method: method || "GET", - redirect: "manual", - body, - }); - return res as unknown as Response; - }; - }); -}); diff --git a/test/presets/cloudflare-module.test.ts b/test/presets/cloudflare-module.test.ts index 5961ed6754..3ff44883d1 100644 --- a/test/presets/cloudflare-module.test.ts +++ b/test/presets/cloudflare-module.test.ts @@ -1,9 +1,9 @@ +import { promises as fsp } from "node:fs"; import { Miniflare } from "miniflare"; import { resolve } from "pathe"; -import { Response as _Response } from "undici"; -import { describe } from "vitest"; +import { describe, expect, it } from "vitest"; -import { setupTest, testNitro } from "../tests"; +import { setupTest, testNitro } from "../tests.ts"; describe("nitro:preset:cloudflare-module", async () => { const ctx = await setupTest("cloudflare-module"); @@ -11,6 +11,7 @@ describe("nitro:preset:cloudflare-module", async () => { testNitro(ctx, () => { const mf = new Miniflare({ modules: true, + compatibilityDate: "2025-04-01", scriptPath: resolve(ctx.outDir, "server/index.mjs"), modulesRules: [{ type: "CompiledWasm", include: ["**/*.wasm"] }], assets: { @@ -22,11 +23,7 @@ describe("nitro:preset:cloudflare-module", async () => { not_found_handling: "none" /* default */, }, }, - compatibilityFlags: [ - "streams_enable_constructors", - "nodejs_compat", - "no_nodejs_compat_v2", - ], + compatibilityFlags: ["nodejs_compat", "no_nodejs_compat_v2"], bindings: { ...ctx.env }, }); @@ -37,7 +34,22 @@ describe("nitro:preset:cloudflare-module", async () => { redirect: "manual", body, }); + return res as unknown as Response; }; }); + + it("should export the correct functions", async () => { + const entry = await fsp.readFile(resolve(ctx.outDir, "server", "index.mjs"), "utf8"); + expect(entry).toMatch(/export \{.*myScheduled.*\}/); + }); + + it("should auto-generate cron triggers in wrangler.json", async () => { + const wranglerConfig = await fsp + .readFile(resolve(ctx.outDir, "server", "wrangler.json"), "utf8") + .then((r) => JSON.parse(r)); + expect(wranglerConfig.triggers).toEqual({ + crons: ["* * * * *"], + }); + }); }); diff --git a/test/presets/cloudflare-pages.test.ts b/test/presets/cloudflare-pages.test.ts index 3a5a70965a..9f833bd154 100644 --- a/test/presets/cloudflare-pages.test.ts +++ b/test/presets/cloudflare-pages.test.ts @@ -1,11 +1,10 @@ import { promises as fsp } from "node:fs"; import { Miniflare } from "miniflare"; import { resolve } from "pathe"; -import { Response as _Response } from "undici"; import { describe, expect, it } from "vitest"; import { isWindows } from "std-env"; -import { setupTest, testNitro } from "../tests"; +import { setupTest, testNitro } from "../tests.ts"; describe.skipIf(isWindows)("nitro:preset:cloudflare-pages", async () => { const ctx = await setupTest("cloudflare-pages"); @@ -13,13 +12,10 @@ describe.skipIf(isWindows)("nitro:preset:cloudflare-pages", async () => { testNitro(ctx, () => { const mf = new Miniflare({ modules: true, + compatibilityDate: "2025-04-01", scriptPath: resolve(ctx.outDir, "_worker.js", "index.js"), modulesRules: [{ type: "CompiledWasm", include: ["**/*.wasm"] }], - compatibilityFlags: [ - "streams_enable_constructors", - "nodejs_compat", - "no_nodejs_compat_v2", - ], + compatibilityFlags: ["nodejs_compat", "no_nodejs_compat_v2"], sitePath: "", bindings: { ...ctx.env }, }); @@ -48,21 +44,26 @@ describe.skipIf(isWindows)("nitro:preset:cloudflare-pages", async () => { "/_openapi.json", "/_openapi.json.br", "/_openapi.json.gz", + "/_openapi.json.zst", "/_scalar", "/_swagger", - "/_unignored.txt", "/favicon.ico", "/foo.css", "/foo.js", "/json-string", "/prerender", "/prerender-custom", + "/_scalar/index.html.br", + "/_scalar/index.html.gz", + "/_scalar/index.html.zst", "/_swagger/index.html.br", "/_swagger/index.html.gz", + "/_swagger/index.html.zst", "/api/hello", "/api/hey", "/prerender/index.html.br", "/prerender/index.html.gz", + "/prerender/index.html.zst", "/api/param/foo.json", "/api/param/hidden", "/api/param/prerender1", @@ -76,4 +77,9 @@ describe.skipIf(isWindows)("nitro:preset:cloudflare-pages", async () => { } `); }); + + it("should export the correct functions", async () => { + const entry = await fsp.readFile(resolve(ctx.outDir, "_worker.js", "index.js"), "utf8"); + expect(entry).toMatch(/export \{.*myScheduled.*\}/); + }); }); diff --git a/test/presets/cloudflare-worker.test.ts b/test/presets/cloudflare-worker.test.ts deleted file mode 100644 index 7c2a587845..0000000000 --- a/test/presets/cloudflare-worker.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Miniflare } from "miniflare"; -import { resolve } from "pathe"; -import { describe } from "vitest"; - -import { setupTest, testNitro } from "../tests"; - -describe("nitro:preset:cloudflare-worker", async () => { - const ctx = await setupTest("cloudflare-worker"); - testNitro(ctx, () => { - const mf = new Miniflare({ - scriptPath: resolve(ctx.outDir, "server/index.mjs"), - bindings: { ...ctx.env }, - compatibilityFlags: ["streams_enable_constructors"], - }); - return async ({ url, headers, method, body }) => { - const res = await mf.dispatchFetch("http://localhost" + url, { - headers: headers || {}, - method: method || "GET", - redirect: "manual", - body, - }); - return res as unknown as Response; - }; - }); -}); diff --git a/test/presets/deno-server.test.ts b/test/presets/deno-server.test.ts index fa9024ae6d..977e995d5b 100644 --- a/test/presets/deno-server.test.ts +++ b/test/presets/deno-server.test.ts @@ -1,17 +1,16 @@ import { execa, execaCommandSync } from "execa"; import { getRandomPort, waitForPort } from "get-port-please"; import { describe } from "vitest"; -import { setupTest, testNitro } from "../tests"; +import { setupTest, testNitro } from "../tests.ts"; const hasDeno = - execaCommandSync("deno --version", { stdio: "ignore", reject: false }) - .exitCode === 0; + execaCommandSync("deno --version", { stdio: "ignore", reject: false }).exitCode === 0; describe.runIf(hasDeno)("nitro:preset:deno-server", async () => { const ctx = await setupTest("deno-server"); testNitro(ctx, async () => { const port = await getRandomPort(); - const p = execa("deno", ["task", "start"], { + execa("deno", ["task", "start"], { cwd: ctx.outDir, // stdio: "inherit", stdio: "ignore", diff --git a/test/presets/netlify-legacy.test.ts b/test/presets/netlify-legacy.test.ts deleted file mode 100644 index a122c62188..0000000000 --- a/test/presets/netlify-legacy.test.ts +++ /dev/null @@ -1,176 +0,0 @@ -import { promises as fsp } from "node:fs"; -import type { APIGatewayEvent, Handler } from "aws-lambda"; -import destr from "destr"; -import { resolve } from "pathe"; -import { describe, expect, it } from "vitest"; -import { generateCatchAllRedirects } from "../../src/presets/netlify/legacy/utils"; -import { getPresetTmpDir, setupTest, testNitro } from "../tests"; - -describe("nitro:preset:netlify-legacy", async () => { - const ctx = await setupTest("netlify-legacy", { - compatibilityDate: "2024-01-01", - config: { - output: { - publicDir: resolve(getPresetTmpDir("netlify-legacy"), "dist"), - }, - netlify: { - images: { - remote_images: ["https://example.com/.*"], - }, - }, - }, - }); - testNitro( - ctx, - async () => { - const { handler } = (await import( - resolve(ctx.outDir, "server/server.mjs") - )) as { handler: Handler }; - return async ({ url: rawRelativeUrl, headers, method, body }) => { - // creating new URL object to parse query easier - const url = new URL(`https://example.com${rawRelativeUrl}`); - const queryStringParameters = Object.fromEntries( - url.searchParams.entries() - ); - const event: Partial = { - resource: "/my/path", - path: url.pathname, - headers: headers || {}, - httpMethod: method || "GET", - queryStringParameters, - body: body || "", - }; - const res = await handler(event, {} as any, () => {}); - const resHeaders = { ...res.headers, ...res.multiValueHeaders }; - return { - data: destr(res.body), - status: res.statusCode, - headers: resHeaders, - }; - }; - }, - () => { - it("should add route rules - redirects", async () => { - const redirects = await fsp.readFile( - resolve(ctx.outDir, "../dist/_redirects"), - "utf8" - ); - - expect(redirects).toMatchInlineSnapshot(` - "/rules/nested/override /other 302 - /rules/redirect/wildcard/* https://nitro.build/:splat 302 - /rules/redirect/obj https://nitro.build/ 301 - /rules/nested/* /base 302 - /rules/redirect /base 302 - /rules/_/cached/noncached /.netlify/functions/server 200 - /rules/_/noncached/cached /.netlify/builders/server 200 - /rules/_/cached/* /.netlify/builders/server 200 - /rules/_/noncached/* /.netlify/functions/server 200 - /rules/swr-ttl/* /.netlify/builders/server 200 - /rules/swr/* /.netlify/builders/server 200 - /rules/isr-ttl/* /.netlify/builders/server 200 - /rules/isr/* /.netlify/builders/server 200 - /rules/dynamic /.netlify/functions/server 200 - /build/* /build/:splat 200 - /* /.netlify/functions/server 200" - `); - }); - it("should add route rules - headers", async () => { - const headers = await fsp.readFile( - resolve(ctx.outDir, "../dist/_headers"), - "utf8" - ); - - expect(headers).toMatchInlineSnapshot(` - "/rules/headers - cache-control: s-maxage=60 - /rules/cors - access-control-allow-origin: * - access-control-allow-methods: GET - access-control-allow-headers: * - access-control-max-age: 0 - /rules/nested/* - x-test: test - /build/* - cache-control: public, max-age=3600, immutable - /* - x-test: test - " - `); - }); - it("should write config.json", async () => { - const config = await fsp - .readFile(resolve(ctx.outDir, "../deploy/v1/config.json"), "utf8") - .then((r) => JSON.parse(r)); - expect(config).toMatchInlineSnapshot(` - { - "images": { - "remote_images": [ - "https://example.com/.*", - ], - }, - } - `); - }); - } - ); - - describe("generateCatchAllRedirects", () => { - it("returns empty string if `catchAllPath` is not defined", () => { - expect(generateCatchAllRedirects([], undefined)).toEqual(""); - }); - - it("includes a redirect from `/*` to `catchAllPath` if defined", () => { - expect(generateCatchAllRedirects([], "/catch-all")).toEqual( - "/* /catch-all 200" - ); - }); - - it("includes a splat redirect for each non-fallthrough non-root public asset path, BEFORE the catch-all", () => { - const publicAssets = [ - { - fallthrough: true, - baseURL: "with-fallthrough", - dir: "with-fallthrough-dir", - maxAge: 0, - }, - { - fallthrough: true, - dir: "with-fallthrough-no-baseURL-dir", - maxAge: 0, - }, - { - fallthrough: false, - dir: "no-fallthrough-no-baseURL-dir", - maxAge: 0, - }, - { - fallthrough: false, - dir: "no-fallthrough-root-baseURL-dir", - baseURL: "/", - maxAge: 0, - }, - { - baseURL: "with-default-fallthrough", - dir: "with-default-fallthrough-dir", - maxAge: 0, - }, - { - fallthrough: false, - baseURL: "nested/no-fallthrough", - dir: "nested/no-fallthrough-dir", - maxAge: 0, - }, - ]; - expect( - generateCatchAllRedirects(publicAssets, "/catch-all") - ).toMatchInlineSnapshot( - ` - "/with-default-fallthrough/* /with-default-fallthrough/:splat 200 - /nested/no-fallthrough/* /nested/no-fallthrough/:splat 200 - /* /catch-all 200" - ` - ); - }); - }); -}); diff --git a/test/presets/netlify.test.ts b/test/presets/netlify.test.ts index 7eeed588a1..cf89a93cc9 100644 --- a/test/presets/netlify.test.ts +++ b/test/presets/netlify.test.ts @@ -2,8 +2,8 @@ import { promises as fsp } from "node:fs"; import type { Context as FunctionContext } from "@netlify/functions"; import { resolve } from "pathe"; import { describe, expect, it } from "vitest"; -import { getStaticPaths } from "../../src/presets/netlify/utils"; -import { getPresetTmpDir, setupTest, testNitro } from "../tests"; +import { getStaticPaths } from "../../src/presets/netlify/utils.ts"; +import { getPresetTmpDir, setupTest, testNitro } from "../tests.ts"; describe("nitro:preset:netlify", async () => { const ctx = await setupTest("netlify", { @@ -21,9 +21,7 @@ describe("nitro:preset:netlify", async () => { testNitro( ctx, async () => { - const { default: handler } = (await import( - resolve(ctx.outDir, "server/main.mjs") - )) as { + const { default: handler } = (await import(resolve(ctx.outDir, "server/main.mjs"))) as { default: (req: Request, _ctx: FunctionContext) => Promise; }; return async ({ url: rawRelativeUrl, headers, method, body }) => { @@ -40,10 +38,7 @@ describe("nitro:preset:netlify", async () => { }, (_ctx, callHandler) => { it("adds route rules - redirects", async () => { - const redirects = await fsp.readFile( - resolve(ctx.outDir, "../dist/_redirects"), - "utf8" - ); + const redirects = await fsp.readFile(resolve(ctx.outDir, "../dist/_redirects"), "utf8"); expect(redirects).toMatchInlineSnapshot(` "/rules/nested/override /other 302 @@ -56,10 +51,7 @@ describe("nitro:preset:netlify", async () => { }); it("adds route rules - headers", async () => { - const headers = await fsp.readFile( - resolve(ctx.outDir, "../dist/_headers"), - "utf8" - ); + const headers = await fsp.readFile(resolve(ctx.outDir, "../dist/_headers"), "utf8"); expect(headers).toMatchInlineSnapshot(` "/rules/headers @@ -103,7 +95,7 @@ describe("nitro:preset:netlify", async () => { "export { default } from "./main.mjs"; export const config = { name: "server handler", - generator: "nitro@2.x", + generator: "nitro@3.x", path: "/*", nodeBundler: "none", includedFiles: ["**"], @@ -116,9 +108,9 @@ describe("nitro:preset:netlify", async () => { describe("matching ISR route rule with no max-age", () => { it("sets Netlify-CDN-Cache-Control header with revalidation after 1 year and durable directive", async () => { const { headers } = await callHandler({ url: "/rules/isr" }); - expect( - (headers as Record)["netlify-cdn-cache-control"] - ).toBe("public, max-age=31536000, must-revalidate, durable"); + expect((headers as Record)["netlify-cdn-cache-control"]).toBe( + "public, max-age=31536000, must-revalidate, durable" + ); }); it("sets Cache-Control header with immediate revalidation", async () => { @@ -132,9 +124,7 @@ describe("nitro:preset:netlify", async () => { describe("matching ISR route rule with a max-age", () => { it("sets Netlify-CDN-Cache-Control header with SWC=1yr, given max-age, and durable directive", async () => { const { headers } = await callHandler({ url: "/rules/isr-ttl" }); - expect( - (headers as Record)["netlify-cdn-cache-control"] - ).toBe( + expect((headers as Record)["netlify-cdn-cache-control"]).toBe( "public, max-age=60, stale-while-revalidate=31536000, durable" ); }); @@ -149,12 +139,8 @@ describe("nitro:preset:netlify", async () => { it("does not overwrite Cache-Control headers given a matching non-ISR route rule", async () => { const { headers } = await callHandler({ url: "/rules/dynamic" }); - expect( - (headers as Record)["cache-control"] - ).not.toBeDefined(); - expect( - (headers as Record)["netlify-cdn-cache-control"] - ).not.toBeDefined(); + expect((headers as Record)["cache-control"]).not.toBeDefined(); + expect((headers as Record)["netlify-cdn-cache-control"]).not.toBeDefined(); }); // Regression test for https://github.com/nitrojs/nitro/issues/2431 @@ -162,9 +148,9 @@ describe("nitro:preset:netlify", async () => { const { headers } = await callHandler({ url: "/rules/isr-ttl?foo=bar", }); - expect( - (headers as Record)["netlify-cdn-cache-control"] - ).toBe("public, max-age=60, stale-while-revalidate=31536000, durable"); + expect((headers as Record)["netlify-cdn-cache-control"]).toBe( + "public, max-age=60, stale-while-revalidate=31536000, durable" + ); }); } ); diff --git a/test/presets/nitro-dev.test.ts b/test/presets/nitro-dev.test.ts index 667146a176..cdb86d9c3b 100644 --- a/test/presets/nitro-dev.test.ts +++ b/test/presets/nitro-dev.test.ts @@ -1,6 +1,6 @@ -import type { OpenAPI3 } from "openapi-typescript"; +import type { OpenAPI3 } from "../../src/types/openapi-ts.ts"; import { describe, expect, it } from "vitest"; -import { setupTest, testNitro } from "../tests"; +import { setupTest, testNitro } from "../tests.ts"; describe("nitro:preset:nitro-dev", async () => { const ctx = await setupTest("nitro-dev"); @@ -17,17 +17,11 @@ describe("nitro:preset:nitro-dev", async () => { }; }, (_ctx, callHandler) => { - it("returns correct status for devProxy", async () => { + it.skipIf(process.env.OFFLINE)("returns correct status for devProxy", async () => { const { status } = await callHandler({ url: "/proxy/example" }); expect(status).toBe(200); }); - it("dev storage", async () => { - const { data } = await callHandler({ url: "/api/storage/dev" }); - expect(data.keys.length).toBeGreaterThan(0); - expect(data.keys).includes("src:public:favicon.ico"); - }); - describe("openAPI", () => { let spec: OpenAPI3; it("/_openapi.json", async () => { @@ -48,6 +42,17 @@ describe("nitro:preset:nitro-dev", async () => { "name": "test", "required": true, }, + { + "in": "query", + "name": "val", + "schema": { + "enum": [ + 0, + 1, + ], + "type": "integer", + }, + }, ], "responses": { "200": { diff --git a/test/presets/node.test.ts b/test/presets/node.test.ts index 01122dd155..e6d7d68c5a 100644 --- a/test/presets/node.test.ts +++ b/test/presets/node.test.ts @@ -1,17 +1,17 @@ import { existsSync } from "node:fs"; import { resolve } from "pathe"; -import { isWindows } from "std-env"; +// import { isWindows } from "std-env"; import { describe, expect, it } from "vitest"; -import { setupTest, startServer, testNitro } from "../tests"; +import { setupTest, startServer, testNitro } from "../tests.ts"; -describe("nitro:preset:node-listener", async () => { - const ctx = await setupTest("node-listener"); +describe("nitro:preset:node-middleware", async () => { + const ctx = await setupTest("node-middleware"); testNitro(ctx, async () => { const entryPath = resolve(ctx.outDir, "server/index.mjs"); - const { listener } = await import(entryPath); + const { middleware } = await import(entryPath); - await startServer(ctx, listener); + await startServer(ctx, middleware); return async ({ url, ...opts }) => { const res = await ctx.fetch(url, opts); @@ -33,13 +33,8 @@ describe("nitro:preset:node-listener", async () => { expect(noncached2.headers.get("etag")).toBeNull(); }); - it.skipIf(isWindows)("should not bundle externals", () => { + it("should trace externals", () => { const serverNodeModules = resolve(ctx.outDir, "server/node_modules"); - expect( - existsSync(resolve(serverNodeModules, "@fixture/nitro-utils/extra.mjs")) - ).toBe(true); - expect( - existsSync(resolve(serverNodeModules, "@fixture/nitro-utils/extra2.mjs")) - ).toBe(true); + expect(existsSync(resolve(serverNodeModules, "@fixture/nitro-utils/extra.mjs"))).toBe(true); }); }); diff --git a/test/presets/standard.test.ts b/test/presets/standard.test.ts new file mode 100644 index 0000000000..da918a7846 --- /dev/null +++ b/test/presets/standard.test.ts @@ -0,0 +1,17 @@ +import { resolve } from "pathe"; +import { describe } from "vitest"; +import { setupTest, testNitro } from "../tests.ts"; + +describe("nitro:standard", async () => { + const ctx = await setupTest("standard"); + + testNitro(ctx, async () => { + const entryPath = resolve(ctx.outDir, "server/index.mjs"); + const fetchHandler = await import(entryPath).then((m) => m.default.fetch); + + return async ({ url, ...init }) => { + const res = await fetchHandler(new Request(`https://test.com${url}`, init)); + return res; + }; + }); +}); diff --git a/test/presets/static.test.ts b/test/presets/static.test.ts index 579e43a722..1fffcca52d 100644 --- a/test/presets/static.test.ts +++ b/test/presets/static.test.ts @@ -1,7 +1,7 @@ import fsp from "node:fs/promises"; import { resolve } from "pathe"; import { describe, expect, it } from "vitest"; -import { setupTest } from "../tests"; +import { setupTest } from "../tests.ts"; describe("nitro:preset:static", async () => { const ctx = await setupTest("static"); diff --git a/test/presets/vercel-edge.test.ts b/test/presets/vercel-edge.test.ts deleted file mode 100644 index 3a0f0f547d..0000000000 --- a/test/presets/vercel-edge.test.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { promises as fsp } from "node:fs"; -import { EdgeRuntime } from "edge-runtime"; -import { resolve } from "pathe"; -import { isWindows } from "std-env"; -import { describeIf, setupTest, testNitro } from "../tests"; - -describeIf(!isWindows, "nitro:preset:vercel-edge", async () => { - const ctx = await setupTest("vercel-edge", { - config: { - minify: false, - }, - }); - testNitro(ctx, async () => { - const entry = resolve(ctx.outDir, "functions/__nitro.func/index.mjs"); - - const init = (await fsp.readFile(entry, "utf8")) - .replace( - /export ?{ ?handleEvent as default ?}/, - "globalThis.handleEvent = handleEvent" - ) - // TODO: we can use AST to replace this. - // This is only needed for testing via EdgeRuntime since unlike prod (workerd?), it is a simple Node.js isolate - .replace( - /import\s+(.+)\s+from\s+['"](node:[^'"]+)['"]/g, - "const $1 = process.getBuiltinModule('$2')" - ) - .replace( - `const nodeAsyncHooks, { AsyncLocalStorage } = process.getBuiltinModule('node:async_hooks');`, - `const nodeAsyncHooks = process.getBuiltinModule('node:async_hooks'); const { AsyncLocalStorage } = nodeAsyncHooks;` - ); - - const runtime = new EdgeRuntime({ - extend: (context) => - Object.assign(context, { - process: { - env: { ...ctx.env }, - getBuiltinModule: process.getBuiltinModule, - }, - }), - }); - - await runtime.evaluate(`(async function() { ${init} })()`); - - return async ({ url, headers, method, body }) => { - const isGet = ["get", "head"].includes((method || "get").toLowerCase()); - const res = await runtime.evaluate( - `handleEvent(new Request(new URL("http://localhost${url}"), { - headers: new Headers(${JSON.stringify(headers || {})}), - method: ${JSON.stringify(method || "get")}, - ${isGet ? "" : `body: ${JSON.stringify(body)},`} - }))` - ); - return res; - }; - }); -}); diff --git a/test/presets/vercel.test.ts b/test/presets/vercel.test.ts index 3b10b698b3..e61e808760 100644 --- a/test/presets/vercel.test.ts +++ b/test/presets/vercel.test.ts @@ -1,19 +1,24 @@ import { promises as fsp } from "node:fs"; -import { resolve } from "pathe"; -import { describe, expect, it } from "vitest"; -import { setupTest, startServer, testNitro } from "../tests"; +import { resolve, join, basename } from "pathe"; +import { describe, expect, it, vi, beforeAll, afterAll } from "vitest"; +import { setupTest, testNitro, fixtureDir } from "../tests.ts"; +import { toFetchHandler } from "srvx/node"; -describe("nitro:preset:vercel", async () => { - const ctx = await setupTest("vercel"); +describe("nitro:preset:vercel:web", async () => { + const ctx = await setupTest("vercel", { + outDirSuffix: "-web", + }); testNitro( ctx, async () => { - const handle = await import( - resolve(ctx.outDir, "functions/__nitro.func/index.mjs") + const { fetch: fetchHandler } = await import( + resolve(ctx.outDir, "functions/__server.func/index.mjs") ).then((r) => r.default || r); - await startServer(ctx, handle); return async ({ url, ...options }) => { - const res = await ctx.fetch(url, options); + const req = new Request(new URL(url, "https://example.com"), options); + const res = await fetchHandler(req, { + waitUntil: vi.fn(), + }); return res; }; }, @@ -24,6 +29,16 @@ describe("nitro:preset:vercel", async () => { .then((r) => JSON.parse(r)); expect(config).toMatchInlineSnapshot(` { + "crons": [ + { + "path": "/_vercel/cron", + "schedule": "* * * * *", + }, + ], + "framework": { + "name": "nitro", + "version": "3.x", + }, "overrides": { "_scalar/index.html": { "path": "_scalar", @@ -102,6 +117,10 @@ describe("nitro:preset:vercel", async () => { }, "src": "/(.*)", }, + { + "dest": "https://cdn.jsdelivr.net/$1", + "src": "/cdn/(.*)", + }, { "continue": true, "headers": { @@ -113,43 +132,243 @@ describe("nitro:preset:vercel", async () => { "handle": "filesystem", }, { - "dest": "/rules/_/noncached/cached?url=$url", - "src": "/rules/_/noncached/cached", + "dest": "/rules/_/noncached/cached-isr?__isr_route=$__isr_route", + "src": "(?<__isr_route>/rules/_/noncached/cached)", + }, + { + "dest": "/__server", + "src": "(?<__isr_route>/rules/_/cached/noncached)", + }, + { + "dest": "/__server", + "src": "(?<__isr_route>/rules/_/noncached/(?:.*))", + }, + { + "dest": "/rules/_/cached/[...]-isr?__isr_route=$__isr_route", + "src": "(?<__isr_route>/rules/_/cached/(?:.*))", + }, + { + "dest": "/__server", + "src": "(?<__isr_route>/rules/dynamic)", + }, + { + "dest": "/rules/isr/[...]-isr?__isr_route=$__isr_route", + "src": "(?<__isr_route>/rules/isr/(?:.*))", + }, + { + "dest": "/rules/isr-ttl/[...]-isr?__isr_route=$__isr_route", + "src": "(?<__isr_route>/rules/isr-ttl/(?:.*))", + }, + { + "dest": "/rules/swr/[...]-isr?__isr_route=$__isr_route", + "src": "(?<__isr_route>/rules/swr/(?:.*))", + }, + { + "dest": "/rules/swr-ttl/[...]-isr?__isr_route=$__isr_route", + "src": "(?<__isr_route>/rules/swr-ttl/(?:.*))", + }, + { + "dest": "/wasm/static-import", + "src": "/wasm/static-import", + }, + { + "dest": "/wasm/dynamic-import", + "src": "/wasm/dynamic-import", + }, + { + "dest": "/wait-until", + "src": "/wait-until", + }, + { + "dest": "/virtual", + "src": "/virtual", + }, + { + "dest": "/stream", + "src": "/stream", + }, + { + "dest": "/static-flags", + "src": "/static-flags", + }, + { + "dest": "/route-group", + "src": "/route-group", + }, + { + "dest": "/replace", + "src": "/replace", + }, + { + "dest": "/raw", + "src": "/raw", + }, + { + "dest": "/prerender-custom.html", + "src": "/prerender-custom.html", + }, + { + "dest": "/prerender", + "src": "/prerender", + }, + { + "dest": "/node-compat", + "src": "/node-compat", + }, + { + "dest": "/modules", + "src": "/modules", + }, + { + "dest": "/jsx", + "src": "/jsx", + }, + { + "dest": "/json-string", + "src": "/json-string", + }, + { + "dest": "/imports", + "src": "/imports", + }, + { + "dest": "/icon.png", + "src": "/icon.png", + }, + { + "dest": "/file", + "src": "/file", + }, + { + "dest": "/fetch", + "src": "/fetch", + }, + { + "dest": "/errors/throw", + "src": "/errors/throw", }, { - "dest": "/__nitro", - "src": "/rules/_/cached/noncached", + "dest": "/errors/stack", + "src": "/errors/stack", }, { - "dest": "/__nitro", - "src": "(?/rules/_/noncached/.*)", + "dest": "/errors/captured", + "src": "/errors/captured", }, { - "dest": "/__nitro--rules---cached?url=$url", - "src": "(?/rules/_/cached/.*)", + "dest": "/env", + "src": "/env", }, { - "dest": "/__nitro", - "src": "/rules/dynamic", + "dest": "/context", + "src": "/context", }, { - "dest": "/__nitro--rules-isr?url=$url", - "src": "(?/rules/isr/.*)", + "dest": "/config", + "src": "/config", }, { - "dest": "/__nitro--rules-isr-ttl?url=$url", - "src": "(?/rules/isr-ttl/.*)", + "dest": "/assets/md", + "src": "/assets/md", }, { - "dest": "/__nitro--rules-swr?url=$url", - "src": "(?/rules/swr/.*)", + "dest": "/assets/all", + "src": "/assets/all", }, { - "dest": "/__nitro--rules-swr-ttl?url=$url", - "src": "(?/rules/swr-ttl/.*)", + "dest": "/api/upload", + "src": "/api/upload", }, { - "dest": "/__nitro", + "dest": "/api/storage/item", + "src": "/api/storage/item", + }, + { + "dest": "/api/methods/get", + "src": "/api/methods/get", + }, + { + "dest": "/api/methods/foo.get", + "src": "/api/methods/foo.get", + }, + { + "dest": "/api/meta/test", + "src": "/api/meta/test", + }, + { + "dest": "/api/kebab", + "src": "/api/kebab", + }, + { + "dest": "/api/hey", + "src": "/api/hey", + }, + { + "dest": "/api/hello", + "src": "/api/hello", + }, + { + "dest": "/api/headers", + "src": "/api/headers", + }, + { + "dest": "/api/echo", + "src": "/api/echo", + }, + { + "dest": "/api/db", + "src": "/api/db", + }, + { + "dest": "/api/cached", + "src": "/api/cached", + }, + { + "dest": "/500", + "src": "/500", + }, + { + "dest": "/_vercel/cron", + "src": "/_vercel/cron", + }, + { + "dest": "/_swagger", + "src": "/_swagger", + }, + { + "dest": "/_scalar", + "src": "/_scalar", + }, + { + "dest": "/_openapi.json", + "src": "/_openapi.json", + }, + { + "dest": "/assets/[id]", + "src": "/assets/(?[^/]+)", + }, + { + "dest": "/api/test/[-]/foo", + "src": "/api/test/(?<_0>[^/]*)/foo", + }, + { + "dest": "/api/param/[test-id]", + "src": "/api/param/(?[^/]+)-id", + }, + { + "dest": "/tasks/[...name]", + "src": "/tasks/?(?.+)", + }, + { + "dest": "/rules/[...slug]", + "src": "/rules/?(?.+)", + }, + { + "dest": "/api/wildcard/[...param]", + "src": "/api/wildcard/?(?.+)", + }, + { + "dest": "/__server", "src": "/(.*)", }, ], @@ -160,17 +379,189 @@ describe("nitro:preset:vercel", async () => { it("should generate prerender config", async () => { const isrRouteConfig = await fsp.readFile( - resolve( - ctx.outDir, - "functions/__nitro--rules-isr.prerender-config.json" - ), + resolve(ctx.outDir, "functions/rules/isr/[...]-isr.prerender-config.json"), "utf8" ); expect(JSON.parse(isrRouteConfig)).toMatchObject({ expiration: false, - allowQuery: ["q", "url"], + allowQuery: ["q", "__isr_route"], }); }); + + const walkDir = async (path: string): Promise => { + const items: string[] = []; + const dirname = basename(path); + const entries = await fsp.readdir(path, { withFileTypes: true }); + for (const entry of entries) { + if (entry.isFile()) { + items.push(`${dirname}/${entry.name}`); + } else if (entry.isSymbolicLink()) { + items.push(`${dirname}/${entry.name} (symlink)`); + } else if (/_\/|_.+|node_modules/.test(entry.name)) { + items.push(`${dirname}/${entry.name}`); + } else if (entry.isDirectory()) { + items.push(...(await walkDir(join(path, entry.name))).map((i) => `${dirname}/${i}`)); + } + } + items.sort(); + return items; + }; + + it("should generated expected functions", async () => { + const functionsDir = resolve(ctx.outDir, "functions"); + const functionsFiles = await walkDir(functionsDir); + expect(functionsFiles).toMatchInlineSnapshot(` + [ + "functions/500.func (symlink)", + "functions/__server.func", + "functions/_openapi.json.func (symlink)", + "functions/_scalar.func (symlink)", + "functions/_swagger.func (symlink)", + "functions/_vercel", + "functions/api/cached.func (symlink)", + "functions/api/db.func (symlink)", + "functions/api/echo.func (symlink)", + "functions/api/headers.func (symlink)", + "functions/api/hello.func (symlink)", + "functions/api/hey.func (symlink)", + "functions/api/kebab.func (symlink)", + "functions/api/meta/test.func (symlink)", + "functions/api/methods/foo.get.func (symlink)", + "functions/api/methods/get.func (symlink)", + "functions/api/param/[test-id].func (symlink)", + "functions/api/storage/item.func (symlink)", + "functions/api/test/[-]/foo.func (symlink)", + "functions/api/upload.func (symlink)", + "functions/api/wildcard/[...param].func (symlink)", + "functions/assets/[id].func (symlink)", + "functions/assets/all.func (symlink)", + "functions/assets/md.func (symlink)", + "functions/config.func (symlink)", + "functions/context.func (symlink)", + "functions/env.func (symlink)", + "functions/errors/captured.func (symlink)", + "functions/errors/stack.func (symlink)", + "functions/errors/throw.func (symlink)", + "functions/fetch.func (symlink)", + "functions/file.func (symlink)", + "functions/icon.png.func (symlink)", + "functions/imports.func (symlink)", + "functions/json-string.func (symlink)", + "functions/jsx.func (symlink)", + "functions/modules.func (symlink)", + "functions/node-compat.func (symlink)", + "functions/prerender-custom.html.func (symlink)", + "functions/prerender.func (symlink)", + "functions/raw.func (symlink)", + "functions/replace.func (symlink)", + "functions/route-group.func (symlink)", + "functions/rules/[...slug].func (symlink)", + "functions/rules/_/cached/[...]-isr.func (symlink)", + "functions/rules/_/cached/[...]-isr.prerender-config.json", + "functions/rules/_/noncached/cached-isr.func (symlink)", + "functions/rules/_/noncached/cached-isr.prerender-config.json", + "functions/rules/isr-ttl/[...]-isr.func (symlink)", + "functions/rules/isr-ttl/[...]-isr.prerender-config.json", + "functions/rules/isr/[...]-isr.func (symlink)", + "functions/rules/isr/[...]-isr.prerender-config.json", + "functions/rules/swr-ttl/[...]-isr.func (symlink)", + "functions/rules/swr-ttl/[...]-isr.prerender-config.json", + "functions/rules/swr/[...]-isr.func (symlink)", + "functions/rules/swr/[...]-isr.prerender-config.json", + "functions/static-flags.func (symlink)", + "functions/stream.func (symlink)", + "functions/tasks/[...name].func (symlink)", + "functions/virtual.func (symlink)", + "functions/wait-until.func (symlink)", + "functions/wasm/dynamic-import.func (symlink)", + "functions/wasm/static-import.func (symlink)", + ] + `); + }); } ); }); + +describe("nitro:preset:vercel:node", async () => { + const ctx = await setupTest("vercel", { + outDirSuffix: "-node", + config: { + vercel: { entryFormat: "node" }, + }, + }); + testNitro(ctx, async () => { + const nodeHandler = await import(resolve(ctx.outDir, "functions/__server.func/index.mjs")).then( + (r) => r.default || r + ); + const fetchHandler = toFetchHandler(nodeHandler); + return async ({ url, ...options }) => { + const req = new Request(new URL(url, "https://example.com"), options); + const res = await fetchHandler(req); + return res; + }; + }); +}); + +describe("nitro:preset:vercel:bun", async () => { + const ctx = await setupTest("vercel", { + outDirSuffix: "-bun", + config: { + preset: "vercel", + vercel: { + functions: { + runtime: "bun1.x", + }, + }, + }, + }); + + it("should generate function config with bun runtime", async () => { + const config = await fsp + .readFile(resolve(ctx.outDir, "functions/__server.func/.vc-config.json"), "utf8") + .then((r) => JSON.parse(r)); + expect(config).toMatchInlineSnapshot(` + { + "handler": "index.mjs", + "launcherType": "Nodejs", + "runtime": "bun1.x", + "shouldAddHelpers": false, + "supportsResponseStreaming": true, + } + `); + }); +}); + +describe.skip("nitro:preset:vercel:bun-verceljson", async () => { + const vercelJsonPath = join(fixtureDir, "vercel.json"); + + const ctx = await setupTest("vercel", { + outDirSuffix: "-bun-verceljson", + config: { + preset: "vercel", + }, + }); + + beforeAll(async () => { + // Need to make sure vercel.json is created before setupTest is called + await fsp.writeFile(vercelJsonPath, JSON.stringify({ bunVersion: "1.x" })); + }); + + afterAll(async () => { + await fsp.unlink(vercelJsonPath).catch(() => {}); + }); + + it("should detect bun runtime from vercel.json", async () => { + const config = await fsp + .readFile(resolve(ctx.outDir, "functions/__server.func/.vc-config.json"), "utf8") + .then((r) => JSON.parse(r)); + expect(config).toMatchInlineSnapshot(` + { + "handler": "index.mjs", + "launcherType": "Nodejs", + "runtime": "bun1.x", + "shouldAddHelpers": false, + "supportsResponseStreaming": true, + } + `); + }); +}); diff --git a/test/presets/winterjs.test.ts b/test/presets/winterjs.test.ts index 8ab0d24451..250ba3db40 100644 --- a/test/presets/winterjs.test.ts +++ b/test/presets/winterjs.test.ts @@ -1,7 +1,7 @@ -import { execa, execaCommandSync } from "execa"; +import { execa } from "execa"; import { getRandomPort, waitForPort } from "get-port-please"; import { describe } from "vitest"; -import { setupTest, testNitro } from "../tests"; +import { setupTest, testNitro } from "../tests.ts"; const hasWasmer = false; // execaCommandSync("wasmer --version", { stdio: "ignore", reject: false }) diff --git a/test/scripts/gen-fixture-types.ts b/test/scripts/gen-fixture-types.ts index 91773ef18c..1a493b9575 100644 --- a/test/scripts/gen-fixture-types.ts +++ b/test/scripts/gen-fixture-types.ts @@ -1,6 +1,7 @@ import { fileURLToPath } from "mlly"; -import { createNitro, scanHandlers, writeTypes } from "nitropack/core"; +import { createNitro, writeTypes } from "nitro/builder"; import { resolve } from "pathe"; +import { scanHandlers } from "../../src/scan.ts"; const prepare = async () => { const fixtureDir = fileURLToPath(new URL("../fixture", import.meta.url).href); diff --git a/test/tests.ts b/test/tests.ts index 32e6420c1a..c52e5d2416 100644 --- a/test/tests.ts +++ b/test/tests.ts @@ -1,10 +1,10 @@ import { promises as fsp } from "node:fs"; -import type { RequestListener } from "node:http"; +import { Server, type RequestListener } from "node:http"; import { tmpdir } from "node:os"; -import { type DateString, formatDate } from "compatx"; +import { formatDate } from "compatx"; +import type { DateString } from "compatx"; import { defu } from "defu"; import destr from "destr"; -import { type Listener, listen } from "listhen"; import { fileURLToPath } from "mlly"; import { build, @@ -13,13 +13,13 @@ import { createNitro, prepare, prerender, -} from "nitropack/core"; -import type { Nitro, NitroConfig } from "nitropack/types"; -import { type FetchOptions, fetch } from "ofetch"; +} from "nitro/builder"; +import type { Nitro, NitroConfig } from "nitro/types"; +import { fetch } from "ofetch"; +import type { FetchOptions } from "ofetch"; import { join, resolve } from "pathe"; -import { isWindows, nodeMajorVersion } from "std-env"; -import { joinURL } from "ufo"; -import { afterAll, beforeAll, describe, expect, it } from "vitest"; +import { isWindows } from "std-env"; +import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; export interface Context { preset: string; @@ -27,7 +27,7 @@ export interface Context { rootDir: string; outDir: string; fetch: (url: string, opts?: FetchOptions) => Promise; - server?: Listener; + server?: { url: string; close: () => Promise }; isDev: boolean; isWorker: boolean; isLambda: boolean; @@ -39,11 +39,7 @@ export interface Context { } // https://github.com/nitrojs/nitro/pull/1240 -export const describeIf = ( - condition: boolean, - title: string, - factory: () => any -) => +export const describeIf = (condition: boolean, title: string, factory: () => any) => condition ? describe(title, factory) : describe(title, () => { @@ -52,28 +48,25 @@ export const describeIf = ( }); }); -export const fixtureDir = fileURLToPath( - new URL("fixture", import.meta.url).href -); +export const fixtureDir = fileURLToPath(new URL("fixture", import.meta.url).href); export const getPresetTmpDir = (preset: string) => { if (preset.startsWith("cloudflare")) { - return fileURLToPath( - new URL(`.tmp/${preset}`, import.meta.url) as any /* remove me */ - ); + return fileURLToPath(new URL(`.tmp/${preset}`, import.meta.url) as any /* remove me */); } - return resolve( - process.env.NITRO_TEST_TMP_DIR || join(tmpdir(), "nitro-tests"), - preset - ); + return resolve(process.env.NITRO_TEST_TMP_DIR || join(tmpdir(), "nitro-tests"), preset); }; export async function setupTest( preset: string, - opts: { config?: NitroConfig; compatibilityDate?: DateString } = {} + opts: { + config?: NitroConfig; + compatibilityDate?: DateString; + outDirSuffix?: string; + } = {} ) { - const presetTmpDir = getPresetTmpDir(preset); + const presetTmpDir = getPresetTmpDir(preset + (opts.outDirSuffix || "")); await fsp.rm(presetTmpDir, { recursive: true }).catch(() => { // Ignore @@ -105,7 +98,7 @@ export async function setupTest( NITRO_DYNAMIC: "from-env", }, fetch: (url, opts) => - fetch(joinURL(ctx.server!.url, url.slice(1)), { + fetch(new URL(url, ctx.server!.url), { redirect: "manual", ...(opts as any), }), @@ -132,7 +125,6 @@ export async function setupTest( output: { dir: ctx.outDir, }, - timing: !ctx.isWorker, }); const nitro = (ctx.nitro = await createNitro(config, { compatibilityDate: opts.compatibilityDate || formatDate(new Date()), @@ -141,7 +133,11 @@ export async function setupTest( if (ctx.isDev) { // Setup development server const devServer = createDevServer(ctx.nitro); - ctx.server = await devServer.listen({}); + const server = await devServer.listen({}); + ctx.server = { + url: server.url!, + close: () => server.close(), + }; await prepare(ctx.nitro); const ready = new Promise((resolve) => { ctx.nitro!.hooks.hook("dev:reload", () => resolve()); @@ -169,12 +165,28 @@ export async function setupTest( } export async function startServer(ctx: Context, handle: RequestListener) { - ctx.server = await listen(handle); + const server = new Server(handle); + await new Promise((resolve, reject) => { + server.on("error", reject); + server.listen(0, () => resolve()); + }); + const port = (server.address() as any).port; + ctx.server = { + url: `http://localhost:${port}`, + close: () => + new Promise((resolve, reject) => { + server.close((err) => { + if (err) return reject(err); + resolve(); + }); + }), + }; } type TestHandlerResult = { data: any; status: number; + statusText?: string; headers: Record; }; type TestHandler = (options: any) => Promise; @@ -194,8 +206,11 @@ export function testNitro( callOpts: { binary?: boolean } = {} ): Promise { const result = await _handler(options); - if (!["Response", "_Response"].includes(result.constructor.name)) { - return result as TestHandlerResult; + if ( + !(result instanceof Response) && + !["Response", "_Response"].includes(result.constructor.name) + ) { + throw new TypeError("Expected Response"); } const headers: Record = {}; @@ -213,12 +228,17 @@ export function testNitro( headers[key] = value; } } + headers["set-cookie"] = (result as Response).headers.getSetCookie(); + if (headers["set-cookie"].length === 0) { + delete headers["set-cookie"]; + } return { data: callOpts.binary ? Buffer.from(await (result as Response).arrayBuffer()) : destr(await (result as Response).text()), status: result.status, + statusText: result.statusText, headers, }; } @@ -227,6 +247,12 @@ export function testNitro( _handler = await getHandler(); }, 25_000); + it("Server entry works", async () => { + const { data, headers } = await callHandler({ url: "/" }); + expect(data).toBe("server entry works!"); + expect(headers["x-test"]).toBe("test"); + }); + it("API Works", async () => { const { data: helloData } = await callHandler({ url: "/api/hello" }); expect(helloData).to.toMatchObject({ message: "Hello API" }); @@ -265,7 +291,14 @@ export function testNitro( expect(res.status).toBe(404); }); - it("Handle 405 method not allowed", async () => { + it("Virtual route", async () => { + const res = await callHandler({ url: "/virtual" }); + expect(res.status).toBe(200); + expect(res.data).toBe("Hello from virtual entry!"); + }); + + // TODO + it.todo("Handle 405 method not allowed", async () => { const res = await callHandler({ url: "/api/upload" }); expect(res.status).toBe(405); }); @@ -288,67 +321,59 @@ export function testNitro( it("binary response", async () => { const { data } = await callHandler({ url: "/icon.png" }, { binary: true }); - let buffer: Buffer; - if (ctx.isLambda) { - // TODO: Handle base64 decoding in lambda tests themselves - expect(typeof data).toBe("string"); - buffer = Buffer.from(data, "base64"); - } else { - buffer = data; - } // Check if buffer is a png function isBufferPng(buffer: Buffer) { - return ( - buffer[0] === 0x89 && - buffer[1] === 0x50 && - buffer[2] === 0x4e && - buffer[3] === 0x47 - ); + return buffer[0] === 0x89 && buffer[1] === 0x50 && buffer[2] === 0x4e && buffer[3] === 0x47; } - expect(isBufferPng(buffer)).toBe(true); + expect(isBufferPng(data)).toBe(true); }); - it("render JSX", async () => { + it.skipIf( + // TODO: srvx reverse-compat bug with streaming? + ctx.preset === "vercel" && ctx.nitro?.options.vercel?.entryFormat === "node" + )("render JSX", async () => { const { data } = await callHandler({ url: "/jsx" }); - expect(data).toMatch("

    Hello JSX!

    "); + expect(data).toMatch(/

    Hello JSX!<\/h1>/); }); - it.runIf(ctx.nitro?.options.serveStatic)( - "handles custom Vary header", - async () => { - let headers = ( - await callHandler({ - url: "/foo.css", - headers: { "Accept-Encoding": "gzip" }, - }) - ).headers; - if (headers["vary"]) - expect( - headers["vary"].includes("Origin") && - headers["vary"].includes("Accept-Encoding") - ).toBeTruthy(); - - headers = ( - await callHandler({ - url: "/foo.css", - headers: { "Accept-Encoding": "" }, - }) - ).headers; - if (headers["vary"]) expect(headers["vary"]).toBe("Origin"); + it("replace", async () => { + const { data } = await callHandler({ url: "/replace" }); + expect(data).toMatchObject({ window: false }); + }); - headers = ( - await callHandler({ - url: "/foo.js", - headers: { "Accept-Encoding": "gzip" }, - }) - ).headers; - if (headers["vary"]) - expect( - headers["vary"].includes("Origin") && - headers["vary"].includes("Accept-Encoding") - ).toBeTruthy(); + it.runIf(ctx.nitro?.options.serveStatic)("handles custom Vary header", async () => { + let headers = ( + await callHandler({ + url: "/foo.css", + headers: { "Accept-Encoding": "gzip" }, + }) + ).headers; + if (headers["vary"]) { + expect(headers["vary"].includes("Origin")).toBeTruthy(); + expect(headers["vary"].includes("Accept-Encoding")).toBeTruthy(); + } + + headers = ( + await callHandler({ + url: "/foo.css", + headers: { "Accept-Encoding": "" }, + }) + ).headers; + if (headers["vary"]) { + expect(headers["vary"]).toBe("Origin"); } - ); + + headers = ( + await callHandler({ + url: "/foo.js", + headers: { "Accept-Encoding": "gzip" }, + }) + ).headers; + if (headers["vary"]) { + expect(headers["vary"].includes("Origin")).toBeTruthy(); + expect(headers["vary"].includes("Accept-Encoding")).toBeTruthy(); + } + }); it("handles route rules - headers", async () => { const { headers } = await callHandler({ url: "/rules/headers" }); @@ -366,6 +391,34 @@ export function testNitro( expect(headers).toMatchObject(expectedHeaders); }); + describe("handles route rules - basic auth", () => { + it("rejects request with bad creds", async () => { + const { status, headers } = await callHandler({ + url: "/rules/basic-auth", + headers: { + Authorization: "Basic " + btoa("user:wrongpass"), + }, + }); + expect(status).toBe(401); + expect(headers["www-authenticate"]).toBe('Basic realm="Secure Area"'); + }); + + it("allows request with correct password", async () => { + const { status } = await callHandler({ + url: "/rules/basic-auth/test", + headers: { + Authorization: "Basic " + btoa("admin:secret"), + }, + }); + expect(status).toBe(200); + }); + + it("disabled basic-auth for sub-rules", async () => { + const { status } = await callHandler({ url: "/rules/basic-auth/no-auth" }); + expect(status).toBe(200); + }); + }); + it("handles route rules - allowing overriding", async () => { const override = await callHandler({ url: "/rules/nested/override" }); expect(override.headers.location).toBe("/other"); @@ -376,43 +429,10 @@ export function testNitro( expect(base.headers["x-test"]).toBe("test"); }); - it("handles errors", async () => { - const { status, headers } = await callHandler({ - url: "/api/error", - headers: { - Accept: "application/json", - }, - }); - expect(status).toBe(503); - - expect(headers).toMatchObject({ - "content-type": "application/json", - "content-security-policy": ctx.isDev - ? "script-src 'self' 'unsafe-inline'; object-src 'none'; base-uri 'self';" - : "script-src 'none'; frame-ancestors 'none';", - "referrer-policy": "no-referrer", - "x-content-type-options": "nosniff", - "x-frame-options": "DENY", - }); - - const { data } = await callHandler({ - url: "/api/error?json", - }); - expect(status).toBe(503); - expect(data.json.error).toBe(true); - }); - - it.skipIf(isWindows && ctx.preset === "nitro-dev")( - "universal import.meta", - async () => { - const { status, data } = await callHandler({ url: "/api/import-meta" }); - expect(status).toBe(200); - expect(data.testFile).toMatch(/[/\\]test.txt$/); - expect(data.hasEnv).toBe(true); - } - ); - - it("handles custom server assets", async () => { + it.skipIf( + // TODO! + ctx.preset === "vercel" && ctx.nitro?.options.vercel?.entryFormat === "node" && isWindows + )("handles custom server assets", async () => { const { data: html, status: htmlStatus } = await callHandler({ url: "/file?filename=index.html", }); @@ -452,7 +472,7 @@ export function testNitro( url: "/api/param/prerender4", }); expect(data).toBe("prerender4"); - expect(headers["content-type"]).toBe("text/plain; charset=utf-16"); + expect(headers["content-type"]).toBe("text/plain; custom"); }); } @@ -469,56 +489,49 @@ export function testNitro( }); }); - it.skipIf(ctx.preset === "deno-server")( - "resolve module version conflicts", - async () => { - const { data } = await callHandler({ url: "/modules" }); - expect(data).toMatchObject({ - depA: "@fixture/nitro-lib@1.0.0+@fixture/nested-lib@1.0.0", - depB: "@fixture/nitro-lib@2.0.1+@fixture/nested-lib@2.0.1", - depLib: "@fixture/nitro-lib@2.0.0+@fixture/nested-lib@2.0.0", - subpathLib: "@fixture/nitro-lib@2.0.0", - extraUtils: "@fixture/nitro-utils/extra", - }); - } - ); - - it.skipIf(ctx.isIsolated)( - "useStorage (with base)", - { retry: 5 }, - async () => { - const putRes = await callHandler({ - url: "/api/storage/item?key=test:hello", - method: "PUT", - body: "world", - }); - expect(putRes.data).toBe("world"); - - expect( - ( - await callHandler({ - url: "/api/storage/item?key=:", - }) - ).data - ).toMatchObject(["test:hello"]); - - expect( - ( - await callHandler({ - url: "/api/storage/item?base=test&key=:", - }) - ).data - ).toMatchObject(["hello"]); - - expect( - ( - await callHandler({ - url: "/api/storage/item?base=test&key=hello", - }) - ).data - ).toBe("world"); - } - ); + it.skipIf(ctx.preset === "deno-server")("resolve module version conflicts", async () => { + const { data } = await callHandler({ url: "/modules" }); + expect(data).toMatchObject({ + depA: "@fixture/nitro-lib@1.0.0+@fixture/nested-lib@1.0.0", + depB: "@fixture/nitro-lib@2.0.1+@fixture/nested-lib@2.0.1", + depLib: "@fixture/nitro-lib@2.0.0+@fixture/nested-lib@2.0.0", + subpathLib: "@fixture/nitro-lib@2.0.0", + extraUtils: "@fixture/nitro-utils/extra", + }); + }); + + it.skipIf(ctx.isIsolated)("useStorage (with base)", { retry: 5 }, async () => { + const putRes = await callHandler({ + url: "/api/storage/item?key=test:hello", + method: "PUT", + body: `"world"`, + }); + expect(putRes.data).toBe("world"); + + expect( + ( + await callHandler({ + url: "/api/storage/item?key=:", + }) + ).data + ).toMatchObject(["test:hello"]); + + expect( + ( + await callHandler({ + url: "/api/storage/item?base=test&key=:", + }) + ).data + ).toMatchObject(["hello"]); + + expect( + ( + await callHandler({ + url: "/api/storage/item?base=test&key=hello", + }) + ).data + ).toBe("world"); + }); if (additionalTests) { additionalTests(ctx, callHandler); @@ -531,15 +544,27 @@ export function testNitro( "x-test": "foobar", }, }); - expect(data.headers["x-test"]).toBe("foobar"); expect(data.url).toBe("/api/echo?foo=bar"); + if (!(ctx.preset === "vercel" && ctx.nitro?.options.vercel?.entryFormat === "node")) { + // TODO: Investigate why headers are missing in this case + expect(data.headers["x-test"]).toBe("foobar"); + } + }); + + it("external proxy", async () => { + const { data, headers, status } = await callHandler({ + url: "/cdn/npm/bootstrap@5.3.8/dist/js/bootstrap.min.js", + }); + expect(status).toBe(200); + expect(headers["etag"]).toMatch(/W\/".+"/); + expect(data).toContain("Bootstrap"); }); it.skipIf(ctx.preset === "bun" /* TODO */)("stream", async () => { const { data } = await callHandler({ url: "/stream", }); - expect(data).toBe(ctx.isLambda ? btoa("nitroisawesome") : "nitroisawesome"); + expect(data).toBe("nitroisawesome"); }); it.skipIf(!ctx.supportsEnv)("config", async () => { @@ -547,12 +572,6 @@ export function testNitro( url: "/config", }); expect(data).toMatchObject({ - appConfig: { - dynamic: "from-middleware", - "app-config": true, - "nitro-config": true, - "server-config": true, - }, runtimeConfig: { dynamic: "from-env", url: "https://test.com", @@ -560,19 +579,8 @@ export function testNitro( baseURL: "/", }, }, - sharedAppConfig: { - dynamic: "initial", - "app-config": true, - "nitro-config": true, - "server-config": true, - }, sharedRuntimeConfig: { - // Cloudflare environment variables are set after first request - dynamic: - ctx.preset.includes("cloudflare") && - ctx.preset !== "cloudflare-worker" - ? "initial" - : "from-env", + dynamic: ctx.preset === "cloudflare-module-legacy" ? "initial" : "from-env", // url: "https://test.com", app: { baseURL: "/", @@ -581,30 +589,18 @@ export function testNitro( }); }); - if (ctx.nitro!.options.timing) { - it("set server timing header", async () => { - const { status, headers } = await callHandler({ - url: "/api/hello", - }); - expect(status).toBe(200); - expect(headers["server-timing"]).toMatch(/-;dur=\d+;desc="Generate"/); - }); - } - it("static build flags", async () => { const { data } = await callHandler({ url: "/static-flags" }); expect(data).toMatchObject({ - dev: [ctx.isDev, ctx.isDev], - preset: [ctx.preset, ctx.preset], - prerender: [ - ctx.preset === "nitro-prerenderer", - ctx.preset === "nitro-prerenderer", - ], - client: [false, false], - nitro: [true, true], - server: [true, true], - "versions.nitro": [expect.any(String), expect.any(String)], - "versions?.nitro": [expect.any(String), expect.any(String)], + dev: ctx.isDev, + preset: ctx.preset, + prerender: false, + nitro: true, + server: true, + client: false, + baseURL: "/", + _asyncContext: true, + _tasks: true, }); }); @@ -619,73 +615,33 @@ export function testNitro( expect((await callHandler({ url: "/_ignored" })).status).toBe(404); }); - it.skipIf(ctx.isWorker || ctx.isDev)( - "public files should be ignored", - async () => { - expect((await callHandler({ url: "/_ignored.txt" })).status).toBe(404); - expect((await callHandler({ url: "/favicon.ico" })).status).toBe(200); - } - ); - - it.skipIf(ctx.isWorker || ctx.isDev)( - "public files can be un-ignored with patterns", - async () => { - expect((await callHandler({ url: "/_unignored.txt" })).status).toBe( - 200 - ); - } - ); + it.skipIf(ctx.isWorker || ctx.isDev)("public files should be ignored", async () => { + expect((await callHandler({ url: "/_ignored.txt" })).status).toBe(404); + expect((await callHandler({ url: "/favicon.ico" })).status).toBe(200); + }); }); describe("headers", () => { it("handles headers correctly", async () => { const { headers } = await callHandler({ url: "/api/headers" }); - expect(headers["content-type"]).toBe("text/html"); expect(headers["x-foo"]).toBe("bar"); expect(headers["x-array"]).toMatch(/^foo,\s?bar$/); - - let expectedCookies: string | string[] = [ + const expectedCookies: string | string[] = [ "foo=bar", "bar=baz", "test=value; Path=/", "test2=value; Path=/", ]; - - // TODO: Node presets do not split cookies - // https://github.com/nitrojs/nitro/issues/1462 - // (vercel and deno-server uses node only for tests only) - const notSplittingPresets = [ - "node-listener", - "nitro-dev", - "vercel", - (nodeMajorVersion || 0) < 18 && "deno-server", - (nodeMajorVersion || 0) < 18 && "bun", - ].filter(Boolean); - if (notSplittingPresets.includes(ctx.preset)) { - expectedCookies = - (nodeMajorVersion || 0) < 18 - ? "foo=bar, bar=baz, test=value; Path=/, test2=value; Path=/" - : ["foo=bar, bar=baz", "test=value; Path=/", "test2=value; Path=/"]; - } - - // TODO: vercel-edge joins all cookies for some reason! - if (typeof expectedCookies === "string") { - expect(headers["set-cookie"]).toBe(expectedCookies); - } else { - expect((headers["set-cookie"] as string[]).join(", ")).toBe( - expectedCookies.join(", ") - ); - } + expect(headers["set-cookie"]).toMatchObject(expectedCookies); }); }); describe("errors", () => { it.skipIf(ctx.isIsolated)("captures errors", async () => { - const { data } = await callHandler({ url: "/api/errors" }); - const allErrorMessages = (data.allErrors || []).map( - (entry: any) => entry.message - ); - expect(allErrorMessages).to.includes("Service Unavailable"); + await callHandler({ url: "/errors/throw" }); + const { data } = await callHandler({ url: "/errors/captured" }); + const allErrorMessages = (data.allErrors || []).map((entry: any) => entry.message); + expect(allErrorMessages).to.includes("Handled error"); }); it.skipIf( @@ -695,9 +651,83 @@ export function testNitro( ctx.preset === "deno-server" || ctx.preset === "nitro-dev" )("sourcemap works", async () => { - const { data } = await callHandler({ url: "/error-stack" }); - expect(data.stack).toMatch("test/fixture/routes/error-stack.ts"); - }); + const { data } = await callHandler({ url: "/errors/stack" }); + expect(data.stack).toMatch("test/fixture/server/routes/errors/stack.ts"); + }); + + for (const errorAction of ["throw", "return"]) { + it(`handled errors (${errorAction})`, async () => { + const res = await callHandler({ url: `/errors/throw?handled&action=${errorAction}` }); + expect(res).toMatchObject({ + status: 503, + statusText: /deno|bun/.test(ctx.preset) + ? "Service Unavailable" + : /aws/.test(ctx.preset) + ? "" + : "Custom Status Text", + headers: { + "content-type": "application/json; charset=utf-8", + "x-custom-error": "custom-value", + }, + data: { + error: true, + status: 503, + statusText: "Custom Status Text", + message: "Handled error", + data: { custom: "data" }, + custom: "body", + }, + }); + }); + + it(`unhandled errors (${errorAction})`, async () => { + const stderrMock = vi.spyOn(process.stderr, "write").mockImplementation(() => true); + const consoleErrorMock = vi.spyOn(console, "error").mockImplementation(() => {}); + let res; + try { + res = await callHandler({ + url: `/errors/throw?unhandled&action=${errorAction}`, + headers: { Accept: "application/json" }, + }); + } finally { + stderrMock.mockRestore(); + consoleErrorMock.mockRestore(); + } + // TODO + // expect(consoleErrorMock).toHaveBeenCalledExactlyOnceWith( + // expect.stringContaining("Unhandled error") + // ); + if (!ctx.isDev) { + // Prod + expect(res).toMatchObject({ + status: 500, + headers: { + "content-type": "application/json; charset=utf-8", + }, + data: { + error: true, + unhandled: true, + status: 500, + }, + }); + } else { + // Dev + expect(res).toMatchObject({ + status: 500, + headers: { + "content-type": "application/json; charset=utf-8", + }, + data: { + error: true, + unhandled: true, + status: 500, + message: "HTTPError", + stack: expect.arrayContaining(["Unhandled error"]), + }, + }); + } + }); + } }); describe("async context", () => { @@ -725,10 +755,11 @@ export function testNitro( "should setItem before returning response the first time", async () => { const { - data: { timestamp, eventContextCache }, + data: { timestamp }, } = await callHandler({ url: "/api/cached" }); - expect(eventContextCache?.options.swr).toBe(true); + // TODO + // expect(eventContextCache?.options.swr).toBe(true); const calls = await Promise.all([ callHandler({ url: "/api/cached" }), @@ -738,7 +769,8 @@ export function testNitro( for (const call of calls) { expect(call.data.timestamp).toBe(timestamp); - expect(call.data.eventContextCache.options.swr).toBe(true); + // TODO + // expect(call.data.eventContextCache.options.swr).toBe(true); } } ); @@ -747,23 +779,17 @@ export function testNitro( describe("scanned files", () => { it("Allow having extra method in file name", async () => { expect((await callHandler({ url: "/api/methods/get" })).data).toBe("get"); - expect((await callHandler({ url: "/api/methods/foo.get" })).data).toBe( - "foo.get" - ); + expect((await callHandler({ url: "/api/methods/foo.get" })).data).toBe("foo.get"); }); }); describe.skipIf(ctx.preset === "cloudflare-worker")("wasm", () => { it("dynamic import wasm", async () => { - expect((await callHandler({ url: "/wasm/dynamic-import" })).data).toBe( - "2+3=5" - ); + expect((await callHandler({ url: "/wasm/dynamic-import" })).data).toBe("2+3=5"); }); it("static import wasm", async () => { - expect((await callHandler({ url: "/wasm/static-import" })).data).toBe( - "2+3=5" - ); + expect((await callHandler({ url: "/wasm/static-import" })).data).toBe("2+3=5"); }); }); @@ -772,13 +798,7 @@ export function testNitro( !ctx.nitro!.options.node || ctx.isLambda || ctx.isWorker || - [ - "bun", - "deno-server", - "deno-deploy", - "netlify", - "netlify-legacy", - ].includes(ctx.preset) + ["bun", "deno-server", "deno-deploy", "netlify", "netlify-legacy"].includes(ctx.preset) )("Database", () => { it("works", async () => { const { data } = await callHandler({ url: "/api/db" }); @@ -811,7 +831,8 @@ export function testNitro( }); it.skipIf( - ["cloudflare-worker", "cloudflare-module-legacy"].includes(ctx.preset) + process.env.OFFLINE /* connect */ || + ["cloudflare-worker", "cloudflare-module-legacy"].includes(ctx.preset) )("nodejs compatibility", async () => { const { data, status } = await callHandler({ url: "/node-compat" }); expect(status).toBe(200); @@ -822,6 +843,13 @@ export function testNitro( if (ctx.preset === "deno-server" && key === "globals:BroadcastChannel") { continue; // unstable API } + if ( + ctx.preset.includes("cloudflare") && + key.startsWith("globals:") && + ctx.nitro!.options.builder === "rolldown" + ) { + continue; + } expect(data[key], key).toBe(true); } }); diff --git a/test/unit/azure.utils.test.ts b/test/unit/azure.utils.test.ts index 984e2f8975..d161f82153 100644 --- a/test/unit/azure.utils.test.ts +++ b/test/unit/azure.utils.test.ts @@ -1,23 +1,16 @@ import { describe, expect, it } from "vitest"; -import { getAzureParsedCookiesFromHeaders } from "../../src/runtime/internal/utils.azure"; +import { getAzureParsedCookiesFromHeaders } from "../../src/presets/azure/runtime/_utils.ts"; describe("getAzureParsedCookiesFromHeaders", () => { it("returns empty array if no cookies", () => { - expect(getAzureParsedCookiesFromHeaders({})).toMatchObject([]); - }); - it("returns empty array if no set-cookie header", () => { - expect( - getAzureParsedCookiesFromHeaders({ "set-cookie": undefined }) - ).toMatchObject([]); + expect(getAzureParsedCookiesFromHeaders(new Headers({}))).toMatchObject([]); }); it("returns empty array if empty set-cookie header", () => { - expect( - getAzureParsedCookiesFromHeaders({ "set-cookie": " " }) - ).toMatchObject([]); + expect(getAzureParsedCookiesFromHeaders(new Headers({ "set-cookie": " " }))).toMatchObject([]); }); it("returns single cookie", () => { expect( - getAzureParsedCookiesFromHeaders({ "set-cookie": "foo=bar" }) + getAzureParsedCookiesFromHeaders(new Headers({ "set-cookie": "foo=bar" })) ).toMatchObject([ { name: "foo", @@ -27,9 +20,11 @@ describe("getAzureParsedCookiesFromHeaders", () => { }); it('returns cookie with "expires" attribute', () => { expect( - getAzureParsedCookiesFromHeaders({ - "set-cookie": "foo=bar; expires=Thu, 01 Jan 1970 00:00:00 GMT", - }) + getAzureParsedCookiesFromHeaders( + new Headers({ + "set-cookie": "foo=bar; expires=Thu, 01 Jan 1970 00:00:00 GMT", + }) + ) ).toMatchObject([ { name: "foo", @@ -40,11 +35,12 @@ describe("getAzureParsedCookiesFromHeaders", () => { }); it("returns a complex cookie", () => { expect( - getAzureParsedCookiesFromHeaders({ - "set-cookie": [ - "session=xyz; Path=/; Expires=Sun, 24 Mar 2024 09:13:27 GMT; HttpOnly; SameSite=Strict", - ], - }) + getAzureParsedCookiesFromHeaders( + new Headers({ + "set-cookie": + "session=xyz; Path=/; Expires=Sun, 24 Mar 2024 09:13:27 GMT; HttpOnly; SameSite=Strict", + }) + ) ).toMatchObject([ { name: "session", @@ -58,25 +54,12 @@ describe("getAzureParsedCookiesFromHeaders", () => { }); it("returns multiple cookies", () => { expect( - getAzureParsedCookiesFromHeaders({ - "set-cookie": ["foo=bar", "baz=qux"], - }) - ).toMatchObject([ - { - name: "foo", - value: "bar", - }, - { - name: "baz", - value: "qux", - }, - ]); - }); - it("returns multiple cookies given as string", () => { - expect( - getAzureParsedCookiesFromHeaders({ - "set-cookie": "foo=bar, baz=qux", - }) + getAzureParsedCookiesFromHeaders( + new Headers([ + ["set-cookie", "foo=bar"], + ["set-cookie", "baz=qux"], + ]) + ) ).toMatchObject([ { name: "foo", diff --git a/test/unit/bump-version.test.ts b/test/unit/bump-version.test.ts new file mode 100644 index 0000000000..8913096b35 --- /dev/null +++ b/test/unit/bump-version.test.ts @@ -0,0 +1,77 @@ +import { describe, it, expect, vi, beforeEach } from "vitest"; +import { valid as semverValid } from "semver"; + +vi.mock("node:fs", () => ({ + promises: { + readFile: vi.fn(), + writeFile: vi.fn(), + }, +})); + +const fetchMock = vi.fn(); +vi.stubGlobal("fetch", fetchMock); + +function mockRegistry(versions: string[]) { + fetchMock.mockResolvedValue({ + ok: true, + json: async () => ({ versions: Object.fromEntries(versions.map((v) => [v, {}])) }), + }); +} + +beforeEach(() => { + vi.restoreAllMocks(); + fetchMock.mockReset(); +}); + +describe("fmtDate", async () => { + const { fmtDate } = await import("../../scripts/bump-version.ts"); + + it("formats date as YYMMDD", () => { + expect(fmtDate(new Date("2026-03-11"))).toBe("260311"); + expect(fmtDate(new Date("2025-01-05"))).toBe("250105"); + }); +}); + +describe("resolveVersion", async () => { + const { resolveVersion } = await import("../../scripts/bump-version.ts"); + + const cases = [ + { name: "no existing versions", existing: [], expected: "3.0.260311-beta" }, + { name: "one existing version", existing: ["3.0.260311-beta"], expected: "3.0.260311-beta.2" }, + { + name: "multiple existing versions", + existing: ["3.0.260311-beta", "3.0.260311-beta.2"], + expected: "3.0.260311-beta.3", + }, + { + name: "other dates only", + existing: ["3.0.260310-beta", "3.0.260310-beta.3"], + expected: "3.0.260311-beta", + }, + { + name: "without prerelease tag", + existing: ["3.0.260311-1", "3.0.260311-2"], + expected: "3.0.260311-3", + prerelease: "", + }, + { + name: "without prerelease, no existing", + existing: [], + expected: "3.0.260311", + prerelease: "", + }, + ]; + + for (const { name, existing, expected, prerelease } of cases) { + it(`${name}: ${existing.join(", ") || "(none)"} → ${expected}`, async () => { + mockRegistry(existing); + const version = await resolveVersion( + "nitro", + "260311", + ...(prerelease !== undefined ? [prerelease] : []) + ); + expect(version).toBe(expected); + expect(semverValid(version)).toBe(version); + }); + } +}); diff --git a/test/unit/chunks.test.ts b/test/unit/chunks.test.ts new file mode 100644 index 0000000000..bfdaa23dea --- /dev/null +++ b/test/unit/chunks.test.ts @@ -0,0 +1,193 @@ +import { describe, expect, it } from "vitest"; +import type { Nitro } from "nitro/types"; +import { + NODE_MODULES_RE, + libChunkName, + pathToPkgName, + getChunkName, + routeToFsPath, +} from "../../src/build/chunks.ts"; + +function createChunk(name: string, moduleIds: string[]): { name: string; moduleIds: string[] } { + return { name, moduleIds }; +} + +function createNitro(overrides: Partial = {}): Nitro { + return { + options: { buildDir: "/build", tasks: {}, ...overrides.options }, + routing: { + routes: { routes: [] }, + ...overrides.routing, + }, + ...overrides, + } as unknown as Nitro; +} + +describe("NODE_MODULES_RE", () => { + it.each([ + ["/foo/node_modules/bar/index.js", true], + ["node_modules/bar/index.js", true], + ["node_modules\\bar\\index.js", true], + ["/foo/node_modules/nitro/dist/index.js", false], + ["/foo/node_modules/nitro-nightly/dist/index.js", false], + ["/foo/node_modules/.nitro", false], + ["/foo/node_modules/.cache", false], + ["/foo/src/bar.js", false], + ])("%s → %s", (path, expected) => { + expect(NODE_MODULES_RE.test(path)).toBe(expected); + }); +}); + +describe("pathToPkgName", () => { + it.each([ + ["/foo/node_modules/express/index.js", "express"], + ["/foo/node_modules/@h3/core/index.js", "@h3/core"], + ["C:\\proj\\node_modules\\express\\index.js", "express"], + ["C:\\proj\\node_modules\\@h3\\core\\index.js", "@h3\\core"], + ["/node_modules/nitro-nightly/dist/index.js", "nitro"], + ["/node_modules/a/node_modules/b/index.js", "b"], + ["/foo/src/bar.js", undefined], + ])("%s → %s", (path, expected) => { + expect(pathToPkgName(path)).toBe(expected); + }); +}); + +describe("libChunkName", () => { + it.each([ + ["/node_modules/express/index.js", "_libs/express"], + ["/node_modules/@h3/core/index.js", "_libs/@h3/core"], + ["/src/utils/foo.ts", undefined], + ["/node_modules/nitro-nightly/dist/index.js", "_libs/nitro"], + ])("%s → %s", (id, expected) => { + expect(libChunkName(id)).toBe(expected); + }); +}); + +describe("routeToFsPath", () => { + it.each([ + ["/api/hello", "api/hello"], + ["/api/users/:id", "api/users/[id]"], + ["/", "index"], + ["/api/users/:id/posts/*", "api/users/[id]/posts/[...]"], + ])("%s → %s", (route, expected) => { + expect(routeToFsPath(route)).toBe(expected); + }); +}); + +describe("getChunkName", () => { + const nitro = createNitro(); + + it.each<[string, { name: string; moduleIds: string[] }, string]>([ + ["rolldown-runtime", createChunk("rolldown-runtime", []), "_runtime.mjs"], + ["_ chunks are preserved", createChunk("_shared", ["/src/foo.ts"]), "_shared.mjs"], + [ + "all node_modules (sorted a-z)", + createChunk("vendor", ["/node_modules/express/index.js", "/node_modules/h3/dist/index.mjs"]), + "_libs/express+h3.mjs", + ], + [ + "single node_modules package", + createChunk("vendor", ["/node_modules/a/index.js"]), + "_libs/a.mjs", + ], + [ + "node_modules names exceed 30 chars", + createChunk("_libs/vendor", [ + "/node_modules/some-very-long-package-name/index.js", + "/node_modules/another-very-long-name/index.js", + ]), + "_libs/vendor+[...].mjs", + ], + [ + "3 node_modules sorted a-z", + createChunk("vendor", [ + "/node_modules/zod/index.js", + "/node_modules/ab/index.js", + "/node_modules/h3/dist/index.mjs", + ]), + "_libs/ab+h3+zod.mjs", + ], + [ + "scoped packages use __ separator", + createChunk("vendor", ["/node_modules/@h3/core/index.js", "/node_modules/defu/index.js"]), + "_libs/defu+h3__core.mjs", + ], + ["empty moduleIds (vacuous every())", createChunk("my-chunk", []), "_libs/_.mjs"], + [ + "virtual:raw modules", + createChunk("raw", ["\0virtual:raw:foo", "#virtual:raw:bar"]), + "_raw/[name].mjs", + ], + ["all virtual modules", createChunk("virt", ["\0something", "#other"]), "_virtual/[name].mjs"], + ["wasm modules", createChunk("wasm", ["/src/module.wasm"]), "_wasm/[name].mjs"], + [ + "vite/services modules", + createChunk("ssr", ["/vite/services/component.js"]), + "_ssr/[name].mjs", + ], + ["buildDir modules", createChunk("build", ["/build/generated.js"]), "_build/[name].mjs"], + [ + "mixed virtual + wasm", + createChunk("mixed", ["\0virtual:something", "/src/module.wasm"]), + "_wasm/[name].mjs", + ], + ["fallback to _chunks", createChunk("misc", ["/src/utils/helper.ts"]), "_chunks/[name].mjs"], + ])("%s → %s", (_label, chunk, expected) => { + expect(getChunkName(chunk, nitro)).toBe(expected); + }); + + it("returns _routes/.mjs for route handler", () => { + const n = createNitro({ + routing: { + routes: { + routes: [{ data: [{ route: "/api/hello", handler: "/src/routes/api/hello.ts" }] }], + }, + }, + } as any); + expect(getChunkName(createChunk("route", ["/src/routes/api/hello.ts"]), n)).toBe( + "_routes/api/hello.mjs" + ); + }); + + it("returns _routes/.mjs for dynamic route", () => { + const n = createNitro({ + routing: { + routes: { + routes: [ + { + data: [{ route: "/api/users/:id", handler: "/src/routes/api/users/[id].ts" }], + }, + ], + }, + }, + } as any); + expect(getChunkName(createChunk("route", ["/src/routes/api/users/[id].ts"]), n)).toBe( + "_routes/api/users/[id].mjs" + ); + }); + + it("returns _routes/index.mjs for root route", () => { + const n = createNitro({ + routing: { + routes: { + routes: [{ data: [{ route: "/", handler: "/src/routes/index.ts" }] }], + }, + }, + } as any); + expect(getChunkName(createChunk("route", ["/src/routes/index.ts"]), n)).toBe( + "_routes/index.mjs" + ); + }); + + it("returns _tasks/[name].mjs for task handler", () => { + const n = createNitro({ + options: { + buildDir: "/build", + tasks: { "db:migrate": { handler: "/src/tasks/migrate.ts" } }, + }, + } as any); + expect(getChunkName(createChunk("task", ["/src/tasks/migrate.ts"]), n)).toBe( + "_tasks/[name].mjs" + ); + }); +}); diff --git a/test/unit/config-loader-env.test.ts b/test/unit/config-loader-env.test.ts new file mode 100644 index 0000000000..59c5e256d8 --- /dev/null +++ b/test/unit/config-loader-env.test.ts @@ -0,0 +1,81 @@ +import { mkdtemp, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "pathe"; +import { afterEach, describe, expect, it, vi } from "vitest"; + +vi.mock("nitro/meta", () => ({ + version: "0.0.0-test", + runtimeDir: "/tmp", + presetsDir: "/tmp", + pkgDir: "/tmp", + runtimeDependencies: [], +})); + +const originalNodeEnv = process.env.NODE_ENV; +const tempDirs: string[] = []; + +async function createFixtureConfig() { + const rootDir = await mkdtemp(join(tmpdir(), "nitro-config-env-")); + tempDirs.push(rootDir); + + await writeFile( + join(rootDir, "nitro.config.ts"), + `export default defineNitroConfig({ + preset: 'node-server', + routeRules: { + '/base': { headers: { 'x-env': 'base' } } + }, + $production: { + routeRules: { + '/prod': { headers: { 'x-env': 'production' } } + } + }, + $development: { + routeRules: { + '/dev': { headers: { 'x-env': 'development' } } + } + } +}) +` + ); + + return rootDir; +} + +afterEach(async () => { + if (originalNodeEnv === undefined) { + delete process.env.NODE_ENV; + } else { + process.env.NODE_ENV = originalNodeEnv; + } + + for (const dir of tempDirs.splice(0, tempDirs.length)) { + await rm(dir, { recursive: true, force: true }); + } +}); + +describe.skip("config loader env layers", () => { + it("applies $production when NODE_ENV is unset and dev=false", async () => { + delete process.env.NODE_ENV; + const rootDir = await createFixtureConfig(); + + const { loadOptions } = await import("../../src/config/loader.ts"); + const options = await loadOptions({ rootDir, dev: false }); + + expect(options.routeRules["/prod"]?.headers?.["x-env"]).toBe("production"); + expect(options.routeRules["/dev"]).toBeUndefined(); + expect(options.routeRules["/base"]?.headers?.["x-env"]).toBe("base"); + }); + + it("applies $development when NODE_ENV is unset and dev=true", async () => { + delete process.env.NODE_ENV; + const rootDir = await createFixtureConfig(); + + const { loadOptions } = await import("../../src/config/loader.ts"); + const options = await loadOptions({ rootDir, dev: true }); + + expect(options.routeRules["/dev"]?.headers?.["x-env"]).toBe("development"); + expect(options.routeRules["/prod"]).toBeUndefined(); + expect(options.routeRules["/base"]?.headers?.["x-env"]).toBe("base"); + }); +}); diff --git a/test/unit/externals.test.ts b/test/unit/externals.test.ts deleted file mode 100644 index ee2377ff6c..0000000000 --- a/test/unit/externals.test.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { applyProductionCondition } from "../../src/rollup/plugins/externals"; - -describe("externals:applyProductionCondition", () => { - const applyProductionConditionCases = [ - { - name: "vue-router@4.1.6", - in: { - ".": { - types: "./dist/vue-router.d.ts", - node: { - import: { - production: "./dist/vue-router.node.mjs", - development: "./dist/vue-router.node.mjs", - default: "./dist/vue-router.node.mjs", - }, - require: { - production: "./dist/vue-router.prod.cjs", - development: "./dist/vue-router.cjs", - default: "./index.js", - }, - }, - import: "./dist/vue-router.mjs", - require: "./index.js", - }, - "./dist/*": "./dist/*", - "./vetur/*": "./vetur/*", - "./package.json": "./package.json", - }, - out: { - ".": { - types: "./dist/vue-router.d.ts", - node: { - import: { - production: "./dist/vue-router.node.mjs", - development: "./dist/vue-router.node.mjs", - default: "./dist/vue-router.node.mjs", - }, - require: { - production: "./dist/vue-router.prod.cjs", - development: "./dist/vue-router.cjs", - default: "./dist/vue-router.prod.cjs", - }, - }, - import: "./dist/vue-router.mjs", - require: "./index.js", - }, - "./dist/*": "./dist/*", - "./vetur/*": "./vetur/*", - "./package.json": "./package.json", - }, - }, - { - name: "fluent-vue@3.2.0", - in: { - ".": { - production: { - require: "./dist/prod/index.cjs", - import: "./dist/prod/index.mjs", - }, - types: "./index.d.ts", - require: "./dist/index.cjs", - import: "./dist/index.mjs", - }, - }, - out: { - ".": { - import: "./dist/prod/index.mjs", - production: { - import: "./dist/prod/index.mjs", - require: "./dist/prod/index.cjs", - }, - require: "./dist/prod/index.cjs", - types: "./index.d.ts", - }, - }, - }, - ]; - for (const t of applyProductionConditionCases) { - it(t.name, () => { - applyProductionCondition(t.in as any); - expect(t.in).toEqual(t.out); - }); - } -}); diff --git a/test/unit/hash.test.ts b/test/unit/hash.test.ts deleted file mode 100644 index 60d4f5adf7..0000000000 --- a/test/unit/hash.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { describe, expect, it, vi } from "vitest"; -import { hash as ohashV1, objectHash } from "ohash-v1"; -import { hash, serialize } from "../../src/runtime/internal/hash"; - -describe("cache: hash consistency", async () => { - const inputs = [ - "test", - 123, - true, - false, - null, - undefined, - {}, - { foo: "bar" }, - new Uint8Array(0), - new Uint8Array([1, 2, 3]), - [1, "test", true], - Buffer.from("test"), - ]; - for (const input of inputs) { - it(JSON.stringify(input), () => { - expect( - hash(input), - `${serialize(input)} should be ${objectHash(input)}` - ).toBe(ohashV1(input)); - }); - } -}); diff --git a/test/unit/utils.env.test.ts b/test/unit/runtime-config.env.test.ts similarity index 80% rename from test/unit/utils.env.test.ts rename to test/unit/runtime-config.env.test.ts index f4375a1c4c..e1d8ad971c 100644 --- a/test/unit/utils.env.test.ts +++ b/test/unit/runtime-config.env.test.ts @@ -1,37 +1,29 @@ import { describe, expect, it } from "vitest"; -import { applyEnv } from "../../src/runtime/internal/utils.env"; + +import { applyEnv } from "../../src/runtime/internal/runtime-config.ts"; describe("env utils", () => { describe("applyEnv", () => { const tests = [ { - config: { a: 1, b: 2 }, + config: { a: "1", b: "2" }, env: { NITRO_A: "123" }, - expected: { a: 123, b: 2 }, - }, - { - config: { feature: { options: { optionA: true, optionB: true } } }, - env: { NITRO_FEATURE: false }, - expected: { feature: false }, + expected: { a: "123", b: "2" }, }, { - config: { feature: { options: { optionA: true, optionB: true } } }, - env: { NITRO_FEATURE_OPTIONS: false }, - expected: { feature: { options: false } }, + config: { feature: { options: { option1: "original", option2: 123 } } }, + env: { NITRO_FEATURE_OPTIONS_OPTION1: "env" }, + expected: { feature: { options: { option1: "env", option2: 123 } } }, }, ]; for (const test of tests) { - it(`Config: ${JSON.stringify(test.config)} Env: { ${Object.entries( - test.env - ) + it(`Config: ${JSON.stringify(test.config)} Env: { ${Object.entries(test.env) .map(([key, value]) => `${key}=${JSON.stringify(value)}`) .join(" ")} }`, () => { for (const key in test.env) { process.env[key] = test.env[key as keyof typeof test.env] as string; } - expect(applyEnv(test.config, { prefix: "NITRO_" })).toEqual( - test.expected - ); + expect(applyEnv(test.config, { prefix: "NITRO_" })).toEqual(test.expected); for (const key in test.env) { delete process.env[key]; } diff --git a/test/unit/runtime-config.test.ts b/test/unit/runtime-config.test.ts index 9a462888c7..f731b648a9 100644 --- a/test/unit/runtime-config.test.ts +++ b/test/unit/runtime-config.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it, vi } from "vitest"; -import { normalizeRuntimeConfig } from "../../src/core/config/resolvers/runtime-config"; -import type { NitroConfig } from "nitropack/types"; +import { normalizeRuntimeConfig } from "../../src/config/resolvers/runtime-config.ts"; +import type { NitroConfig } from "nitro/types"; const defaultRuntimeConfig = { textProperty: "value", @@ -49,7 +49,7 @@ describe("normalizeRuntimeConfig", () => { }); it("should throw a warning when runtimeConfig is not serializable", () => { - const originalWarn = console.warn; + // const originalWarn = console.warn; const spyWarn = (console.warn = vi.fn()); normalizeRuntimeConfig({ ...nitroConfig, diff --git a/test/unit/sourcemap-min.test.ts b/test/unit/sourcemap-min.test.ts new file mode 100644 index 0000000000..5cd6900b44 --- /dev/null +++ b/test/unit/sourcemap-min.test.ts @@ -0,0 +1,112 @@ +import { describe, expect, it } from "vitest"; +import { sourcemapMinify } from "../../src/build/plugins/sourcemap-min.ts"; + +type BundleAsset = { type: "asset"; source: string }; + +function createSourcemapAsset(sourcemap: { + sources?: string[]; + sourcesContent?: string[]; + mappings?: string; + x_google_ignoreList?: number[]; +}): BundleAsset { + return { + type: "asset", + source: JSON.stringify({ + version: 3, + sources: [], + mappings: "AAAA,CAAC", + ...sourcemap, + }), + }; +} + +function runPlugin(bundle: Record) { + const plugin = sourcemapMinify(); + (plugin.generateBundle as Function).call(null, {}, bundle); + const results: Record> = {}; + for (const [key, asset] of Object.entries(bundle)) { + if (key.endsWith(".map")) { + results[key] = JSON.parse(asset.source); + } + } + return results; +} + +describe("sourcemapMinify", () => { + it("removes sourcesContent from all sourcemaps", () => { + const bundle = { + "index.mjs.map": createSourcemapAsset({ + sources: ["src/index.ts"], + sourcesContent: ["export default 42;"], + }), + }; + const results = runPlugin(bundle); + expect(results["index.mjs.map"].sourcesContent).toBeUndefined(); + }); + + it("removes x_google_ignoreList from all sourcemaps", () => { + const bundle = { + "index.mjs.map": createSourcemapAsset({ + sources: ["src/index.ts"], + x_google_ignoreList: [0], + }), + }; + const results = runPlugin(bundle); + expect(results["index.mjs.map"].x_google_ignoreList).toBeUndefined(); + }); + + it("wipes mappings for pure library chunks", () => { + const bundle = { + "_libs/express.mjs.map": createSourcemapAsset({ + sources: [ + "../../node_modules/express/index.js", + "../../node_modules/express/lib/router.js", + ], + mappings: "AAAA,CAAC", + }), + }; + const results = runPlugin(bundle); + expect(results["_libs/express.mjs.map"].mappings).toBe(""); + }); + + it("preserves mappings for pure user code chunks", () => { + const bundle = { + "_routes/api/hello.mjs.map": createSourcemapAsset({ + sources: ["src/routes/api/hello.ts"], + mappings: "AAAA,CAAC", + }), + }; + const results = runPlugin(bundle); + expect(results["_routes/api/hello.mjs.map"].mappings).toBe("AAAA,CAAC"); + }); + + it("preserves mappings when library is hoisted into user chunk", () => { + const bundle = { + "_routes/api/hello.mjs.map": createSourcemapAsset({ + sources: ["src/routes/api/hello.ts", "../../node_modules/some-lib/index.js"], + mappings: "AAAA,CAAC", + }), + }; + const results = runPlugin(bundle); + expect(results["_routes/api/hello.mjs.map"].mappings).toBe("AAAA,CAAC"); + }); + + it("skips non-sourcemap files", () => { + const bundle = { + "index.mjs": { type: "asset" as const, source: "console.log(42)" }, + }; + runPlugin(bundle as any); + expect(bundle["index.mjs"].source).toBe("console.log(42)"); + }); + + it("handles empty sources array", () => { + const bundle = { + "chunk.mjs.map": createSourcemapAsset({ + sources: [], + mappings: "AAAA,CAAC", + }), + }; + const results = runPlugin(bundle); + expect(results["chunk.mjs.map"].mappings).toBe(""); + }); +}); diff --git a/test/unit/static-middleware.test.ts b/test/unit/static-middleware.test.ts new file mode 100644 index 0000000000..d28b41de47 --- /dev/null +++ b/test/unit/static-middleware.test.ts @@ -0,0 +1,65 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; +import { mockEvent } from "h3"; +import handler from "../../src/runtime/internal/static.ts"; + +const { getAsset, isPublicAssetURL, readAsset } = vi.hoisted(() => ({ + getAsset: vi.fn(), + isPublicAssetURL: vi.fn(), + readAsset: vi.fn(), +})); + +vi.mock("#nitro/virtual/public-assets", () => ({ + getAsset, + isPublicAssetURL, + readAsset, +})); + +function createEvent(pathname: string, acceptEncoding = "") { + const event = mockEvent(`http://localhost${pathname}`, { + headers: acceptEncoding ? { "accept-encoding": acceptEncoding } : undefined, + }); + event.res.headers.set("Vary", "Origin"); + event.res.headers.set("Cache-Control", "max-age=3600"); + return event; +} + +describe("runtime static middleware", () => { + beforeEach(() => { + getAsset.mockReset(); + isPublicAssetURL.mockReset(); + readAsset.mockReset(); + }); + + it("does not append Accept-Encoding vary when no asset is matched", async () => { + getAsset.mockReturnValue(undefined); + isPublicAssetURL.mockReturnValue(true); + const event = createEvent("/foo-missing.css", "gzip"); + + expect(() => handler(event)).toThrow("404"); + expect(event.res.headers.get("Vary")).toBe("Origin"); + expect(event.res.headers.get("Cache-Control")).toBeNull(); + }); + + it("appends Accept-Encoding vary when a compressed asset is matched", async () => { + getAsset.mockImplementation((id: string) => { + if (id === "/foo.css.gz") { + return { + etag: '"test"', + mtime: Date.now(), + type: "text/css", + encoding: "gzip", + size: 1, + }; + } + return undefined; + }); + isPublicAssetURL.mockReturnValue(true); + readAsset.mockResolvedValue("body"); + const event = createEvent("/foo.css", "gzip"); + + await handler(event); + + expect(event.res.headers.get("Vary")).toContain("Origin"); + expect(event.res.headers.get("Vary")).toContain("Accept-Encoding"); + }); +}); diff --git a/test/unit/virtual.test.ts b/test/unit/virtual.test.ts new file mode 100644 index 0000000000..5a8f857dcc --- /dev/null +++ b/test/unit/virtual.test.ts @@ -0,0 +1,11 @@ +import { describe, expect, it } from "vitest"; + +import { serverFetch } from "nitro/app"; + +describe("virtual modules", () => { + it("app fetch", async () => { + const res = await serverFetch("/"); + expect(res.status).toBe(404); + expect(await res.text()).to.include("Cannot find any route matching"); + }); +}); diff --git a/test/unit/zephyr-preset.test.ts b/test/unit/zephyr-preset.test.ts new file mode 100644 index 0000000000..c38a4d7aec --- /dev/null +++ b/test/unit/zephyr-preset.test.ts @@ -0,0 +1,137 @@ +import { afterEach, describe, expect, it, vi } from "vitest"; + +const ZEPHYR_PRESET_PATH = "../../src/presets/zephyr/preset.ts"; + +const importDepMock = vi.hoisted(() => vi.fn()); +vi.mock("../../src/utils/dep.ts", () => ({ + importDep: importDepMock, +})); + +async function getZephyrPreset() { + const { default: presets } = await import(ZEPHYR_PRESET_PATH); + return presets[0]; +} + +describe("zephyr preset", () => { + afterEach(() => { + vi.restoreAllMocks(); + vi.clearAllMocks(); + vi.resetModules(); + delete (globalThis as any).__nitroDeploying__; + delete process.env.NITRO_INTERNAL_ZEPHYR_SKIP_DEPLOY_ON_BUILD; + }); + + it("extends base-worker", async () => { + const preset = await getZephyrPreset(); + expect(preset.extends).toBe("base-worker"); + expect(preset.output?.publicDir).toBe("{{ output.dir }}/client/{{ baseURL }}"); + expect(preset.commands?.deploy).toBeUndefined(); + }); + + it("adds cloudflare unenv presets", async () => { + const preset = await getZephyrPreset(); + const hooks = preset.hooks!; + + const nitro = { + options: { + preset: "zephyr", + output: { + dir: "/tmp/zephyr-output", + serverDir: "/tmp/zephyr-output/server", + }, + unenv: [], + }, + logger: { + info: vi.fn(), + success: vi.fn(), + }, + } as any; + + await hooks["build:before"]?.(nitro); + expect(nitro.options.unenv).toHaveLength(2); + expect(nitro.options.unenv[0].meta?.name).toBe("nitro:cloudflare-externals"); + expect(nitro.options.unenv[1].meta?.name).toBe("nitro:cloudflare-node-compat"); + expect(nitro.logger.info).not.toHaveBeenCalled(); + expect(nitro.logger.success).not.toHaveBeenCalled(); + }); + + it("deploys on compiled hook by default", async () => { + const uploadOutputToZephyr = vi.fn().mockResolvedValue({ + deploymentUrl: "https://example.zephyr-cloud.io", + entrypoint: "server/index.mjs", + }); + importDepMock.mockResolvedValue({ uploadOutputToZephyr }); + + (globalThis as any).__nitroDeploying__ = true; + + const preset = await getZephyrPreset(); + + const hooks = preset.hooks!; + const nitro = { + options: { + rootDir: "/tmp/project", + baseURL: "/docs/", + output: { + dir: "/tmp/zephyr-output", + publicDir: "client/docs", + }, + }, + logger: { + info: vi.fn(), + success: vi.fn(), + }, + } as any; + + await hooks.compiled?.(nitro); + + expect(importDepMock).toHaveBeenCalledWith({ + id: "zephyr-agent", + reason: "deploying to Zephyr", + dir: "/tmp/project", + }); + expect(uploadOutputToZephyr).toHaveBeenCalledWith({ + rootDir: "/tmp/project", + baseURL: "/docs/", + outputDir: "/tmp/zephyr-output", + publicDir: "/tmp/zephyr-output/client/docs", + }); + expect(nitro.logger.success).toHaveBeenCalledWith( + "[zephyr-nitro-preset] Zephyr deployment succeeded: https://example.zephyr-cloud.io" + ); + expect(nitro.logger.info).not.toHaveBeenCalled(); + }); + + it("can skip deploy on build", async () => { + const uploadOutputToZephyr = vi.fn().mockResolvedValue({ + deploymentUrl: "https://example.zephyr-cloud.io", + entrypoint: "server/index.mjs", + }); + importDepMock.mockResolvedValue({ uploadOutputToZephyr }); + + const preset = await getZephyrPreset(); + const hooks = preset.hooks!; + const nitro = { + options: { + zephyr: { + deployOnBuild: false, + }, + output: { + dir: "/tmp/zephyr-output", + }, + }, + logger: { + info: vi.fn(), + success: vi.fn(), + }, + } as any; + + await hooks.compiled?.(nitro); + + expect(importDepMock).not.toHaveBeenCalled(); + expect(uploadOutputToZephyr).not.toHaveBeenCalled(); + expect(nitro.logger.info).toHaveBeenCalledWith( + "[zephyr-nitro-preset] Zephyr deploy skipped on build." + ); + expect(nitro.logger.success).not.toHaveBeenCalled(); + }); +}); diff --git a/test/vite/hmr-fixture/api/state.ts b/test/vite/hmr-fixture/api/state.ts new file mode 100644 index 0000000000..179dafca0a --- /dev/null +++ b/test/vite/hmr-fixture/api/state.ts @@ -0,0 +1,3 @@ +import { state } from "../shared.ts"; + +export default () => ({ state }); diff --git a/test/vite/hmr-fixture/app/entry-client.ts b/test/vite/hmr-fixture/app/entry-client.ts new file mode 100644 index 0000000000..d9ee20939d --- /dev/null +++ b/test/vite/hmr-fixture/app/entry-client.ts @@ -0,0 +1,3 @@ +import { state } from "../shared.ts"; + +document.getElementById("client-state-value")!.textContent = state + " (modified)"; diff --git a/test/vite/hmr-fixture/app/entry-server.ts b/test/vite/hmr-fixture/app/entry-server.ts new file mode 100644 index 0000000000..7ee680b093 --- /dev/null +++ b/test/vite/hmr-fixture/app/entry-server.ts @@ -0,0 +1,26 @@ +import { html } from "nitro/h3"; +import { serverFetch } from "nitro"; +import { state } from "../shared.ts"; + +export default { + fetch: async () => { + const apiData = (await serverFetch("/api/state").then((res) => res.json())) as { + state: number; + }; + const viteClientScript = ""; + const clientScript = ""; + return html` + + + ${viteClientScript} + +

    SSR Page

    +

    [SSR] state: ${state}

    +

    [API] state: ${apiData.state}

    +

    [Client] state: ?

    + ${clientScript} + + + `; + }, +}; diff --git a/test/vite/hmr-fixture/shared.ts b/test/vite/hmr-fixture/shared.ts new file mode 100644 index 0000000000..3eafc06aed --- /dev/null +++ b/test/vite/hmr-fixture/shared.ts @@ -0,0 +1 @@ +export const state = 1; diff --git a/test/vite/hmr-fixture/tsconfig.json b/test/vite/hmr-fixture/tsconfig.json new file mode 100644 index 0000000000..4b886bd47e --- /dev/null +++ b/test/vite/hmr-fixture/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "nitro/tsconfig" +} diff --git a/test/vite/hmr-fixture/vite.config.ts b/test/vite/hmr-fixture/vite.config.ts new file mode 100644 index 0000000000..dca04a0e8f --- /dev/null +++ b/test/vite/hmr-fixture/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ + plugins: [nitro({ serverDir: "./" })], +}); diff --git a/test/vite/hmr.test.ts b/test/vite/hmr.test.ts new file mode 100644 index 0000000000..95def37872 --- /dev/null +++ b/test/vite/hmr.test.ts @@ -0,0 +1,157 @@ +import { join } from "pathe"; +import { readFileSync, writeFileSync } from "node:fs"; +import { fileURLToPath } from "node:url"; +import type { ViteDevServer } from "vite"; +import { describe, test, expect, beforeAll, afterEach, afterAll } from "vitest"; + +const { createServer } = (await import( + process.env.NITRO_VITE_PKG || "vite" +)) as typeof import("vite"); + +describe("vite:hmr", { sequential: true }, () => { + let server: ViteDevServer; + let serverURL: string; + const wsMessages: any[] = []; + + const rootDir = fileURLToPath(new URL("./hmr-fixture", import.meta.url)); + + const files = { + client: openFileForEditing(join(rootDir, "app/entry-client.ts")), + api: openFileForEditing(join(rootDir, "api/state.ts")), + shared: openFileForEditing(join(rootDir, "shared.ts")), + ssr: openFileForEditing(join(rootDir, "app/entry-server.ts")), + }; + + beforeAll(async () => { + process.chdir(rootDir); + server = await createServer({ root: rootDir }); + + const originalSend = server.ws.send.bind(server.ws); + server.ws.send = function (payload: any) { + wsMessages.push(payload); + return originalSend(payload); + }; + + await server.listen("0" as unknown as number); + const addr = server.httpServer?.address() as { port: number; address: string; family: string }; + serverURL = `http://${addr.family === "IPv6" ? `[${addr.address}]` : addr.address}:${addr.port}`; + + const html = await fetch(serverURL).then((r) => r.text()); + expect(html).toContain("

    SSR Page

    "); + expect(html).toContain("[SSR] state: 1"); + expect(html).toContain("[API] state: 1"); + }, 30_000); + + afterAll(async () => { + await server?.close(); + }); + + afterEach(async () => { + wsMessages.length = 0; + let restored = false; + for (const file of Object.values(files)) { + if (file.restore()) { + restored = true; + } + } + if (restored) { + await waitFor(() => wsMessages.length > 0, 500); + } + wsMessages.length = 0; + }); + + test("editing API entry", async () => { + files.api.update((content) => + content.replace("({ state })", '({ state: state + " (modified)" })') + ); + await pollResponse(`${serverURL}/api/state`, /modified/); + expect(wsMessages).toMatchObject([{ type: "full-reload" }]); + }); + + test("Editing client entry (no full-reload)", async () => { + files.client.update((content) => content.replace(`+ ""`, `+ " (modified)"`)); + await pollResponse(`${serverURL}/app/entry-client.ts`, /modified/); + expect(wsMessages.length).toBe(0); + }); + + test("editing SSR entry (no full-reload)", async () => { + files.ssr.update((content) => + content.replace("

    SSR Page

    ", "

    Modified SSR Page

    ") + ); + await pollResponse(serverURL, /Modified SSR Page/); + expect(wsMessages.length).toBe(0); + }); + + test("Editing shared entry", async () => { + files.shared.update((content) => content.replace(`state = 1`, `state = 2`)); + await pollResponse( + `${serverURL}`, + (txt) => txt.includes("state: 2") && !txt.includes("state: 1") + ); + expect(wsMessages).toMatchObject([{ type: "full-reload" }]); + }); +}); + +function openFileForEditing(path: string) { + const originalContent = readFileSync(path, "utf-8"); + return { + path, + update(cb: (content: string) => string) { + const currentContent = readFileSync(path, "utf-8"); + const newContent = cb(currentContent); + writeFileSync(path, newContent); + }, + restore() { + if (readFileSync(path, "utf-8") !== originalContent) { + writeFileSync(path, originalContent); + return true; + } + return false; + }, + }; +} + +function waitFor(check: () => boolean, duration: number): Promise { + const start = Date.now(); + return new Promise((resolve) => { + const poll = () => { + if (check() || Date.now() - start > duration) { + resolve(); + } else { + setTimeout(poll, 10); + } + }; + poll(); + }); +} + +function pollResponse( + url: string, + match: RegExp | ((txt: string) => boolean), + timeout = 5000 +): Promise { + const start = Date.now(); + let lastResponse = ""; + return new Promise((resolve, reject) => { + const check = async () => { + try { + const response = await fetch(url); + lastResponse = await response.text(); + if (typeof match === "function" ? match(lastResponse) : match.test(lastResponse)) { + resolve(lastResponse); + } else if (Date.now() - start > timeout) { + reject( + new Error( + `Timeout waiting for response to match ${match} at ${url}. Last response: ${lastResponse}` + ) + ); + } else { + setTimeout(check, 100); + } + } catch (err) { + reject(err); + } + }; + check(); + }); +} diff --git a/tsconfig.json b/tsconfig.json index 3b7bb997b7..b99703ce4f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,74 +1,22 @@ { + "extends": "./lib/tsconfig.json", "compilerOptions": { - /* Base options: */ - "esModuleInterop": false, + "module": "NodeNext", + "moduleResolution": "NodeNext", "allowSyntheticDefaultImports": true, - "skipLibCheck": true, - "target": "es2022", - "allowJs": true, - "resolveJsonModule": true, - "moduleDetection": "force", - "isolatedModules": true, - "verbatimModuleSyntax": true, - /* Strictness */ - "strict": true, - // TODO: enable noUncheckedIndexedAccess in subsequent PR - // "noUncheckedIndexedAccess": true, - "forceConsistentCasingInFileNames": true, - "noImplicitOverride": true, - /* If NOT transpiling with TypeScript: */ - "module": "preserve", - "noEmit": true, + "erasableSyntaxOnly": true, + "noUncheckedIndexedAccess": false, + "noImplicitReturns": false, "jsx": "preserve", - "jsxFactory": "h", - "jsxFragmentFactory": "Fragment", "lib": ["es2022", "webworker", "dom.iterable"], - "paths": { - // CLI - "nitro/cli": ["./src/cli"], - "nitropack/cli": ["./src/cli"], - // Config - "nitro/config": ["./src/config"], - "nitropack/config": ["./src/config"], - // Core - "nitro/core": ["./src/core"], - "nitropack/core": ["./src/core"], - // Core (alias) - "nitro": ["./src/core"], - "nitropack": ["./src/core"], - // Runtime - "nitro/runtime": ["./src/runtime"], - "nitropack/runtime": ["./src/runtime"], - // Runtime subpaths - "nitro/runtime/*": ["./src/runtime/*"], - "nitropack/runtime/*": ["./src/runtime/*"], - // Runtime meta - "nitro/runtime/meta": ["./runtime-meta"], - "nitropack/runtime/meta": ["./runtime-meta"], - // Kit - "nitro/kit": ["./src/kit"], - "nitropack/kit": ["./src/kit"], - // Meta - "nitro/meta": ["./src/meta"], - "nitropack/meta": ["./src/meta"], - // Presets - "nitro/presets": ["./src/presets"], - "nitropack/presets": ["./src/presets"], - "nitro/presets/*": ["./src/presets/*"], - "nitropack/presets/*": ["./src/presets/*"], - // Rollup - "nitro/rollup": ["./src/rollup"], - "nitropack/rollup": ["./src/rollup"], - // Types - "nitro/types": ["./src/types"], - "nitropack/types": ["./src/types"], - // Virtual files - "#nitro-internal-virtual/*": ["./src/types/virtual/*"], - // Compatibility (#internal/nitro) - "#internal/nitro": ["./src/runtime"], - "#internal/nitro/*": ["./src/runtime/*"] - } + "types": ["node", "@cloudflare/workers-types"] }, - "include": ["src", "test", "scripts/gen-mirror.ts"], - "exclude": ["dist", "examples", "playground", "test/fixture"] + "exclude": [ + "examples/import-alias/**", + "examples/vite-rsc/**", + "test/fixture/server/routes/jsx.tsx", + "examples/vite-ssr-html/vite.config.ts", + "examples/vite-ssr-solid/src/entry-server.tsx", + "examples/vite-ssr-solid/src/entry-client.tsx" + ] } diff --git a/vitest.config.ts b/vitest.config.ts index 31d8d62acb..6683af6817 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,10 +1,13 @@ import { defineConfig } from "vitest/config"; +process.env.NODE_ENV = "production"; + export default defineConfig({ test: { testTimeout: 30_000, coverage: { reporter: ["text", "clover", "json"], + include: ["src/**/*.ts", "!src/types/**/*.ts"], }, include: ["test/**/*.test.ts"], },