From 00cb2ec88b51bfde163b1b1f266c29f59f72d911 Mon Sep 17 00:00:00 2001 From: cemalturkcan Date: Wed, 25 Mar 2026 09:04:42 +0300 Subject: [PATCH 01/26] feat: add static site generation (SSG) package Add @geajs/ssg package for build-time static HTML generation with: - Vite plugin integration (build, dev, preview modes) - Markdown content system via ssg.content() and ssg.file() - Dynamic routes from content files or explicit paths - Layout and outlet support for nested page structures - Active link detection for static HTML output - Sitemap generation - Path traversal protection and XSS-safe content injection Core changes: - Guard browser APIs in component-manager for Node compatibility - Add resetUidCounter for deterministic SSG rendering - Add SSG rendering hooks to RouterView, Outlet, and Link - Support SSG route configs in resolve.ts - Add Component._ssgMode to skip reactive hooks during SSG Includes ssg-basic example with blog, dynamic routes, and markdown content. 61 SSG tests, 377 core tests passing. --- .gitignore | 2 + docs/SUMMARY.md | 1 + docs/tooling/ssg.md | 231 ++ examples/ssg-basic/README.md | 3 + examples/ssg-basic/index.html | 18 + examples/ssg-basic/package-lock.json | 1502 +++++++++ examples/ssg-basic/package.json | 20 + examples/ssg-basic/src/App.tsx | 33 + .../content/blog/getting-started-with-gea.md | 40 + .../content/blog/reactive-stores-deep-dive.md | 53 + .../src/content/blog/understanding-ssg.md | 49 + .../ssg-basic/src/content/changelog/v1.1.md | 9 + .../ssg-basic/src/content/changelog/v1.md | 9 + examples/ssg-basic/src/main.ts | 8 + examples/ssg-basic/src/styles.css | 192 ++ examples/ssg-basic/src/views/About.tsx | 56 + examples/ssg-basic/src/views/Blog.tsx | 30 + examples/ssg-basic/src/views/BlogPost.tsx | 32 + examples/ssg-basic/src/views/Contact.tsx | 24 + examples/ssg-basic/src/views/Home.tsx | 27 + examples/ssg-basic/tsconfig.json | 5 + examples/ssg-basic/vite.config.ts | 21 + package-lock.json | 2700 ++++++----------- packages/gea-ssg/README.md | 168 + packages/gea-ssg/package.json | 71 + packages/gea-ssg/src/client.ts | 30 + packages/gea-ssg/src/content.ts | 93 + packages/gea-ssg/src/crawl.ts | 138 + packages/gea-ssg/src/generate.ts | 190 ++ packages/gea-ssg/src/index.ts | 24 + packages/gea-ssg/src/render.ts | 37 + packages/gea-ssg/src/shell.ts | 54 + packages/gea-ssg/src/types.ts | 53 + packages/gea-ssg/src/vite-plugin.ts | 164 + packages/gea-ssg/tests/content.test.ts | 186 ++ packages/gea-ssg/tests/crawl.test.ts | 169 ++ packages/gea-ssg/tests/generate.test.ts | 393 +++ packages/gea-ssg/tests/render.test.ts | 87 + packages/gea-ssg/tests/shell.test.ts | 74 + packages/gea-ssg/tsconfig.json | 17 + packages/gea/src/index.ts | 4 +- .../gea/src/lib/base/component-manager.ts | 4 + packages/gea/src/lib/base/component.tsx | 10 +- packages/gea/src/lib/base/uid.ts | 4 + packages/gea/src/lib/router/index.ts | 2 + packages/gea/src/lib/router/link.ts | 16 +- packages/gea/src/lib/router/outlet.ts | 4 + packages/gea/src/lib/router/resolve.ts | 11 + packages/gea/src/lib/router/router-view.ts | 46 +- 49 files changed, 5332 insertions(+), 1782 deletions(-) create mode 100644 docs/tooling/ssg.md create mode 100644 examples/ssg-basic/README.md create mode 100644 examples/ssg-basic/index.html create mode 100644 examples/ssg-basic/package-lock.json create mode 100644 examples/ssg-basic/package.json create mode 100644 examples/ssg-basic/src/App.tsx create mode 100644 examples/ssg-basic/src/content/blog/getting-started-with-gea.md create mode 100644 examples/ssg-basic/src/content/blog/reactive-stores-deep-dive.md create mode 100644 examples/ssg-basic/src/content/blog/understanding-ssg.md create mode 100644 examples/ssg-basic/src/content/changelog/v1.1.md create mode 100644 examples/ssg-basic/src/content/changelog/v1.md create mode 100644 examples/ssg-basic/src/main.ts create mode 100644 examples/ssg-basic/src/styles.css create mode 100644 examples/ssg-basic/src/views/About.tsx create mode 100644 examples/ssg-basic/src/views/Blog.tsx create mode 100644 examples/ssg-basic/src/views/BlogPost.tsx create mode 100644 examples/ssg-basic/src/views/Contact.tsx create mode 100644 examples/ssg-basic/src/views/Home.tsx create mode 100644 examples/ssg-basic/tsconfig.json create mode 100644 examples/ssg-basic/vite.config.ts create mode 100644 packages/gea-ssg/README.md create mode 100644 packages/gea-ssg/package.json create mode 100644 packages/gea-ssg/src/client.ts create mode 100644 packages/gea-ssg/src/content.ts create mode 100644 packages/gea-ssg/src/crawl.ts create mode 100644 packages/gea-ssg/src/generate.ts create mode 100644 packages/gea-ssg/src/index.ts create mode 100644 packages/gea-ssg/src/render.ts create mode 100644 packages/gea-ssg/src/shell.ts create mode 100644 packages/gea-ssg/src/types.ts create mode 100644 packages/gea-ssg/src/vite-plugin.ts create mode 100644 packages/gea-ssg/tests/content.test.ts create mode 100644 packages/gea-ssg/tests/crawl.test.ts create mode 100644 packages/gea-ssg/tests/generate.test.ts create mode 100644 packages/gea-ssg/tests/render.test.ts create mode 100644 packages/gea-ssg/tests/shell.test.ts create mode 100644 packages/gea-ssg/tsconfig.json diff --git a/.gitignore b/.gitignore index 94afd5b..1691332 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ docs/.vitepress/cache docs/public/gea-ui-showcase website/docs .worktrees +.idea +.data \ No newline at end of file diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 6edcecf..fc00b67 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -46,6 +46,7 @@ ## Tooling - [Vite Plugin](tooling/vite-plugin.md) +- [Static Site Generation](tooling/ssg.md) - [create-gea](tooling/create-gea.md) - [VS Code Extension](tooling/vscode-extension.md) diff --git a/docs/tooling/ssg.md b/docs/tooling/ssg.md new file mode 100644 index 0000000..75770fe --- /dev/null +++ b/docs/tooling/ssg.md @@ -0,0 +1,231 @@ +# Static Site Generation + +`@geajs/ssg` pre-renders your Gea application to static HTML at build time. Every route becomes an `index.html` file with zero client JavaScript — instant loads, full SEO, and no runtime overhead. + +## Installation + +```bash +npm install -D @geajs/ssg +``` + +Requires `@geajs/core` ^1.0.0 and `vite` ^8.0.0 as peer dependencies. + +## Setup + +Add `geaSSG()` to your Vite config after `geaPlugin()`: + +```ts +// vite.config.ts +import { defineConfig } from 'vite' +import { geaPlugin } from '@geajs/vite-plugin' +import { geaSSG } from '@geajs/ssg/vite' + +export default defineConfig({ + plugins: [ + geaPlugin(), + geaSSG({ + contentDir: 'src/content', + sitemap: { hostname: 'https://example.com' }, + }), + ], +}) +``` + +Your `src/App.tsx` must export a `routes` object and `App` (or a default export): + +```tsx +import { Component, RouterView, Link } from '@geajs/core' + +export const routes = { + '/': Home, + '/about': About, + '/blog': Blog, + '/blog/:slug': { component: BlogPost, content: 'blog' }, +} + +export default class App extends Component { + template() { + return ( +
+ + +
+ ) + } +} +``` + +Running `vite build` renders every route to `dist/`: + +``` +dist/ +├── index.html (/) +├── about/index.html (/about) +├── blog/ +│ ├── index.html (/blog) +│ ├── hello/index.html +│ └── world/index.html +└── sitemap.xml +``` + +## Markdown Content + +The `ssg` accessor reads markdown files with YAML frontmatter from a content directory: + +```tsx +import { ssg } from '@geajs/ssg' + +class Blog extends Component { + posts = ssg.content<{ title: string; date: string }>('blog', { + sort: (a, b) => new Date(b.frontmatter.date).getTime() - new Date(a.frontmatter.date).getTime(), + }) + + template() { + return ( + + ) + } +} +``` + +Each returned file has: + +- `slug` — filename without extension +- `frontmatter` — parsed YAML metadata +- `content` — raw markdown +- `html` — rendered HTML + +A typical markdown file: + +```markdown +--- +title: Hello World +date: 2026-01-15 +excerpt: Getting started with Gea SSG. +--- + +# Hello World + +This is the body content. It supports **bold**, `code`, and [links](https://example.com). +``` + +### Single File Lookup + +Use `ssg.file()` to look up a single content file by slug: + +```tsx +class BlogPost extends Component { + template(props) { + const post = ssg.file('blog', props?.slug) + if (!post) return '
Not found
' + return ( +
+

{post.frontmatter.title}

+
{post.html}
+
+ ) + } +} +``` + +## Dynamic Routes + +### Content-Based Routes + +Parameterized routes can auto-generate pages from content files. Each `.md` file's slug becomes a route parameter: + +```tsx +export const routes = { + '/blog/:slug': { component: BlogPost, content: 'blog' }, +} +``` + +With three files in `src/content/blog/` (`hello.md`, `world.md`, `intro.md`), this generates three pages: `/blog/hello`, `/blog/world`, `/blog/intro`. + +### Explicit Paths + +For non-content parameterized routes, provide explicit paths: + +```tsx +export const routes = { + '/user/:id': { + component: UserPage, + paths: [{ params: { id: '1' } }, { params: { id: '2' } }], + }, +} +``` + +## Layouts + +Route groups with `layout` components work automatically. The SSG renders layouts wrapping page content through `Outlet`, just like client-side rendering: + +```tsx +export const routes = { + '/': Home, + '/docs': { + layout: DocsLayout, + children: { + '/getting-started': GettingStarted, + '/api': ApiReference, + }, + }, +} +``` + +## Active Links + +`Link` components get `data-active` attributes in static output matching the current route. Style them with CSS: + +```css +[data-active] { + font-weight: bold; + color: var(--accent); +} +``` + +## Dev Mode + +In development (`vite dev`), content is preloaded and injected into the page so `ssg.content()` and `ssg.file()` work without a build step. Content file changes trigger automatic page reload. + +## Sitemap + +Pass a `sitemap` option to generate `sitemap.xml`: + +```ts +geaSSG({ + sitemap: { + hostname: 'https://example.com', + changefreq: 'weekly', + priority: 0.8, + exclude: ['/404'], + }, +}) +``` + +## Plugin Options + +| Option | Type | Default | Description | +| --- | --- | --- | --- | +| `contentDir` | `string` | — | Markdown content directory (relative to project root) | +| `sitemap` | `boolean \| SitemapOptions` | — | Generate sitemap.xml | +| `appElementId` | `string` | `'app'` | Mount element id in index.html | +| `routes` | `RouteMap` | — | Override routes (default: loaded from `src/App.tsx`) | +| `app` | `Component` | — | Override app component (default: loaded from `src/App.tsx`) | +| `concurrency` | `number` | `4` | Max concurrent page renders | +| `onBeforeRender` | `function` | — | Hook before each page render | +| `onAfterRender` | `function` | — | Hook after render, can transform HTML | +| `onRenderError` | `function` | — | Custom error handler per route | + +## Programmatic API + +All functions are available from the main entry point for custom build pipelines: + +```ts +import { ssg, generate, renderToString, crawlRoutes, parseShell, preloadContent } from '@geajs/ssg' +``` diff --git a/examples/ssg-basic/README.md b/examples/ssg-basic/README.md new file mode 100644 index 0000000..a9e91fe --- /dev/null +++ b/examples/ssg-basic/README.md @@ -0,0 +1,3 @@ +# SSG Basic + +Static site generation example with Gea. Demonstrates `@geajs/ssg` with static routes, parameterized routes using `getStaticPaths`, markdown content loading via `loadContent`, layout support, active link highlighting, and sitemap generation — all pre-rendered to static HTML with zero client JavaScript. diff --git a/examples/ssg-basic/index.html b/examples/ssg-basic/index.html new file mode 100644 index 0000000..d833cd3 --- /dev/null +++ b/examples/ssg-basic/index.html @@ -0,0 +1,18 @@ + + + + + SSG Basic - Gea + + + + + + +
+ + + diff --git a/examples/ssg-basic/package-lock.json b/examples/ssg-basic/package-lock.json new file mode 100644 index 0000000..51322e8 --- /dev/null +++ b/examples/ssg-basic/package-lock.json @@ -0,0 +1,1502 @@ +{ + "name": "ssg-basic-gea", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ssg-basic-gea", + "version": "1.0.0", + "dependencies": { + "@geajs/core": "file:../../packages/gea" + }, + "devDependencies": { + "@geajs/ssg": "file:../../packages/gea-ssg", + "@geajs/vite-plugin": "file:../../packages/vite-plugin-gea", + "tsx": "^4.21.0", + "typescript": "~5.8.0", + "vite": "^8.0.0" + } + }, + "../../packages/gea": { + "name": "@geajs/core", + "version": "1.0.4", + "license": "MIT", + "devDependencies": { + "@types/node": "^25.5.0", + "c8": "^11.0.0", + "jsdom": "^29.0.0", + "quill": "^2.0.3", + "tsdown": "^0.21.2", + "tsx": "^4.21.0", + "typescript": "~5.8.0" + } + }, + "../../packages/gea-ssg": { + "name": "@geajs/ssg", + "version": "1.0.0", + "dev": true, + "license": "MIT", + "devDependencies": { + "tsup": "^8.5.1", + "tsx": "^4.21.0", + "typescript": "~5.8.0" + }, + "peerDependencies": { + "@geajs/core": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "../../packages/vite-plugin-gea": { + "name": "@geajs/vite-plugin", + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@acemir/cssom": "^0.9.31", + "@babel/generator": "^7.23.0", + "@babel/parser": "^7.23.0", + "@babel/traverse": "^7.23.0", + "@babel/types": "^7.23.0", + "eszter": "^0.3.0" + }, + "devDependencies": { + "@codemirror/commands": "^6.10.3", + "@codemirror/lang-javascript": "^6.2.5", + "@codemirror/language": "^6.12.2", + "@codemirror/state": "^6.6.0", + "@codemirror/view": "^6.40.0", + "@lezer/highlight": "^1.2.3", + "@rollup/plugin-commonjs": "^29.0.2", + "@rollup/plugin-json": "^6.1.0", + "@rollup/plugin-node-resolve": "^16.0.3", + "@types/node": "^25.4.0", + "c8": "^11.0.0", + "cssstyle": "^6.2.0", + "jsdom": "^28.1.0", + "rollup": "^4.60.0", + "rollup-plugin-esbuild": "^6.2.1", + "tsup": "^8.5.1", + "tsx": "^4.21.0", + "typescript": "^5.9.3" + }, + "peerDependencies": { + "vite": "^8.0.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.1.tgz", + "integrity": "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.1.tgz", + "integrity": "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz", + "integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz", + "integrity": "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.4.tgz", + "integrity": "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.4.tgz", + "integrity": "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.4.tgz", + "integrity": "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz", + "integrity": "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.4.tgz", + "integrity": "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.4.tgz", + "integrity": "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.4.tgz", + "integrity": "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.4.tgz", + "integrity": "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.4.tgz", + "integrity": "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.4.tgz", + "integrity": "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.4.tgz", + "integrity": "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.4.tgz", + "integrity": "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.4.tgz", + "integrity": "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.4.tgz", + "integrity": "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.4.tgz", + "integrity": "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz", + "integrity": "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.4.tgz", + "integrity": "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.4.tgz", + "integrity": "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.4.tgz", + "integrity": "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.4.tgz", + "integrity": "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.4.tgz", + "integrity": "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.4.tgz", + "integrity": "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.4.tgz", + "integrity": "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.4.tgz", + "integrity": "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.4.tgz", + "integrity": "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@geajs/core": { + "resolved": "../../packages/gea", + "link": true + }, + "node_modules/@geajs/ssg": { + "resolved": "../../packages/gea-ssg", + "link": true + }, + "node_modules/@geajs/vite-plugin": { + "resolved": "../../packages/vite-plugin-gea", + "link": true + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz", + "integrity": "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.122.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.122.0.tgz", + "integrity": "sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.11.tgz", + "integrity": "sha512-SJ+/g+xNnOh6NqYxD0V3uVN4W3VfnrGsC9/hoglicgTNfABFG9JjISvkkU0dNY84MNHLWyOgxP9v9Y9pX4S7+A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.11.tgz", + "integrity": "sha512-7WQgR8SfOPwmDZGFkThUvsmd/nwAWv91oCO4I5LS7RKrssPZmOt7jONN0cW17ydGC1n/+puol1IpoieKqQidmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.11.tgz", + "integrity": "sha512-39Ks6UvIHq4rEogIfQBoBRusj0Q0nPVWIvqmwBLaT6aqQGIakHdESBVOPRRLacy4WwUPIx4ZKzfZ9PMW+IeyUQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.11.tgz", + "integrity": "sha512-jfsm0ZHfhiqrvWjJAmzsqiIFPz5e7mAoCOPBNTcNgkiid/LaFKiq92+0ojH+nmJmKYkre4t71BWXUZDNp7vsag==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.11.tgz", + "integrity": "sha512-zjQaUtSyq1nVe3nxmlSCuR96T1LPlpvmJ0SZy0WJFEsV4kFbXcq2u68L4E6O0XeFj4aex9bEauqjW8UQBeAvfQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.11.tgz", + "integrity": "sha512-WMW1yE6IOnehTcFE9eipFkm3XN63zypWlrJQ2iF7NrQ9b2LDRjumFoOGJE8RJJTJCTBAdmLMnJ8uVitACUUo1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.11.tgz", + "integrity": "sha512-jfndI9tsfm4APzjNt6QdBkYwre5lRPUgHeDHoI7ydKUuJvz3lZeCfMsI56BZj+7BYqiKsJm7cfd/6KYV7ubrBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.11.tgz", + "integrity": "sha512-ZlFgw46NOAGMgcdvdYwAGu2Q+SLFA9LzbJLW+iyMOJyhj5wk6P3KEE9Gct4xWwSzFoPI7JCdYmYMzVtlgQ+zfw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.11.tgz", + "integrity": "sha512-hIOYmuT6ofM4K04XAZd3OzMySEO4K0/nc9+jmNcxNAxRi6c5UWpqfw3KMFV4MVFWL+jQsSh+bGw2VqmaPMTLyw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.11.tgz", + "integrity": "sha512-qXBQQO9OvkjjQPLdUVr7Nr2t3QTZI7s4KZtfw7HzBgjbmAPSFwSv4rmET9lLSgq3rH/ndA3ngv3Qb8l2njoPNA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.11.tgz", + "integrity": "sha512-/tpFfoSTzUkH9LPY+cYbqZBDyyX62w5fICq9qzsHLL8uTI6BHip3Q9Uzft0wylk/i8OOwKik8OxW+QAhDmzwmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.11.tgz", + "integrity": "sha512-mcp3Rio2w72IvdZG0oQ4bM2c2oumtwHfUfKncUM6zGgz0KgPz4YmDPQfnXEiY5t3+KD/i8HG2rOB/LxdmieK2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.11.tgz", + "integrity": "sha512-LXk5Hii1Ph9asuGRjBuz8TUxdc1lWzB7nyfdoRgI0WGPZKmCxvlKk8KfYysqtr4MfGElu/f/pEQRh8fcEgkrWw==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.1.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.11.tgz", + "integrity": "sha512-dDwf5otnx0XgRY1yqxOC4ITizcdzS/8cQ3goOWv3jFAo4F+xQYni+hnMuO6+LssHHdJW7+OCVL3CoU4ycnh35Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.11.tgz", + "integrity": "sha512-LN4/skhSggybX71ews7dAj6r2geaMJfm3kMbK2KhFMg9B10AZXnKoLCVVgzhMHL0S+aKtr4p8QbAW8k+w95bAA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.11.tgz", + "integrity": "sha512-xQO9vbwBecJRv9EUcQ/y0dzSTJgA7Q6UVN7xp6B81+tBGSLVAK03yJ9NkJaUA7JFD91kbjxRSC/mDnmvXzbHoQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/esbuild": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz", + "integrity": "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "peer": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@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" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.7", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.7.tgz", + "integrity": "sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "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" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/rolldown": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.11.tgz", + "integrity": "sha512-NRjoKMusSjfRbSYiH3VSumlkgFe7kYAa3pzVOsVYVFY3zb5d7nS+a3KGQ7hJKXuYWbzJKPVQ9Wxq2UvyK+ENpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.122.0", + "@rolldown/pluginutils": "1.0.0-rc.11" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-rc.11", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.11", + "@rolldown/binding-darwin-x64": "1.0.0-rc.11", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.11", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.11", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.11", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.11", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.11", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.11", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.11", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.11", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.11", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.11", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.11", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.11" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/vite": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.2.tgz", + "integrity": "sha512-1gFhNi+bHhRE/qKZOJXACm6tX4bA3Isy9KuKF15AgSRuRazNBOJfdDemPBU16/mpMxApDPrWvZ08DcLPEoRnuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.8", + "rolldown": "1.0.0-rc.11", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.0", + "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 + } + } + } + } +} diff --git a/examples/ssg-basic/package.json b/examples/ssg-basic/package.json new file mode 100644 index 0000000..f824760 --- /dev/null +++ b/examples/ssg-basic/package.json @@ -0,0 +1,20 @@ +{ + "name": "ssg-basic-gea", + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "@geajs/core": "file:../../packages/gea" + }, + "devDependencies": { + "vite": "^8.0.0", + "@geajs/vite-plugin": "file:../../packages/vite-plugin-gea", + "@geajs/ssg": "file:../../packages/gea-ssg", + "typescript": "~5.8.0", + "tsx": "^4.21.0" + } +} diff --git a/examples/ssg-basic/src/App.tsx b/examples/ssg-basic/src/App.tsx new file mode 100644 index 0000000..15e24d3 --- /dev/null +++ b/examples/ssg-basic/src/App.tsx @@ -0,0 +1,33 @@ +import { Component } from '@geajs/core' +import { Link, RouterView } from '@geajs/core' +import Home from './views/Home' +import About from './views/About' +import Contact from './views/Contact' +import Blog from './views/Blog' +import BlogPost from './views/BlogPost' + +export const routes = { + '/': Home, + '/about': About, + '/contact': Contact, + '/blog': Blog, + '/blog/:slug': { component: BlogPost, content: 'blog' }, +} + +export default class App extends Component { + template() { + return ( +
+ +
+ +
+
+ ) + } +} diff --git a/examples/ssg-basic/src/content/blog/getting-started-with-gea.md b/examples/ssg-basic/src/content/blog/getting-started-with-gea.md new file mode 100644 index 0000000..752652f --- /dev/null +++ b/examples/ssg-basic/src/content/blog/getting-started-with-gea.md @@ -0,0 +1,40 @@ +--- +title: Getting Started with Gea +date: 2025-03-15 +excerpt: Learn how to build reactive UIs with Gea — a compile-time JSX framework with no virtual DOM. +--- + +Gea is a lightweight reactive UI framework that compiles JSX at build time and uses proxy-based stores for surgical DOM updates. At **~13kb gzipped**, it delivers a fast, minimal footprint without a virtual DOM. + +## Installation + +```bash +npm create gea@latest my-app +``` + +## Your First Component + +Components in Gea are class-based with a `template()` method that returns JSX: + +```tsx +import { Component } from '@geajs/core' + +export default class Hello extends Component { + template() { + return

Hello, Gea!

+ } +} +``` + +## Reactive Stores + +Stores use JavaScript `Proxy` under the hood. When you mutate a property, only the DOM nodes that depend on it get updated — no diffing, no reconciliation: + +```tsx +import { Store } from '@geajs/core' + +const counter = new Store({ count: 0 }) +counter.count++ // only the bound DOM node updates +``` + +Start building with `npm run dev` and enjoy instant HMR powered by Vite. diff --git a/examples/ssg-basic/src/content/blog/reactive-stores-deep-dive.md b/examples/ssg-basic/src/content/blog/reactive-stores-deep-dive.md new file mode 100644 index 0000000..a7606d1 --- /dev/null +++ b/examples/ssg-basic/src/content/blog/reactive-stores-deep-dive.md @@ -0,0 +1,53 @@ +--- +title: Reactive Stores Deep Dive +date: 2025-03-05 +excerpt: How Gea's proxy-based stores track changes and trigger surgical DOM updates. +--- + +Gea stores use JavaScript `Proxy` to intercept property access and mutations. When a store property changes, only the DOM nodes that depend on that specific property are updated. + +## The Proxy Pattern + +Every `Store` instance wraps its data in a `Proxy`: + +```tsx +import { Store } from '@geajs/core' + +class AppState extends Store { + count = 0 + name = 'World' +} + +const state = new AppState() +``` + +When you access `state.count` inside a `template()`, Gea records the dependency. When `state.count` changes, only that specific binding updates. + +## No Virtual DOM + +Unlike React or Vue, Gea doesn't diff a virtual tree. The compile-time JSX transform generates direct DOM update instructions: + +- **React**: render → diff → patch +- **Gea**: store change → update bound node + +This means updates are `O(1)` per changed property, not `O(n)` where n is the tree size. + +## Nested Objects + +Stores support deep reactivity. Nested objects and arrays are automatically wrapped in proxies: + +```tsx +class TodoStore extends Store { + todos = [ + { text: 'Learn Gea', done: false }, + { text: 'Build an app', done: false }, + ] +} + +const store = new TodoStore() +store.todos[0].done = true // triggers update +``` + +## Observer Pattern + +Under the hood, each property maintains an observer tree. Components subscribe during rendering and unsubscribe on disposal — no memory leaks. diff --git a/examples/ssg-basic/src/content/blog/understanding-ssg.md b/examples/ssg-basic/src/content/blog/understanding-ssg.md new file mode 100644 index 0000000..83e8935 --- /dev/null +++ b/examples/ssg-basic/src/content/blog/understanding-ssg.md @@ -0,0 +1,49 @@ +--- +title: Understanding Static Site Generation +date: 2025-03-10 +excerpt: What SSG means, why it matters, and how @geajs/ssg pre-renders your routes at build time. +--- + +Static Site Generation (SSG) pre-renders your pages at build time into **plain HTML files**. This means zero JavaScript is needed for initial content display, giving you instant loads and perfect SEO. + +## How It Works + +The `@geajs/ssg` package does three things at build time: + +1. **Crawls** your route map to discover all pages +2. **Renders** each component via `Component.template()` +3. **Writes** the output HTML to disk + +## Dynamic Routes + +For parameterized routes like `/blog/:slug`, you define a static `getStaticPaths()` method: + +```tsx +export default class BlogPost extends Component { + static getStaticPaths() { + return posts.map(p => ({ + params: { slug: p.slug }, + props: { title: p.title, html: p.html }, + })) + } +} +``` + +## Markdown Support + +You can also write content in Markdown files with frontmatter: + +```md +--- +title: My Post +date: 2025-03-10 +--- + +Content goes here with **bold**, *italic*, and `code`. +``` + +Load them with `loadContent()` and pass the rendered HTML as props. + +## The Result + +Each page becomes a standalone `.html` file — no client JS, no loading spinners. Just instant content. diff --git a/examples/ssg-basic/src/content/changelog/v1.1.md b/examples/ssg-basic/src/content/changelog/v1.1.md new file mode 100644 index 0000000..08663e4 --- /dev/null +++ b/examples/ssg-basic/src/content/changelog/v1.1.md @@ -0,0 +1,9 @@ +--- +version: 1.1.0 +date: 2025-03-15 +--- + +- Dynamic route support with `getStaticPaths()` +- Layout and outlet rendering +- `getStaticProps()` for static routes +- `Link` active state in SSG output diff --git a/examples/ssg-basic/src/content/changelog/v1.md b/examples/ssg-basic/src/content/changelog/v1.md new file mode 100644 index 0000000..ac9c325 --- /dev/null +++ b/examples/ssg-basic/src/content/changelog/v1.md @@ -0,0 +1,9 @@ +--- +version: 1.0.0 +date: 2025-03-01 +--- + +- Initial release of `@geajs/ssg` +- Static page generation from route map +- Markdown content loading with frontmatter +- Sitemap generation diff --git a/examples/ssg-basic/src/main.ts b/examples/ssg-basic/src/main.ts new file mode 100644 index 0000000..ad05e69 --- /dev/null +++ b/examples/ssg-basic/src/main.ts @@ -0,0 +1,8 @@ +import App from './App' +import './styles.css' + +const root = document.getElementById('app') +if (!root) throw new Error('App root element not found') + +const app = new App() +app.render(root) diff --git a/examples/ssg-basic/src/styles.css b/examples/ssg-basic/src/styles.css new file mode 100644 index 0000000..604762b --- /dev/null +++ b/examples/ssg-basic/src/styles.css @@ -0,0 +1,192 @@ +:root { + --bg-dark: #0f1419; + --bg-card: #1a2332; + --accent: #00d4aa; + --accent-dim: rgba(0, 212, 170, 0.15); + --text: #e7edf4; + --text-muted: #8b9cad; + --border: #2d3a4d; +} + +* { + box-sizing: border-box; +} + +body { + margin: 0; + padding: 0; + font-family: 'DM Sans', system-ui, sans-serif; + background: var(--bg-dark); + color: var(--text); + min-height: 100vh; +} + +#app { + max-width: 640px; + margin: 0 auto; + padding: 24px 20px; +} + +.nav { + display: flex; + gap: 8px; + padding-bottom: 20px; + margin-bottom: 24px; + border-bottom: 1px solid var(--border); + flex-wrap: wrap; +} + +.nav-link { + padding: 10px 18px; + border: 2px solid var(--border); + border-radius: 8px; + background: transparent; + color: var(--text-muted); + font-size: 0.9rem; + font-weight: 500; + text-decoration: none; +} + +.nav-link:hover, +.nav-link[data-active] { + border-color: var(--accent); + color: var(--accent); +} + +.content { + min-height: 300px; +} + +.view h1 { + font-size: 1.5rem; + font-weight: 600; + margin: 0 0 16px 0; +} + +.view p { + color: var(--text-muted); + line-height: 1.6; + margin: 0 0 12px 0; +} + +.view code { + font-family: 'JetBrains Mono', monospace; + font-size: 0.85em; + background: var(--bg-card); + padding: 2px 6px; + border-radius: 4px; + border: 1px solid var(--border); +} + +.feature-list { + list-style: none; + padding: 0; + margin: 0 0 16px 0; +} + +.feature-list li { + padding: 10px 16px; + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: 8px; + margin-bottom: 8px; + color: var(--text-muted); + line-height: 1.5; +} + +.feature-list li strong { + color: var(--accent); +} + +.card { + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: 8px; + padding: 20px; + margin-bottom: 12px; +} + +.card h2 { + font-size: 1.1rem; + font-weight: 600; + margin: 0 0 8px 0; +} + +.card p { + margin: 0; +} + +.badge { + display: inline-block; + padding: 4px 12px; + border-radius: 20px; + background: var(--accent-dim); + color: var(--accent); + font-size: 0.85rem; + font-weight: 500; + margin-bottom: 16px; +} + +.post-list { + display: flex; + flex-direction: column; + gap: 12px; +} + +.post-card { + display: block; + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: 8px; + padding: 20px; + text-decoration: none; + color: inherit; + transition: border-color 0.15s; +} + +.post-card:hover { + border-color: var(--accent); +} + +.post-card time { + display: block; + color: var(--text-muted); + font-size: 0.8rem; + margin-bottom: 6px; +} + +.post-card h2 { + font-size: 1.1rem; + font-weight: 600; + margin: 0 0 6px 0; + color: var(--text); +} + +.post-card p { + margin: 0; + font-size: 0.9rem; +} + +.back-link { + display: inline-block; + color: var(--accent); + text-decoration: none; + font-size: 0.9rem; + margin-bottom: 16px; +} + +.back-link:hover { + text-decoration: underline; +} + +.post time { + display: block; + color: var(--text-muted); + font-size: 0.85rem; + margin-bottom: 8px; +} + +.post-body { + color: var(--text-muted); + line-height: 1.7; +} diff --git a/examples/ssg-basic/src/views/About.tsx b/examples/ssg-basic/src/views/About.tsx new file mode 100644 index 0000000..baaa3de --- /dev/null +++ b/examples/ssg-basic/src/views/About.tsx @@ -0,0 +1,56 @@ +import { Component } from '@geajs/core' +import { ssg } from '@geajs/ssg' + +const features = [ + { name: 'Compile-time JSX', description: 'No runtime template parsing — JSX is compiled at build time' }, + { name: 'Proxy-based Stores', description: 'Surgical DOM updates without virtual DOM diffing' }, + { name: 'Tiny Footprint', description: '~13kb gzipped — minimal overhead for maximum performance' }, + { name: 'SSG Support', description: 'Pre-render pages at build time for instant loads' }, +] + +export default class About extends Component { + template() { + const changelog = ssg.content('changelog', { + sort: (a, b) => new Date(b.frontmatter.date).getTime() - new Date(a.frontmatter.date).getTime(), + }) + + return ( +
+

About

+

+ Gea is a lightweight reactive UI framework that compiles JSX at build time and uses proxy-based stores for + surgical DOM updates — all without a virtual DOM. +

+ +

Features

+
+ {features + .map( + (f) => ` +
+

${f.name}

+

${f.description}

+
+ `, + ) + .join('')} +
+ +

Changelog

+ {changelog + .map( + (c) => ` +
+
+ v${c.frontmatter.version} + +
+
${c.html}
+
+ `, + ) + .join('')} +
+ ) + } +} diff --git a/examples/ssg-basic/src/views/Blog.tsx b/examples/ssg-basic/src/views/Blog.tsx new file mode 100644 index 0000000..1a62d4c --- /dev/null +++ b/examples/ssg-basic/src/views/Blog.tsx @@ -0,0 +1,30 @@ +import { Component } from '@geajs/core' +import { ssg } from '@geajs/ssg' + +export default class Blog extends Component { + template() { + const posts = ssg.content('blog', { + sort: (a, b) => new Date(b.frontmatter.date).getTime() - new Date(a.frontmatter.date).getTime(), + }) + + return ( +
+

Blog

+

Articles about Gea and modern web development.

+
+ {posts + .map( + (post) => ` + + +

${post.frontmatter.title}

+

${post.frontmatter.excerpt}

+
+ `, + ) + .join('')} +
+
+ ) + } +} diff --git a/examples/ssg-basic/src/views/BlogPost.tsx b/examples/ssg-basic/src/views/BlogPost.tsx new file mode 100644 index 0000000..082c603 --- /dev/null +++ b/examples/ssg-basic/src/views/BlogPost.tsx @@ -0,0 +1,32 @@ +import { Component } from '@geajs/core' +import { ssg } from '@geajs/ssg' + +export default class BlogPost extends Component { + template(props: any) { + const post = ssg.file('blog', props?.slug) + + if (!post) { + return ( +
+

Post not found

+ + ← Back to blog + +
+ ) + } + + return ( +
+ + ← Back to blog + +
+ +

{post.frontmatter.title}

+
{post.html}
+
+
+ ) + } +} diff --git a/examples/ssg-basic/src/views/Contact.tsx b/examples/ssg-basic/src/views/Contact.tsx new file mode 100644 index 0000000..ae54ed8 --- /dev/null +++ b/examples/ssg-basic/src/views/Contact.tsx @@ -0,0 +1,24 @@ +import { Component } from '@geajs/core' + +export default class Contact extends Component { + template() { + return ( +
+

Contact

+

Get in touch with us through the channels below.

+ +
+

Email

+

hello@geajs.dev

+
+
+ ) + } +} diff --git a/examples/ssg-basic/src/views/Home.tsx b/examples/ssg-basic/src/views/Home.tsx new file mode 100644 index 0000000..aa28ac5 --- /dev/null +++ b/examples/ssg-basic/src/views/Home.tsx @@ -0,0 +1,27 @@ +import { Component } from '@geajs/core' + +export default class Home extends Component { + template() { + return ( +
+ Static Site Generation +

Welcome to Gea SSG

+

+ This page was statically generated at build time. No JavaScript is required to display this content — it is + served as pure HTML. +

+ +
+ ) + } +} diff --git a/examples/ssg-basic/tsconfig.json b/examples/ssg-basic/tsconfig.json new file mode 100644 index 0000000..43c1fc3 --- /dev/null +++ b/examples/ssg-basic/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../packages/gea/tsconfig.json", + "include": ["**/*.ts", "**/*.tsx", "**/*.d.ts", "../../packages/vite-plugin-gea/gea-env.d.ts"], + "exclude": ["dist", "node_modules"] +} diff --git a/examples/ssg-basic/vite.config.ts b/examples/ssg-basic/vite.config.ts new file mode 100644 index 0000000..4766aec --- /dev/null +++ b/examples/ssg-basic/vite.config.ts @@ -0,0 +1,21 @@ +import { resolve } from 'node:path' +import { defineConfig } from 'vite' +import { geaPlugin } from '@geajs/vite-plugin' +import { geaSSG } from '@geajs/ssg/vite' + +export default defineConfig({ + plugins: [ + geaPlugin(), + ...geaSSG({ + contentDir: 'src/content', + sitemap: { + hostname: 'https://gea-ssg-example.com', + }, + }), + ], + resolve: { + alias: { + '@geajs/core': resolve(__dirname, '../../packages/gea/src'), + }, + }, +}) diff --git a/package-lock.json b/package-lock.json index 51c5eb5..7cdca05 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,8 +18,7 @@ "globals": "^17.4.0", "prettier": "^3.8.1", "typescript-eslint": "^8.57.0", - "vitepress": "^1.6.4", - "vitepress-plugin-llms": "^1.12.0" + "vitepress": "^1.6.4" } }, "node_modules/@acemir/cssom": { @@ -317,9 +316,9 @@ } }, "node_modules/@asamuzakjp/dom-selector": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-7.0.4.tgz", - "integrity": "sha512-jXR6x4AcT3eIrS2fSNAwJpwirOkGcd+E7F7CP3zjdTqz9B/2huHOL8YJZBgekKwLML+u7qB/6P1LXQuMScsx0w==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-7.0.3.tgz", + "integrity": "sha512-Q6mU0Z6bfj6YvnX2k9n0JxiIwrCFN59x/nWmYQnAqP000ruX/yV+5bp/GRcF5T8ncvfwJQ7fgfP74DlpKExILA==", "dev": true, "license": "MIT", "dependencies": { @@ -830,9 +829,9 @@ } }, "node_modules/@codemirror/language": { - "version": "6.12.3", - "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.12.3.tgz", - "integrity": "sha512-QwCZW6Tt1siP37Jet9Tb02Zs81TQt6qQrZR2H+eGMcFsL1zMrk2/b9CLC7/9ieP1fjIUMgviLWMmgiHoJrj+ZA==", + "version": "6.12.2", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.12.2.tgz", + "integrity": "sha512-jEPmz2nGGDxhRTg3lTpzmIyGKxz3Gp3SJES4b0nAuE5SWQoKdT5GoQ69cwMmFd+wvFUhYirtDTr0/DRHpQAyWg==", "dev": true, "license": "MIT", "dependencies": { @@ -1108,7 +1107,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1125,7 +1123,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1142,7 +1139,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1159,7 +1155,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1176,7 +1171,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1193,7 +1187,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1210,7 +1203,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1227,7 +1219,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1244,7 +1235,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1261,7 +1251,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1278,7 +1267,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1295,7 +1283,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1312,7 +1299,6 @@ "cpu": [ "mips64el" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1329,7 +1315,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1346,7 +1331,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1363,7 +1347,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1380,7 +1363,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1397,7 +1379,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1414,7 +1395,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1431,7 +1411,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1448,7 +1427,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1465,7 +1443,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1482,7 +1459,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1499,7 +1475,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1516,7 +1491,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1533,7 +1507,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1722,8 +1695,8 @@ "resolved": "packages/gea-mobile", "link": true }, - "node_modules/@geajs/ssr": { - "resolved": "packages/gea-ssr", + "node_modules/@geajs/ssg": { + "resolved": "packages/gea-ssg", "link": true }, "node_modules/@geajs/ui": { @@ -1787,9 +1760,9 @@ } }, "node_modules/@iconify-json/simple-icons": { - "version": "1.2.75", - "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.75.tgz", - "integrity": "sha512-KvcCUbvcBWb0sbqLIxHoY8z5/piXY08wcY9gfMhF+ph3AfzGMaSmZFkUY71HSXAljQngXkgs4bdKdekO0HQWvg==", + "version": "1.2.74", + "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.74.tgz", + "integrity": "sha512-yqaohfY6jnYjTVpuTkaBQHrWbdUrQyWXhau0r/0EZiNWYXPX/P8WWwl1DoLH5CbvDjjcWQw5J0zADhgCUklOqA==", "dev": true, "license": "CC0-1.0", "dependencies": { @@ -2052,10 +2025,11 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.122.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.122.0.tgz", - "integrity": "sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==", + "version": "0.120.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.120.0.tgz", + "integrity": "sha512-k1YNu55DuvAip/MGE1FTsIuU3FUCn6v/ujG9V7Nq5Df/kX2CWb13hhwD0lmJGMGqE+bE1MXvv9SZVnMzEXlWcg==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/Boshen" } @@ -2107,9 +2081,9 @@ "license": "MIT" }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.12.tgz", - "integrity": "sha512-pv1y2Fv0JybcykuiiD3qBOBdz6RteYojRFY1d+b95WVuzx211CRh+ytI/+9iVyWQ6koTh5dawe4S/yRfOFjgaA==", + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.10.tgz", + "integrity": "sha512-jOHxwXhxmFKuXztiu1ORieJeTbx5vrTkcOkkkn2d35726+iwhrY1w/+nYY/AGgF12thg33qC3R1LMBF5tHTZHg==", "cpu": [ "arm64" ], @@ -2124,9 +2098,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.12.tgz", - "integrity": "sha512-cFYr6zTG/3PXXF3pUO+umXxt1wkRK/0AYT8lDwuqvRC+LuKYWSAQAQZjCWDQpAH172ZV6ieYrNnFzVVcnSflAg==", + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.10.tgz", + "integrity": "sha512-gED05Teg/vtTZbIJBc4VNMAxAFDUPkuO/rAIyyxZjTj1a1/s6z5TII/5yMGZ0uLRCifEtwUQn8OlYzuYc0m70w==", "cpu": [ "arm64" ], @@ -2141,9 +2115,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.12.tgz", - "integrity": "sha512-ZCsYknnHzeXYps0lGBz8JrF37GpE9bFVefrlmDrAQhOEi4IOIlcoU1+FwHEtyXGx2VkYAvhu7dyBf75EJQffBw==", + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.10.tgz", + "integrity": "sha512-rI15NcM1mA48lqrIxVkHfAqcyFLcQwyXWThy+BQ5+mkKKPvSO26ir+ZDp36AgYoYVkqvMcdS8zOE6SeBsR9e8A==", "cpu": [ "x64" ], @@ -2158,9 +2132,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.12.tgz", - "integrity": "sha512-dMLeprcVsyJsKolRXyoTH3NL6qtsT0Y2xeuEA8WQJquWFXkEC4bcu1rLZZSnZRMtAqwtrF/Ib9Ddtpa/Gkge9Q==", + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.10.tgz", + "integrity": "sha512-XZRXHdTa+4ME1MuDVp021+doQ+z6Ei4CCFmNc5/sKbqb8YmkiJdj8QKlV3rCI0AJtAeSB5n0WGPuJWNL9p/L2w==", "cpu": [ "x64" ], @@ -2175,9 +2149,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.12.tgz", - "integrity": "sha512-YqWjAgGC/9M1lz3GR1r1rP79nMgo3mQiiA+Hfo+pvKFK1fAJ1bCi0ZQVh8noOqNacuY1qIcfyVfP6HoyBRZ85Q==", + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.10.tgz", + "integrity": "sha512-R0SQMRluISSLzFE20sPWYHVmJdDQnRyc/FzSCN72BqQmh2SOZUFG+N3/vBZpR4C6WpEUVYJLrYUXaj43sJsNLA==", "cpu": [ "arm" ], @@ -2192,9 +2166,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.12.tgz", - "integrity": "sha512-/I5AS4cIroLpslsmzXfwbe5OmWvSsrFuEw3mwvbQ1kDxJ822hFHIx+vsN/TAzNVyepI/j/GSzrtCIwQPeKCLIg==", + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.10.tgz", + "integrity": "sha512-Y1reMrV/o+cwpduYhJuOE3OMKx32RMYCidf14y+HssARRmhDuWXJ4yVguDg2R/8SyyGNo+auzz64LnPK9Hq6jg==", "cpu": [ "arm64" ], @@ -2209,9 +2183,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.12.tgz", - "integrity": "sha512-V6/wZztnBqlx5hJQqNWwFdxIKN0m38p8Jas+VoSfgH54HSj9tKTt1dZvG6JRHcjh6D7TvrJPWFGaY9UBVOaWPw==", + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.10.tgz", + "integrity": "sha512-vELN+HNb2IzuzSBUOD4NHmP9yrGwl1DVM29wlQvx1OLSclL0NgVWnVDKl/8tEks79EFek/kebQKnNJkIAA4W2g==", "cpu": [ "arm64" ], @@ -2226,9 +2200,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.12.tgz", - "integrity": "sha512-AP3E9BpcUYliZCxa3w5Kwj9OtEVDYK6sVoUzy4vTOJsjPOgdaJZKFmN4oOlX0Wp0RPV2ETfmIra9x1xuayFB7g==", + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.10.tgz", + "integrity": "sha512-ZqrufYTgzxbHwpqOjzSsb0UV/aV2TFIY5rP8HdsiPTv/CuAgCRjM6s9cYFwQ4CNH+hf9Y4erHW1GjZuZ7WoI7w==", "cpu": [ "ppc64" ], @@ -2243,9 +2217,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.12.tgz", - "integrity": "sha512-nWwpvUSPkoFmZo0kQazZYOrT7J5DGOJ/+QHHzjvNlooDZED8oH82Yg67HvehPPLAg5fUff7TfWFHQS8IV1n3og==", + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.10.tgz", + "integrity": "sha512-gSlmVS1FZJSRicA6IyjoRoKAFK7IIHBs7xJuHRSmjImqk3mPPWbR7RhbnfH2G6bcmMEllCt2vQ/7u9e6bBnByg==", "cpu": [ "s390x" ], @@ -2260,9 +2234,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.12.tgz", - "integrity": "sha512-RNrafz5bcwRy+O9e6P8Z/OCAJW/A+qtBczIqVYwTs14pf4iV1/+eKEjdOUta93q2TsT/FI0XYDP3TCky38LMAg==", + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.10.tgz", + "integrity": "sha512-eOCKUpluKgfObT2pHjztnaWEIbUabWzk3qPZ5PuacuPmr4+JtQG4k2vGTY0H15edaTnicgU428XW/IH6AimcQw==", "cpu": [ "x64" ], @@ -2277,9 +2251,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.12.tgz", - "integrity": "sha512-Jpw/0iwoKWx3LJ2rc1yjFrj+T7iHZn2JDg1Yny1ma0luviFS4mhAIcd1LFNxK3EYu3DHWCps0ydXQ5i/rrJ2ig==", + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.10.tgz", + "integrity": "sha512-Xdf2jQbfQowJnLcgYfD/m0Uu0Qj5OdxKallD78/IPPfzaiaI4KRAwZzHcKQ4ig1gtg1SuzC7jovNiM2TzQsBXA==", "cpu": [ "x64" ], @@ -2294,9 +2268,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.12.tgz", - "integrity": "sha512-vRugONE4yMfVn0+7lUKdKvN4D5YusEiPilaoO2sgUWpCvrncvWgPMzK00ZFFJuiPgLwgFNP5eSiUlv2tfc+lpA==", + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.10.tgz", + "integrity": "sha512-o1hYe8hLi1EY6jgPFyxQgQ1wcycX+qz8eEbVmot2hFkgUzPxy9+kF0u0NIQBeDq+Mko47AkaFFaChcvZa9UX9Q==", "cpu": [ "arm64" ], @@ -2311,9 +2285,9 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.12.tgz", - "integrity": "sha512-ykGiLr/6kkiHc0XnBfmFJuCjr5ZYKKofkx+chJWDjitX+KsJuAmrzWhwyOMSHzPhzOHOy7u9HlFoa5MoAOJ/Zg==", + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.10.tgz", + "integrity": "sha512-Ugv9o7qYJudqQO5Y5y2N2SOo6S4WiqiNOpuQyoPInnhVzCY+wi/GHltcLHypG9DEUYMB0iTB/huJrpadiAcNcA==", "cpu": [ "wasm32" ], @@ -2328,9 +2302,9 @@ } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.12.tgz", - "integrity": "sha512-5eOND4duWkwx1AzCxadcOrNeighiLwMInEADT0YM7xeEOOFcovWZCq8dadXgcRHSf3Ulh1kFo/qvzoFiCLOL1Q==", + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.10.tgz", + "integrity": "sha512-7UODQb4fQUNT/vmgDZBl3XOBAIOutP5R3O/rkxg0aLfEGQ4opbCgU5vOw/scPe4xOqBwL9fw7/RP1vAMZ6QlAQ==", "cpu": [ "arm64" ], @@ -2345,9 +2319,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.12.tgz", - "integrity": "sha512-PyqoipaswDLAZtot351MLhrlrh6lcZPo2LSYE+VDxbVk24LVKAGOuE4hb8xZQmrPAuEtTZW8E6D2zc5EUZX4Lw==", + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.10.tgz", + "integrity": "sha512-PYxKHMVHOb5NJuDL53vBUl1VwUjymDcYI6rzpIni0C9+9mTiJedvUxSk7/RPp7OOAm3v+EjgMu9bIy3N6b408w==", "cpu": [ "x64" ], @@ -2362,9 +2336,9 @@ } }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.12.tgz", - "integrity": "sha512-HHMwmarRKvoFsJorqYlFeFRzXZqCt2ETQlEDOb9aqssrnVBB1/+xgTGtuTrIk5vzLNX1MjMtTf7W9z3tsSbrxw==", + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.10.tgz", + "integrity": "sha512-UkVDEFk1w3mveXeKgaTuYfKWtPbvgck1dT8TUG3bnccrH0XtLTuAyfCoks4Q/M5ZGToSVJTIQYCzy2g/atAOeg==", "license": "MIT", "peer": true }, @@ -2395,6 +2369,37 @@ } } }, + "node_modules/@rollup/plugin-commonjs/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/@rollup/plugin-json": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", @@ -2464,6 +2469,19 @@ } } }, + "node_modules/@rollup/pluginutils/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.60.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.0.tgz", @@ -2920,16 +2938,6 @@ "tslib": "^2.4.0" } }, - "node_modules/@types/debug": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", - "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/ms": "*" - } - }, "node_modules/@types/esrecurse": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", @@ -3010,13 +3018,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/ms": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/node": { "version": "25.5.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz", @@ -3056,17 +3057,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.57.2.tgz", - "integrity": "sha512-NZZgp0Fm2IkD+La5PR81sd+g+8oS6JwJje+aRWsDocxHkjyRw0J5L5ZTlN3LI1LlOcGL7ph3eaIUmTXMIjLk0w==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.57.1.tgz", + "integrity": "sha512-Gn3aqnvNl4NGc6x3/Bqk1AOn0thyTU9bqDRhiRnUWezgvr2OnhYCWCgC8zXXRVqBsIL1pSDt7T9nJUe0oM0kDQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.57.2", - "@typescript-eslint/type-utils": "8.57.2", - "@typescript-eslint/utils": "8.57.2", - "@typescript-eslint/visitor-keys": "8.57.2", + "@typescript-eslint/scope-manager": "8.57.1", + "@typescript-eslint/type-utils": "8.57.1", + "@typescript-eslint/utils": "8.57.1", + "@typescript-eslint/visitor-keys": "8.57.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" @@ -3079,7 +3080,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.57.2", + "@typescript-eslint/parser": "^8.57.1", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } @@ -3095,16 +3096,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.57.2.tgz", - "integrity": "sha512-30ScMRHIAD33JJQkgfGW1t8CURZtjc2JpTrq5n2HFhOefbAhb7ucc7xJwdWcrEtqUIYJ73Nybpsggii6GtAHjA==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.57.1.tgz", + "integrity": "sha512-k4eNDan0EIMTT/dUKc/g+rsJ6wcHYhNPdY19VoX/EOtaAG8DLtKCykhrUnuHPYvinn5jhAPgD2Qw9hXBwrahsw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.57.2", - "@typescript-eslint/types": "8.57.2", - "@typescript-eslint/typescript-estree": "8.57.2", - "@typescript-eslint/visitor-keys": "8.57.2", + "@typescript-eslint/scope-manager": "8.57.1", + "@typescript-eslint/types": "8.57.1", + "@typescript-eslint/typescript-estree": "8.57.1", + "@typescript-eslint/visitor-keys": "8.57.1", "debug": "^4.4.3" }, "engines": { @@ -3120,14 +3121,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.57.2.tgz", - "integrity": "sha512-FuH0wipFywXRTHf+bTTjNyuNQQsQC3qh/dYzaM4I4W0jrCqjCVuUh99+xd9KamUfmCGPvbO8NDngo/vsnNVqgw==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.57.1.tgz", + "integrity": "sha512-vx1F37BRO1OftsYlmG9xay1TqnjNVlqALymwWVuYTdo18XuKxtBpCj1QlzNIEHlvlB27osvXFWptYiEWsVdYsg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.57.2", - "@typescript-eslint/types": "^8.57.2", + "@typescript-eslint/tsconfig-utils": "^8.57.1", + "@typescript-eslint/types": "^8.57.1", "debug": "^4.4.3" }, "engines": { @@ -3142,14 +3143,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.57.2.tgz", - "integrity": "sha512-snZKH+W4WbWkrBqj4gUNRIGb/jipDW3qMqVJ4C9rzdFc+wLwruxk+2a5D+uoFcKPAqyqEnSb4l2ULuZf95eSkw==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.57.1.tgz", + "integrity": "sha512-hs/QcpCwlwT2L5S+3fT6gp0PabyGk4Q0Rv2doJXA0435/OpnSR3VRgvrp8Xdoc3UAYSg9cyUjTeFXZEPg/3OKg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.57.2", - "@typescript-eslint/visitor-keys": "8.57.2" + "@typescript-eslint/types": "8.57.1", + "@typescript-eslint/visitor-keys": "8.57.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3160,9 +3161,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.57.2.tgz", - "integrity": "sha512-3Lm5DSM+DCowsUOJC+YqHHnKEfFh5CoGkj5Z31NQSNF4l5wdOwqGn99wmwN/LImhfY3KJnmordBq/4+VDe2eKw==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.57.1.tgz", + "integrity": "sha512-0lgOZB8cl19fHO4eI46YUx2EceQqhgkPSuCGLlGi79L2jwYY1cxeYc1Nae8Aw1xjgW3PKVDLlr3YJ6Bxx8HkWg==", "dev": true, "license": "MIT", "engines": { @@ -3177,15 +3178,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.57.2.tgz", - "integrity": "sha512-Co6ZCShm6kIbAM/s+oYVpKFfW7LBc6FXoPXjTRQ449PPNBY8U0KZXuevz5IFuuUj2H9ss40atTaf9dlGLzbWZg==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.57.1.tgz", + "integrity": "sha512-+Bwwm0ScukFdyoJsh2u6pp4S9ktegF98pYUU0hkphOOqdMB+1sNQhIz8y5E9+4pOioZijrkfNO/HUJVAFFfPKA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.57.2", - "@typescript-eslint/typescript-estree": "8.57.2", - "@typescript-eslint/utils": "8.57.2", + "@typescript-eslint/types": "8.57.1", + "@typescript-eslint/typescript-estree": "8.57.1", + "@typescript-eslint/utils": "8.57.1", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, @@ -3202,9 +3203,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.2.tgz", - "integrity": "sha512-/iZM6FnM4tnx9csuTxspMW4BOSegshwX5oBDznJ7S4WggL7Vczz5d2W11ecc4vRrQMQHXRSxzrCsyG5EsPPTbA==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.1.tgz", + "integrity": "sha512-S29BOBPJSFUiblEl6RzPPjJt6w25A6XsBqRVDt53tA/tlL8q7ceQNZHTjPeONt/3S7KRI4quk+yP9jK2WjBiPQ==", "dev": true, "license": "MIT", "engines": { @@ -3216,16 +3217,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.57.2.tgz", - "integrity": "sha512-2MKM+I6g8tJxfSmFKOnHv2t8Sk3T6rF20A1Puk0svLK+uVapDZB/4pfAeB7nE83uAZrU6OxW+HmOd5wHVdXwXA==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.57.1.tgz", + "integrity": "sha512-ybe2hS9G6pXpqGtPli9Gx9quNV0TWLOmh58ADlmZe9DguLq0tiAKVjirSbtM1szG6+QH6rVXyU6GTLQbWnMY+g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.57.2", - "@typescript-eslint/tsconfig-utils": "8.57.2", - "@typescript-eslint/types": "8.57.2", - "@typescript-eslint/visitor-keys": "8.57.2", + "@typescript-eslint/project-service": "8.57.1", + "@typescript-eslint/tsconfig-utils": "8.57.1", + "@typescript-eslint/types": "8.57.1", + "@typescript-eslint/visitor-keys": "8.57.1", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -3244,16 +3245,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.57.2.tgz", - "integrity": "sha512-krRIbvPK1ju1WBKIefiX+bngPs+odIQUtR7kymzPfo1POVw3jlF+nLkmexdSSd4UCbDcQn+wMBATOOmpBbqgKg==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.57.1.tgz", + "integrity": "sha512-XUNSJ/lEVFttPMMoDVA2r2bwrl8/oPx8cURtczkSEswY5T3AeLmCy+EKWQNdL4u0MmAHOjcWrqJp2cdvgjn8dQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.57.2", - "@typescript-eslint/types": "8.57.2", - "@typescript-eslint/typescript-estree": "8.57.2" + "@typescript-eslint/scope-manager": "8.57.1", + "@typescript-eslint/types": "8.57.1", + "@typescript-eslint/typescript-estree": "8.57.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3268,13 +3269,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.57.2.tgz", - "integrity": "sha512-zhahknjobV2FiD6Ee9iLbS7OV9zi10rG26odsQdfBO/hjSzUQbkIYgda+iNKK1zNiW2ey+Lf8MU5btN17V3dUw==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.57.1.tgz", + "integrity": "sha512-YWnmJkXbofiz9KbnbbwuA2rpGkFPLbAIetcCNO6mJ8gdhdZ/v7WDXsoGFAJuM6ikUFKTlSQnjWnVO4ux+UzS6A==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.57.2", + "@typescript-eslint/types": "8.57.1", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -3293,14 +3294,14 @@ "license": "ISC" }, "node_modules/@vue/compiler-core": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.31.tgz", - "integrity": "sha512-k/ueL14aNIEy5Onf0OVzR8kiqF/WThgLdFhxwa4e/KF/0qe38IwIdofoSWBTvvxQOesaz6riAFAUaYjoF9fLLQ==", + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.30.tgz", + "integrity": "sha512-s3DfdZkcu/qExZ+td75015ljzHc6vE+30cFMGRPROYjqkroYI5NV2X1yAMX9UeyBNWB9MxCfPcsjpLS11nzkkw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.2", - "@vue/shared": "3.5.31", + "@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" @@ -3320,28 +3321,28 @@ } }, "node_modules/@vue/compiler-dom": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.31.tgz", - "integrity": "sha512-BMY/ozS/xxjYqRFL+tKdRpATJYDTTgWSo0+AJvJNg4ig+Hgb0dOsHPXvloHQ5hmlivUqw1Yt2pPIqp4e0v1GUw==", + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.30.tgz", + "integrity": "sha512-eCFYESUEVYHhiMuK4SQTldO3RYxyMR/UQL4KdGD1Yrkfdx4m/HYuZ9jSfPdA+nWJY34VWndiYdW/wZXyiPEB9g==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.31", - "@vue/shared": "3.5.31" + "@vue/compiler-core": "3.5.30", + "@vue/shared": "3.5.30" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.31.tgz", - "integrity": "sha512-M8wpPgR9UJ8MiRGjppvx9uWJfLV7A/T+/rL8s/y3QG3u0c2/YZgff3d6SuimKRIhcYnWg5fTfDMlz2E6seUW8Q==", + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.30.tgz", + "integrity": "sha512-LqmFPDn89dtU9vI3wHJnwaV6GfTRD87AjWpTWpyrdVOObVtjIuSeZr181z5C4PmVx/V3j2p+0f7edFKGRMpQ5A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.2", - "@vue/compiler-core": "3.5.31", - "@vue/compiler-dom": "3.5.31", - "@vue/compiler-ssr": "3.5.31", - "@vue/shared": "3.5.31", + "@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", @@ -3349,14 +3350,14 @@ } }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.31.tgz", - "integrity": "sha512-h0xIMxrt/LHOvJKMri+vdYT92BrK3HFLtDqq9Pr/lVVfE4IyKZKvWf0vJFW10Yr6nX02OR4MkJwI0c1HDa1hog==", + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.30.tgz", + "integrity": "sha512-NsYK6OMTnx109PSL2IAyf62JP6EUdk4Dmj6AkWcJGBvN0dQoMYtVekAmdqgTtWQgEJo+Okstbf/1p7qZr5H+bA==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.31", - "@vue/shared": "3.5.31" + "@vue/compiler-dom": "3.5.30", + "@vue/shared": "3.5.30" } }, "node_modules/@vue/devtools-api": { @@ -3396,57 +3397,57 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.31.tgz", - "integrity": "sha512-DtKXxk9E/KuVvt8VxWu+6Luc9I9ETNcqR1T1oW1gf02nXaZ1kuAx58oVu7uX9XxJR0iJCro6fqBLw9oSBELo5g==", + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.30.tgz", + "integrity": "sha512-179YNgKATuwj9gB+66snskRDOitDiuOZqkYia7mHKJaidOMo/WJxHKF8DuGc4V4XbYTJANlfEKb0yxTQotnx4Q==", "dev": true, "license": "MIT", "dependencies": { - "@vue/shared": "3.5.31" + "@vue/shared": "3.5.30" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.31.tgz", - "integrity": "sha512-AZPmIHXEAyhpkmN7aWlqjSfYynmkWlluDNPHMCZKFHH+lLtxP/30UJmoVhXmbDoP1Ng0jG0fyY2zCj1PnSSA6Q==", + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.30.tgz", + "integrity": "sha512-e0Z+8PQsUTdwV8TtEsLzUM7SzC7lQwYKePydb7K2ZnmS6jjND+WJXkmmfh/swYzRyfP1EY3fpdesyYoymCzYfg==", "dev": true, "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.31", - "@vue/shared": "3.5.31" + "@vue/reactivity": "3.5.30", + "@vue/shared": "3.5.30" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.31.tgz", - "integrity": "sha512-xQJsNRmGPeDCJq/u813tyonNgWBFjzfVkBwDREdEWndBnGdHLHgkwNBQxLtg4zDrzKTEcnikUy1UUNecb3lJ6g==", + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.30.tgz", + "integrity": "sha512-2UIGakjU4WSQ0T4iwDEW0W7vQj6n7AFn7taqZ9Cvm0Q/RA2FFOziLESrDL4GmtI1wV3jXg5nMoJSYO66egDUBw==", "dev": true, "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.31", - "@vue/runtime-core": "3.5.31", - "@vue/shared": "3.5.31", + "@vue/reactivity": "3.5.30", + "@vue/runtime-core": "3.5.30", + "@vue/shared": "3.5.30", "csstype": "^3.2.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.31.tgz", - "integrity": "sha512-GJuwRvMcdZX/CriUnyIIOGkx3rMV3H6sOu0JhdKbduaeCji6zb60iOGMY7tFoN24NfsUYoFBhshZtGxGpxO4iA==", + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.30.tgz", + "integrity": "sha512-v+R34icapydRwbZRD0sXwtHqrQJv38JuMB4JxbOxd8NEpGLny7cncMp53W9UH/zo4j8eDHjQ1dEJXwzFQknjtQ==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.31", - "@vue/shared": "3.5.31" + "@vue/compiler-ssr": "3.5.30", + "@vue/shared": "3.5.30" }, "peerDependencies": { - "vue": "3.5.31" + "vue": "3.5.30" } }, "node_modules/@vue/shared": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.31.tgz", - "integrity": "sha512-nBxuiuS9Lj5bPkPbWogPUnjxxWpkRniX7e5UBQDWl6Fsf4roq9wwV+cR7ezQ4zXswNvPIlsdj1slcLB7XCsRAw==", + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.30.tgz", + "integrity": "sha512-YXgQ7JjaO18NeK2K9VTbDHaFy62WrObMa6XERNfNOkAhD1F1oDSf3ZJ7K6GqabZ0BvSDHajp8qfS5Sa2I9n8uQ==", "dev": true, "license": "MIT" }, @@ -3557,555 +3558,555 @@ } }, "node_modules/@zag-js/accordion": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/accordion/-/accordion-1.38.2.tgz", - "integrity": "sha512-lr3K8R4c8cY1ghcU4lpav4dAXCFqFcNOrieqy4lsS5n5CSrpLbL1EFrOdTBux/CCeijmipFp14ddUZGHWHIDJQ==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/accordion/-/accordion-1.38.0.tgz", + "integrity": "sha512-EtMzxUQ3fXQKCMb5K8JAmEe9qsl5S/G5vlhLzr8Im9ODnR1OLYpSNjMYYk1hoH57igpB7BPuseqfSafoT0/i/w==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "1.38.2", - "@zag-js/core": "1.38.2", - "@zag-js/dom-query": "1.38.2", - "@zag-js/types": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/anatomy": "1.38.0", + "@zag-js/core": "1.38.0", + "@zag-js/dom-query": "1.38.0", + "@zag-js/types": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/anatomy": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/anatomy/-/anatomy-1.38.2.tgz", - "integrity": "sha512-3wEwuHkHiErD1r36MrC1Jd4lqvQK+wQ5EgqdEk8r3L2koD7fTdq8CB5KbMcP0JM08eFCOo2CBl3gP3VBmiTNJA==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/anatomy/-/anatomy-1.38.0.tgz", + "integrity": "sha512-wmlwq2gvDd72O5W0WJizrjuo6rCuFW9H8d3guGWqTxLTVpdqV25JHkp35Qf5AnceJ9564d72+VolBZYMnjJCyQ==", "license": "MIT" }, "node_modules/@zag-js/aria-hidden": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/aria-hidden/-/aria-hidden-1.38.2.tgz", - "integrity": "sha512-TvMdHUouslt6RZmKZ6k41B1KTqjOFaD4T6c4sTb6qSUkuTYgyYsA7ZqimiR0vcvmmG852nSaOepvr6Jj0sRPNA==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/aria-hidden/-/aria-hidden-1.38.0.tgz", + "integrity": "sha512-kiBXFexhxEebcOPmF6h5/F7oRy1U04EEj8JzsUywMijACb5ZYIeCUWOFfi0s+IvuY6KptAL4zb27MZAIxzVLIw==", "license": "MIT", "dependencies": { - "@zag-js/dom-query": "1.38.2" + "@zag-js/dom-query": "1.38.0" } }, "node_modules/@zag-js/auto-resize": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/auto-resize/-/auto-resize-1.38.2.tgz", - "integrity": "sha512-0nVYusVmxDfa1j8fyycQCxcULT07BUM+23BlEslPy0Hfzt5c7CwMQFan4JiMia82RzgnWv3s+5svVMvI++ZZqw==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/auto-resize/-/auto-resize-1.38.0.tgz", + "integrity": "sha512-R60LDs2lH0x3hZoXhGtWpl+i5zA1BgPJgFj37eYraZjuIkTVL+p10w2oqXBmldG0PArP8bfxz4bbeszO2obYLQ==", "license": "MIT", "dependencies": { - "@zag-js/dom-query": "1.38.2" + "@zag-js/dom-query": "1.38.0" } }, "node_modules/@zag-js/avatar": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/avatar/-/avatar-1.38.2.tgz", - "integrity": "sha512-DmhoaJG+IcKFSWSrtfcI91WJNSJQx2PYDmChnOtNvyGIXibNHkoYXzvZTCrKsVGgKeUXFtOxSqSYMbzxgL2k2Q==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/avatar/-/avatar-1.38.0.tgz", + "integrity": "sha512-1sugDuVbmmk5+fSckBbw3oRXtyy6uVGKWk4SV1NE2IkWIkKP7aCWTlNY/QHLnfgxi9HfTLNvQgkFt6PdQ80Y1Q==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "1.38.2", - "@zag-js/core": "1.38.2", - "@zag-js/dom-query": "1.38.2", - "@zag-js/types": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/anatomy": "1.38.0", + "@zag-js/core": "1.38.0", + "@zag-js/dom-query": "1.38.0", + "@zag-js/types": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/checkbox": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/checkbox/-/checkbox-1.38.2.tgz", - "integrity": "sha512-AAljBvGog/jLWhdEFc2ADzsGODoGua8fWZs0RUYq/wQ9UBiG4w5VRyPAq5ZEzaIoSruoHm5AHN9D9VdWN9py3g==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/checkbox/-/checkbox-1.38.0.tgz", + "integrity": "sha512-0sVE4ZCbFu5lG1hF/b/dMYWZszDC/Rj5+YhQuOcsYCWemxcdxIuugIoQSYLsNZ0nSHMrgRwGrfyLDmNSUc3QOQ==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "1.38.2", - "@zag-js/core": "1.38.2", - "@zag-js/dom-query": "1.38.2", - "@zag-js/focus-visible": "1.38.2", - "@zag-js/types": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/anatomy": "1.38.0", + "@zag-js/core": "1.38.0", + "@zag-js/dom-query": "1.38.0", + "@zag-js/focus-visible": "1.38.0", + "@zag-js/types": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/clipboard": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/clipboard/-/clipboard-1.38.2.tgz", - "integrity": "sha512-LIDcuZDU70cvMAbIz7LgeXM+CvhRW8Ez84UPkorwT+EyDCOaCNEADabSY2AM4WKn81EV56UKkwSNblkhP3gmZA==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/clipboard/-/clipboard-1.38.0.tgz", + "integrity": "sha512-G3bHENAFqjbrC/Um8hYOvy2GQH0NzDvkOdDVgkKTWh5cRhw3hgEnfOKYWmfH4uHT/hcdak4wsu7KAUtbcixTNQ==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "1.38.2", - "@zag-js/core": "1.38.2", - "@zag-js/dom-query": "1.38.2", - "@zag-js/types": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/anatomy": "1.38.0", + "@zag-js/core": "1.38.0", + "@zag-js/dom-query": "1.38.0", + "@zag-js/types": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/collapsible": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/collapsible/-/collapsible-1.38.2.tgz", - "integrity": "sha512-7yBlX/9d/A7Da/9PZoBye0nA+FjVZv7rjrUfmO2NhoERt2IV6r0S143DrwcW3ELjz+76HzV+wlP8ytruqaK1gQ==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/collapsible/-/collapsible-1.38.0.tgz", + "integrity": "sha512-cMSQ9ZOgBgTTXlsIOHgWfvb4BvRHNTanP9v+PKBdi0F3pbYv85ogLdMbzIKQ9X5T/dYGSkDzxpNq0K+uQKWHqA==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "1.38.2", - "@zag-js/core": "1.38.2", - "@zag-js/dom-query": "1.38.2", - "@zag-js/types": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/anatomy": "1.38.0", + "@zag-js/core": "1.38.0", + "@zag-js/dom-query": "1.38.0", + "@zag-js/types": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/collection": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/collection/-/collection-1.38.2.tgz", - "integrity": "sha512-1Edek5yrjHfpmciK4M5PoUbDFRgEEkFh3HMIwWjMRdcRzea9ibVhSGXvXsenafC/b3so/ApEXBhs1ch7dFn+NQ==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/collection/-/collection-1.38.0.tgz", + "integrity": "sha512-vhVzbotw4SyWHh1d5tzj3PGcg7gG6mokts5Bi2AZTU+qfnHUFCRZ6J4LoRDKYBtr5pZ1v0FyqdYYD1EL5VnYAg==", "license": "MIT", "dependencies": { - "@zag-js/utils": "1.38.2" + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/combobox": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/combobox/-/combobox-1.38.2.tgz", - "integrity": "sha512-J2M1vB3Keepv2Wr/sC5kue18ver+nf/7gj9LgHxSU5sgwl9Fr4wZLPH1s9ZQ7FDhBXjWsitILbf9dqR1UpyLJQ==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/combobox/-/combobox-1.38.0.tgz", + "integrity": "sha512-51QsgVyD1iL4ChIyr2+chP6yjTY63PlRLr3d5P9B6YUA0A7shKZgbQtxbez98P9a9bGPWid9ilw4h6oKOr/pag==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "1.38.2", - "@zag-js/aria-hidden": "1.38.2", - "@zag-js/collection": "1.38.2", - "@zag-js/core": "1.38.2", - "@zag-js/dismissable": "1.38.2", - "@zag-js/dom-query": "1.38.2", - "@zag-js/focus-visible": "1.38.2", - "@zag-js/popper": "1.38.2", - "@zag-js/types": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/anatomy": "1.38.0", + "@zag-js/aria-hidden": "1.38.0", + "@zag-js/collection": "1.38.0", + "@zag-js/core": "1.38.0", + "@zag-js/dismissable": "1.38.0", + "@zag-js/dom-query": "1.38.0", + "@zag-js/focus-visible": "1.38.0", + "@zag-js/popper": "1.38.0", + "@zag-js/types": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/core": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/core/-/core-1.38.2.tgz", - "integrity": "sha512-UaRU6TVOJV07phQkToR6fNceJbfPiNLx2itSh78ofHn8w9w860mNrS5tyn8HExuNwY5JVQdfMkyFlMF0LfgVLQ==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/core/-/core-1.38.0.tgz", + "integrity": "sha512-YsVQILNw/smzdf9Oelg88PTGXL+n5ZNXOJGg3Szpk5yWiNx6FCddHpNJsNfCT4r+PguLZz7I0YPUtgz+pkdIpQ==", "license": "MIT", "dependencies": { - "@zag-js/dom-query": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/dom-query": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/dialog": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/dialog/-/dialog-1.38.2.tgz", - "integrity": "sha512-cVYBXiEnQ30UjudJxODoV8Au/18VyePEvJ9SollGFJYnr+/2mCue5CoraOQJqoZVED3tdUCBodz9kyjS1CcvAw==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/dialog/-/dialog-1.38.0.tgz", + "integrity": "sha512-LjnmHup8g4YbwLVg1C2FsgMGY5wQMSAxTOtk9wk66EEEj7BAFAxnQ74roFu8yAc8x6+zdnYYJh9Q/j2ntyO+pg==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "1.38.2", - "@zag-js/aria-hidden": "1.38.2", - "@zag-js/core": "1.38.2", - "@zag-js/dismissable": "1.38.2", - "@zag-js/dom-query": "1.38.2", - "@zag-js/focus-trap": "1.38.2", - "@zag-js/remove-scroll": "1.38.2", - "@zag-js/types": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/anatomy": "1.38.0", + "@zag-js/aria-hidden": "1.38.0", + "@zag-js/core": "1.38.0", + "@zag-js/dismissable": "1.38.0", + "@zag-js/dom-query": "1.38.0", + "@zag-js/focus-trap": "1.38.0", + "@zag-js/remove-scroll": "1.38.0", + "@zag-js/types": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/dismissable": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/dismissable/-/dismissable-1.38.2.tgz", - "integrity": "sha512-4B83ZGD8YKnwiXwL4J49txeXSPdS29bPt6p00v99u6nJPlQRRubzPUQo4OJr6NxUuT9cIn2kDqt5oj8ZCwhmng==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/dismissable/-/dismissable-1.38.0.tgz", + "integrity": "sha512-VcI555h/Gm5tm2sWrhofEvvNtwqT5CCsaJpJN9V3oPu2DKZbq6Am/etz4u4riekYNOckCkdtC+vr1+weYp47RQ==", "license": "MIT", "dependencies": { - "@zag-js/dom-query": "1.38.2", - "@zag-js/interact-outside": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/dom-query": "1.38.0", + "@zag-js/interact-outside": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/dom-query": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/dom-query/-/dom-query-1.38.2.tgz", - "integrity": "sha512-E2plmm/bDjMQhi4fmyhw2uhoQv2cgNYaG+fzLrJgepLqovCOTU85lwzaLFiB7ldG2a9DVmjbAnFX4nVVWvaxGA==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/dom-query/-/dom-query-1.38.0.tgz", + "integrity": "sha512-0c1kKEvF8xDSCH1ElSJBTBjRnstuA5VDDlc/f5/7MjLyFmw/x9GucXq5tGgOjsWXr8H22G6W3Z1wGeW+taCTLA==", "license": "MIT", "dependencies": { - "@zag-js/types": "1.38.2" + "@zag-js/types": "1.38.0" } }, "node_modules/@zag-js/file-upload": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/file-upload/-/file-upload-1.38.2.tgz", - "integrity": "sha512-sA5gKafIRDcKc6zsEYrByQQpl2am+ioRzGcuxhwBdOIacJP3G2vs4bJx0wCbdM8O9Ue11s9KBcqfJhenDlBWMg==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/file-upload/-/file-upload-1.38.0.tgz", + "integrity": "sha512-pcjuZNH5+6JmTRAW13wY707aPKHQCh7jmZGrGkfDWBWwgEmYRa6/jMBWcMe/0JuS7joaUVqPKAK0QFP+b0/2xA==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "1.38.2", - "@zag-js/core": "1.38.2", - "@zag-js/dom-query": "1.38.2", - "@zag-js/file-utils": "1.38.2", - "@zag-js/i18n-utils": "1.38.2", - "@zag-js/types": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/anatomy": "1.38.0", + "@zag-js/core": "1.38.0", + "@zag-js/dom-query": "1.38.0", + "@zag-js/file-utils": "1.38.0", + "@zag-js/i18n-utils": "1.38.0", + "@zag-js/types": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/file-utils": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/file-utils/-/file-utils-1.38.2.tgz", - "integrity": "sha512-498kXYSlUrNXdjmn0mKfovd7zQv1PnLXhNW94L0DYX7GcAqd6SQ4QohtxbT4IHrzlV9FfskKhe9ahXxV2IlNVQ==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/file-utils/-/file-utils-1.38.0.tgz", + "integrity": "sha512-8g5Nngqi3JmQvL48oxlE6iLc+hqvlFGjxTaHZkx8NGroTMOvFbl4kmJXNxOAmu8xG2Wv14cynzbXfwWWDkJGJg==", "license": "MIT", "dependencies": { - "@zag-js/i18n-utils": "1.38.2" + "@zag-js/i18n-utils": "1.38.0" } }, "node_modules/@zag-js/focus-trap": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/focus-trap/-/focus-trap-1.38.2.tgz", - "integrity": "sha512-m1CBTmUy7kHsMVBFlzOmxddxESv7ce6XOX+3YhXKWNJLvnt4a3bWMnh+C3CmV7B14pntTkQwfXJALR6e3gfS6Q==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/focus-trap/-/focus-trap-1.38.0.tgz", + "integrity": "sha512-wzR3YckysnN97fRQuoJwLHzw1rLeXbPpa0RIgqWsPMEesTTdADfxWw0faAiAgy8hsN79lvIRF3y1nT8CZDke4g==", "license": "MIT", "dependencies": { - "@zag-js/dom-query": "1.38.2" + "@zag-js/dom-query": "1.38.0" } }, "node_modules/@zag-js/focus-visible": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/focus-visible/-/focus-visible-1.38.2.tgz", - "integrity": "sha512-ME0zulSEZLxR9jJqtwDpcWuBnZKO/8xQ+UtuYrJPvqPyUyUVkxFon+jCqNUOGjK4rHB+OjEV19LrHAzq6CQjNg==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/focus-visible/-/focus-visible-1.38.0.tgz", + "integrity": "sha512-6Iabj3LxzzPvYtf4R5QTi9y1CR4d8HnqsGmafMJozQsRoLJ6ZZQAIdYHDmSvJgEOe9AY1UO+uo9ETnfHDBpkxA==", "license": "MIT", "dependencies": { - "@zag-js/dom-query": "1.38.2" + "@zag-js/dom-query": "1.38.0" } }, "node_modules/@zag-js/hover-card": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/hover-card/-/hover-card-1.38.2.tgz", - "integrity": "sha512-Un/65bC+ppCktMBd798z7x90t6/kvvqkASxezV6ds0Ex56TB26KQnaRPUASV+fW6uH4nLdBOeGlCH3cC8KEPYg==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/hover-card/-/hover-card-1.38.0.tgz", + "integrity": "sha512-MHxcuR2Y4jsSotFXIsYxhaOytl/JPoMqSSdIm194ApGomLxiWgCBNZdoZu0xHhVDD9MDP1IVObOUeyw5MBr5BQ==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "1.38.2", - "@zag-js/core": "1.38.2", - "@zag-js/dismissable": "1.38.2", - "@zag-js/dom-query": "1.38.2", - "@zag-js/popper": "1.38.2", - "@zag-js/types": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/anatomy": "1.38.0", + "@zag-js/core": "1.38.0", + "@zag-js/dismissable": "1.38.0", + "@zag-js/dom-query": "1.38.0", + "@zag-js/popper": "1.38.0", + "@zag-js/types": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/i18n-utils": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/i18n-utils/-/i18n-utils-1.38.2.tgz", - "integrity": "sha512-/thV2gwDtfubrL8gcBXGiNmQVcHACmYIXneLVW94wVADdsuRKV/s0QrMQXe/QH3f3M9QAU5VWQnoz9Z2ySilGQ==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/i18n-utils/-/i18n-utils-1.38.0.tgz", + "integrity": "sha512-ccpUWxl/Drekn3HCnCDQbkzAXX5I5AdIcIwS3RIzGCR8YGyJ/Vm2f9H+a7jFHkeeyHPNi7B73olbfV6BrVGRWQ==", "license": "MIT", "dependencies": { - "@zag-js/dom-query": "1.38.2" + "@zag-js/dom-query": "1.38.0" } }, "node_modules/@zag-js/interact-outside": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/interact-outside/-/interact-outside-1.38.2.tgz", - "integrity": "sha512-jszzVoozqcO3vn1iiZ726xYXpy/mR+fLnx1tBs4Dvkg/n52Mm3Uv+pFDBfHgswqS/kRJ/U8P0fItFJjOH0yvlA==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/interact-outside/-/interact-outside-1.38.0.tgz", + "integrity": "sha512-w0VKBfrWbY4J5Id7R+27gFzJfVtbivnmy95AhPKKtqURlj8t4hZmZyBDUZUCF5l9703ka37EYllsi/DVabIR/w==", "license": "MIT", "dependencies": { - "@zag-js/dom-query": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/dom-query": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/live-region": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/live-region/-/live-region-1.38.2.tgz", - "integrity": "sha512-6qVPHEZRPbO/BKUTGXC3otZXODpsRg/lliBHUHzK7Pg83eSW4yGQI+XKRjmJnoWvB7U5vFXDC3SXG3aO0dyLYQ==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/live-region/-/live-region-1.38.0.tgz", + "integrity": "sha512-h5ehhnF3hmlmvdZakQoqnzo3ghcabYpbOTkwOOSrPi5tL4WxvL5kIkSKnmIsGRopCY9tFHXUL5s0pxqg70Zhqg==", "license": "MIT" }, "node_modules/@zag-js/menu": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/menu/-/menu-1.38.2.tgz", - "integrity": "sha512-n0AO5uz31csUcnk1daHf/O5T2Yqtdo8KV9PInrIxwKXwfeLM2uFTHubhP2bv/j7+R+LpnZkK5laXe9WxKueBVQ==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/menu/-/menu-1.38.0.tgz", + "integrity": "sha512-VEEalJztk1rECej4YyB9vjZCCEA8YT+PJAxCbohLYH9Lz2IfbpRVYHZmyVDKcYySNnGiMWl5hadZo7Gryyf0VQ==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "1.38.2", - "@zag-js/core": "1.38.2", - "@zag-js/dismissable": "1.38.2", - "@zag-js/dom-query": "1.38.2", - "@zag-js/focus-visible": "1.38.2", - "@zag-js/popper": "1.38.2", - "@zag-js/rect-utils": "1.38.2", - "@zag-js/types": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/anatomy": "1.38.0", + "@zag-js/core": "1.38.0", + "@zag-js/dismissable": "1.38.0", + "@zag-js/dom-query": "1.38.0", + "@zag-js/focus-visible": "1.38.0", + "@zag-js/popper": "1.38.0", + "@zag-js/rect-utils": "1.38.0", + "@zag-js/types": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/number-input": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/number-input/-/number-input-1.38.2.tgz", - "integrity": "sha512-WJJA6EusT1HGDJlzW9YpbgOJ6Qv3TM1jcBNftrGCLGNhePXBzLzsTZKp+IZdjkI+11bab5siXwU9wcQWUhmUNw==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/number-input/-/number-input-1.38.0.tgz", + "integrity": "sha512-J8htY+l69Qg8oA+xflwYVWCUN7EWoQBjHE4yiwXg85DCSrUjrlrXwM/U0X+LmAa+Kzv2LZq78Yn7KmNTxpjHNA==", "license": "MIT", "dependencies": { "@internationalized/number": "3.6.5", - "@zag-js/anatomy": "1.38.2", - "@zag-js/core": "1.38.2", - "@zag-js/dom-query": "1.38.2", - "@zag-js/types": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/anatomy": "1.38.0", + "@zag-js/core": "1.38.0", + "@zag-js/dom-query": "1.38.0", + "@zag-js/types": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/pagination": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/pagination/-/pagination-1.38.2.tgz", - "integrity": "sha512-pqdR7Eek6FFK4EyVRZbxwRymvunguGVAZAHrg0Aij/CnPbZZATDk4gQbGKpIgEywSYSk6m4hurjLg8L+shkfVQ==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/pagination/-/pagination-1.38.0.tgz", + "integrity": "sha512-F6tVKQre9YaDutO5WLJFttxgEQI5kdurOybSs7YFBklLhhrpy0omz3PPiRJSo2y7zop680/1icoQrq0Pj3+KAQ==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "1.38.2", - "@zag-js/core": "1.38.2", - "@zag-js/dom-query": "1.38.2", - "@zag-js/types": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/anatomy": "1.38.0", + "@zag-js/core": "1.38.0", + "@zag-js/dom-query": "1.38.0", + "@zag-js/types": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/pin-input": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/pin-input/-/pin-input-1.38.2.tgz", - "integrity": "sha512-kMmlRTOLBqxVaBM4Ly7NZi4VbB5SJUfcmyj6pxHV+YSqzFpuS8/o24CTtbLWUg9Zh4wSuM7vnx8A0viWg92V2Q==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/pin-input/-/pin-input-1.38.0.tgz", + "integrity": "sha512-lPecBshH/0PYCRpwMKbzJl22EOiPNNPzSPpyftm1B04yX/pGhVctd8NdyP7GvNzx+CRps6QVrZvGUxc6a0n68w==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "1.38.2", - "@zag-js/core": "1.38.2", - "@zag-js/dom-query": "1.38.2", - "@zag-js/types": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/anatomy": "1.38.0", + "@zag-js/core": "1.38.0", + "@zag-js/dom-query": "1.38.0", + "@zag-js/types": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/popover": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/popover/-/popover-1.38.2.tgz", - "integrity": "sha512-LPA4Ld/eD34/C+/jsojXU/GiG9Y4rYN1xFAJIeOdUGF9fAvMVr+TEhvNUnVV7FnIbK5hdFOy7EgAAEL34uqBow==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/popover/-/popover-1.38.0.tgz", + "integrity": "sha512-wOHnwD3w/54oA3PKGERMaDo7JUQEPJ9MK00QqiEhRyJWV6ARYsyVpjEmEIbaIdcFud5TMT6nF3OyMwdvshW7Uw==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "1.38.2", - "@zag-js/aria-hidden": "1.38.2", - "@zag-js/core": "1.38.2", - "@zag-js/dismissable": "1.38.2", - "@zag-js/dom-query": "1.38.2", - "@zag-js/focus-trap": "1.38.2", - "@zag-js/popper": "1.38.2", - "@zag-js/remove-scroll": "1.38.2", - "@zag-js/types": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/anatomy": "1.38.0", + "@zag-js/aria-hidden": "1.38.0", + "@zag-js/core": "1.38.0", + "@zag-js/dismissable": "1.38.0", + "@zag-js/dom-query": "1.38.0", + "@zag-js/focus-trap": "1.38.0", + "@zag-js/popper": "1.38.0", + "@zag-js/remove-scroll": "1.38.0", + "@zag-js/types": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/popper": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/popper/-/popper-1.38.2.tgz", - "integrity": "sha512-iqAFCeximjd2SGbsciXxbrHdrB/T5jeV4bf5KAPPGNM8Ce/dMcz5RteAArqBYJt1RDpB5px4RdeO8y+8vZOK/w==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/popper/-/popper-1.38.0.tgz", + "integrity": "sha512-qvTnAFGIUz9MnVGUy065ijeoycemwnOw3WKcbMBf7lUOuCyaWkRd/dvnHkidsDmwTP5HtTwCe5KJCERKo3C8Dg==", "license": "MIT", "dependencies": { "@floating-ui/dom": "^1.7.6", - "@zag-js/dom-query": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/dom-query": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/progress": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/progress/-/progress-1.38.2.tgz", - "integrity": "sha512-PY8fD2whXqLWafcIAOt8puFcLtnzutk9z074bWrWAV0dhUAzCTuMXF4hPrB/Qf+11CHxZZS467zp8WbgdPhIEw==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/progress/-/progress-1.38.0.tgz", + "integrity": "sha512-F8DijF7GwLlhkRianCnfIeySVBwMsMG6SGEJOSiecFHYJMedlgj37j3B6RRr13GDnqAGj3wAJBtvn+R8IYxv1Q==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "1.38.2", - "@zag-js/core": "1.38.2", - "@zag-js/dom-query": "1.38.2", - "@zag-js/types": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/anatomy": "1.38.0", + "@zag-js/core": "1.38.0", + "@zag-js/dom-query": "1.38.0", + "@zag-js/types": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/radio-group": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/radio-group/-/radio-group-1.38.2.tgz", - "integrity": "sha512-hyQq2AVCov/lgtfXraA/y2cKd9NKKdzXJT7sO2/59eKHyRYMylV3oatcQ2WqjrrnPxEfqLcQ7CWxl7NlcdnTow==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/radio-group/-/radio-group-1.38.0.tgz", + "integrity": "sha512-U1cO7fYKun3IWdfXp00c4mzegYNhfgGBm3lFfpj195jr5dXIEDfNYyto8Yf0MMUQigwFJwoQLSRHw2sW4TZ4rg==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "1.38.2", - "@zag-js/core": "1.38.2", - "@zag-js/dom-query": "1.38.2", - "@zag-js/focus-visible": "1.38.2", - "@zag-js/types": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/anatomy": "1.38.0", + "@zag-js/core": "1.38.0", + "@zag-js/dom-query": "1.38.0", + "@zag-js/focus-visible": "1.38.0", + "@zag-js/types": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/rating-group": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/rating-group/-/rating-group-1.38.2.tgz", - "integrity": "sha512-MggGwIcMWVvuRgDZJPnEvGnk5xYarbXOJnnP7BQK/31OgjRZmxwAAUKxHFDGY8vxRQ2XVTwmrPNTUVDDpQUJxQ==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/rating-group/-/rating-group-1.38.0.tgz", + "integrity": "sha512-6cql7pQDDDyxk7uE3RaiaOun5+J6Q7hqesk0WbBz2P8qmvokzd040aoa7xSsI+71Sdt93ESSjR7aN3tdhUHWwQ==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "1.38.2", - "@zag-js/core": "1.38.2", - "@zag-js/dom-query": "1.38.2", - "@zag-js/types": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/anatomy": "1.38.0", + "@zag-js/core": "1.38.0", + "@zag-js/dom-query": "1.38.0", + "@zag-js/types": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/rect-utils": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/rect-utils/-/rect-utils-1.38.2.tgz", - "integrity": "sha512-VX/EHbtq++h+rFGrj/ql3EFPuJwFQLAYjOxyMvEKF34L8N5imDodIyVqrQfumZl5MMGmKstz/x1kL4nHYAxyWQ==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/rect-utils/-/rect-utils-1.38.0.tgz", + "integrity": "sha512-tqLJliO8jLnNRUvqGbkvuH6SBfIza9hGoEoaDGZ1uWr7VHW1VCX9EUc1zunNz/YvU12M/Rh6O2i1E8Na7gYqXQ==", "license": "MIT" }, "node_modules/@zag-js/remove-scroll": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/remove-scroll/-/remove-scroll-1.38.2.tgz", - "integrity": "sha512-2NInlGgJmMQKMOyd5J2pc+L9/wj4NBhz028VwE31yxCK4dm3swcm5NYHdBAdpNG96ymximJsJndTkry7pnNNIA==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/remove-scroll/-/remove-scroll-1.38.0.tgz", + "integrity": "sha512-j2KsP2LFHBGBvlEbVUeW5mUZoNkZ2uhK8SxApq1GgtR+p+2LB+1BfVMeVtVplodaW+Ryl6f44iqXvFDcmUxvEg==", "license": "MIT", "dependencies": { - "@zag-js/dom-query": "1.38.2" + "@zag-js/dom-query": "1.38.0" } }, "node_modules/@zag-js/select": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/select/-/select-1.38.2.tgz", - "integrity": "sha512-F0qOw0ntyVO1G80iwktVFF3XYUodP9Tfet5XrCmDN+kM2trumn94wV+1plE/7/SRjDED7uwaCSpaBXaFiv8KUw==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/select/-/select-1.38.0.tgz", + "integrity": "sha512-S1pbBZbBxnDEWOZtlQ5Vp96LOp9qmKZCyZamX6IgnknuDz5NfT5771RVASA08A07Xu7PiZ021IMw1L0o0Wy3Hg==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "1.38.2", - "@zag-js/collection": "1.38.2", - "@zag-js/core": "1.38.2", - "@zag-js/dismissable": "1.38.2", - "@zag-js/dom-query": "1.38.2", - "@zag-js/focus-visible": "1.38.2", - "@zag-js/popper": "1.38.2", - "@zag-js/types": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/anatomy": "1.38.0", + "@zag-js/collection": "1.38.0", + "@zag-js/core": "1.38.0", + "@zag-js/dismissable": "1.38.0", + "@zag-js/dom-query": "1.38.0", + "@zag-js/focus-visible": "1.38.0", + "@zag-js/popper": "1.38.0", + "@zag-js/types": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/slider": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/slider/-/slider-1.38.2.tgz", - "integrity": "sha512-EBiCCLpwOA5eMcFgIMcAxNKQDePUqcVE+tTePteUVzzRONK1F/HLsLevIkpdJ4UouhPcDSsu5o2AH+w3bxW4sA==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/slider/-/slider-1.38.0.tgz", + "integrity": "sha512-AGWOIFN71C4zrEaiZu5HoSPIILErWH2fHX6HXJuwHjkjnD+2gMyv7SoRgqdzcbVJLA5IYGOpd98ugHU/xGqVog==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "1.38.2", - "@zag-js/core": "1.38.2", - "@zag-js/dom-query": "1.38.2", - "@zag-js/types": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/anatomy": "1.38.0", + "@zag-js/core": "1.38.0", + "@zag-js/dom-query": "1.38.0", + "@zag-js/types": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/store": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/store/-/store-1.38.2.tgz", - "integrity": "sha512-TlJM6M2dW5W9jr6US4/R/VobLmlFrSv48ls18XffmXp+uuwZ7Aisciq0Djtwx7Y7e5KhlUWtk4ncE5PtjP4AzQ==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/store/-/store-1.38.0.tgz", + "integrity": "sha512-LDX+/oBxEIXB6zXWkYrcI3KX1POW43tXIujJN7FlFjtagD5RL8RxgiPXPFz47d9HUCe0OjqCZJc2tX9K+wfrlw==", "license": "MIT", "dependencies": { "proxy-compare": "3.0.1" } }, "node_modules/@zag-js/switch": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/switch/-/switch-1.38.2.tgz", - "integrity": "sha512-EIK0DO8cFcDqE6cobEh66O07nufwQnRnpVvgOWpoB13Ts/LyQ/HUxF377JRPa4EYIY2/hIt6L8zvwfgFHUGAMg==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/switch/-/switch-1.38.0.tgz", + "integrity": "sha512-n67jUnU5LqZbtaQr5WW1az7QDA5uKyEaARs8pwQmhOqG0mEEZsbbzNzwBbvMjTQgLEScq3M2oP26iB+zhivLKQ==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "1.38.2", - "@zag-js/core": "1.38.2", - "@zag-js/dom-query": "1.38.2", - "@zag-js/focus-visible": "1.38.2", - "@zag-js/types": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/anatomy": "1.38.0", + "@zag-js/core": "1.38.0", + "@zag-js/dom-query": "1.38.0", + "@zag-js/focus-visible": "1.38.0", + "@zag-js/types": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/tabs": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/tabs/-/tabs-1.38.2.tgz", - "integrity": "sha512-yqCKQ+ugYtwAuF8ya6fkI577Yz96apRwHDawPem4xRq381YC5TYDrLpWvRj4UjakPOjs+1mHf2+53RYQhhEpEg==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/tabs/-/tabs-1.38.0.tgz", + "integrity": "sha512-El2D4MlzYvLA+2zYKl1GOWblRIxAXZGH7RaWe4gCblcgm7Zqie7iKdbFruWprQo2UgkTaGrTav+sACqDLjDt1A==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "1.38.2", - "@zag-js/core": "1.38.2", - "@zag-js/dom-query": "1.38.2", - "@zag-js/types": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/anatomy": "1.38.0", + "@zag-js/core": "1.38.0", + "@zag-js/dom-query": "1.38.0", + "@zag-js/types": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/tags-input": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/tags-input/-/tags-input-1.38.2.tgz", - "integrity": "sha512-WV7uz5UGXThL8PqTor8tFKtLsTO79B7mRjoVNwgSKJ473C+Z9tFhJx+S6cPXvSx0PcDxYBX1DXI0NFWVgWVD4Q==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/tags-input/-/tags-input-1.38.0.tgz", + "integrity": "sha512-aeke5F837hxJrPIIfC2IgtSvpNNmyBy3FlxdK9kyxLj6i8kyMTKWkqWTHLPh1eC9YsktGwrE69///DpQBEM5Ag==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "1.38.2", - "@zag-js/auto-resize": "1.38.2", - "@zag-js/core": "1.38.2", - "@zag-js/dom-query": "1.38.2", - "@zag-js/interact-outside": "1.38.2", - "@zag-js/live-region": "1.38.2", - "@zag-js/types": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/anatomy": "1.38.0", + "@zag-js/auto-resize": "1.38.0", + "@zag-js/core": "1.38.0", + "@zag-js/dom-query": "1.38.0", + "@zag-js/interact-outside": "1.38.0", + "@zag-js/live-region": "1.38.0", + "@zag-js/types": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/toast": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/toast/-/toast-1.38.2.tgz", - "integrity": "sha512-VRTfTjRrnn9U8RVKr2dTUWBzMBALNy5PMxr+z7Q1hUufv0JYfzPsSkVXsbSjI5OZPklbJ5P1ugmUrtVrATyGHw==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/toast/-/toast-1.38.0.tgz", + "integrity": "sha512-cGLrdDYiEvivbHO9KxopKDc1PT/klJKKcz6lPBx4lD8AsGysxrTsn92YSBLC98bV3QReepBKOLTD3/D/SQCeGA==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "1.38.2", - "@zag-js/core": "1.38.2", - "@zag-js/dismissable": "1.38.2", - "@zag-js/dom-query": "1.38.2", - "@zag-js/types": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/anatomy": "1.38.0", + "@zag-js/core": "1.38.0", + "@zag-js/dismissable": "1.38.0", + "@zag-js/dom-query": "1.38.0", + "@zag-js/types": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/toggle-group": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/toggle-group/-/toggle-group-1.38.2.tgz", - "integrity": "sha512-vl9hDypfxiwR3gcsai+lBwRcPR1NwwNVP8ZhS3mdMwi3v5Lr4R4UCZc0l2/qFPj+IQ0q01VIGJJbkkFCB7a3iQ==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/toggle-group/-/toggle-group-1.38.0.tgz", + "integrity": "sha512-p/rHDw3gcJthSJs6jrpFTjZJV+W124rDj5yUkv6BzkNPrCacTPtNiO4l5i7YTKcn9+gWKkM3RnKoPdQDR3dz/g==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "1.38.2", - "@zag-js/core": "1.38.2", - "@zag-js/dom-query": "1.38.2", - "@zag-js/types": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/anatomy": "1.38.0", + "@zag-js/core": "1.38.0", + "@zag-js/dom-query": "1.38.0", + "@zag-js/types": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/tooltip": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/tooltip/-/tooltip-1.38.2.tgz", - "integrity": "sha512-pFVWc6KjLujIvyOz2CzFQu4e9NVC61yE0oQpjRIQwzZAICxxiPE3QeOtb0Aw3Jhd0n2Y7qxuLyFI6gcAxI9Sxg==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/tooltip/-/tooltip-1.38.0.tgz", + "integrity": "sha512-S5EnwYpR/wREV2gUm4YjiTHq9lCHD9hdwkpjF0vWmpI9av8DQWGCGHA6LMVue7h+nHQRImp3qo5SvNWmZhu8OQ==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "1.38.2", - "@zag-js/core": "1.38.2", - "@zag-js/dom-query": "1.38.2", - "@zag-js/focus-visible": "1.38.2", - "@zag-js/popper": "1.38.2", - "@zag-js/types": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/anatomy": "1.38.0", + "@zag-js/core": "1.38.0", + "@zag-js/dom-query": "1.38.0", + "@zag-js/focus-visible": "1.38.0", + "@zag-js/popper": "1.38.0", + "@zag-js/types": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/tree-view": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/tree-view/-/tree-view-1.38.2.tgz", - "integrity": "sha512-w2R+EI6/ovTjGI6Vu/z6pMS9ZUMjSsj7jAsm7ZKbfwNngSIJBAu+kdAAZbeovl9MW/gnNVgpuJuS6N4yqANdIw==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/tree-view/-/tree-view-1.38.0.tgz", + "integrity": "sha512-EjlnUxsfuUluzlX/QN0RKtFd2XGYtw0sTF/jsoSJT1yJbZsvJuhARV29Dz8M4aJOpIg3e61Lz5J897fpmdUiFA==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "1.38.2", - "@zag-js/collection": "1.38.2", - "@zag-js/core": "1.38.2", - "@zag-js/dom-query": "1.38.2", - "@zag-js/types": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/anatomy": "1.38.0", + "@zag-js/collection": "1.38.0", + "@zag-js/core": "1.38.0", + "@zag-js/dom-query": "1.38.0", + "@zag-js/types": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/@zag-js/types": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/types/-/types-1.38.2.tgz", - "integrity": "sha512-fvUf3J4QOFAliuo5wHTO/awO0GKFAn5AHNOXbGH5IuoxIwa0oK5tSXVwdF8JE7ISOkQh4oB2fq3g4QjxmAXDyA==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/types/-/types-1.38.0.tgz", + "integrity": "sha512-F8SL5eiJbwX+K546AQY2nsroMJDBGML19IiveGkFrOnL6/wOqSh15QIzY+Qk6Qblt6eBS2F+HkYFW7UF0V7SHw==", "license": "MIT", "dependencies": { "csstype": "3.2.3" } }, "node_modules/@zag-js/utils": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/utils/-/utils-1.38.2.tgz", - "integrity": "sha512-8UuWDomJ5JLX/KSDjEA4poX9rzqkGL47RiSCuVod+qZpWD0jpyXP7Lf600GUFtirRAiuN3x1+7KE6Elt/0rxtw==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/utils/-/utils-1.38.0.tgz", + "integrity": "sha512-eFTeTnsgs+G1Pf1qh6CXnaoaH0FL3WC4ksj5Ep3rrVZ+tOGzlJOESOgw9poh2IbRIzpk85+eR4rJ+PXfhNu4KQ==", "license": "MIT" }, "node_modules/@zag-js/vanilla": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@zag-js/vanilla/-/vanilla-1.38.2.tgz", - "integrity": "sha512-5//7bSqbZ0UbIGYX3ShEZNVRd1xrTxHx30b6Wdac5WbJLqcdoodtAaRy/w7w1azq1Cpj8mmxyyedOeNGdrnoBg==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/@zag-js/vanilla/-/vanilla-1.38.0.tgz", + "integrity": "sha512-kPGeV5cu150Q5VvVEYV8OzrXQHupJq5Vd3nUt5nWwmMz9MBIuQsqeNNN+DBVMGmzeLHqI0XB90aRSlDub1pN5g==", "license": "MIT", "dependencies": { - "@zag-js/core": "1.38.2", - "@zag-js/store": "1.38.2", - "@zag-js/types": "1.38.2", - "@zag-js/utils": "1.38.2" + "@zag-js/core": "1.38.0", + "@zag-js/store": "1.38.0", + "@zag-js/types": "1.38.0", + "@zag-js/utils": "1.38.0" } }, "node_modules/acorn": { @@ -4241,19 +4242,6 @@ "node": ">= 8" } }, - "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", @@ -4393,17 +4381,6 @@ "postcss": "^8.1.0" } }, - "node_modules/bail": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", - "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/balanced-match": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", @@ -4415,9 +4392,9 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.10.10", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.10.tgz", - "integrity": "sha512-sUoJ3IMxx4AyRqO4MLeHlnGDkyXRoUG0/AI9fjK+vS72ekpV0yWVY7O0BVjmBcRtkNcsAO2QDZ4tdKKGoI6YaQ==", + "version": "2.10.9", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.9.tgz", + "integrity": "sha512-OZd0e2mU11ClX8+IdXe3r0dbqMEznRiT4TfbhYIbcRPZkqJ7Qwer8ij3GZAmLsRKa+II9V1v5czCkvmHH3XZBg==", "dev": true, "license": "Apache-2.0", "bin": { @@ -4669,9 +4646,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001781", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001781.tgz", - "integrity": "sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw==", + "version": "1.0.30001780", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001780.tgz", + "integrity": "sha512-llngX0E7nQci5BPJDqoZSbuZ5Bcs9F5db7EtgfwBerX9XGtkkiO4NwfDDIRzHTTwcYC8vC7bmeUEPGrKlR/TkQ==", "dev": true, "funding": [ { @@ -4700,17 +4677,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/character-entities": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", - "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/character-entities-html4": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", @@ -4988,20 +4954,6 @@ "dev": true, "license": "MIT" }, - "node_modules/decode-named-character-reference": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", - "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "character-entities": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -5055,12 +5007,6 @@ "node": ">=8" } }, - "node_modules/devalue": { - "version": "5.6.4", - "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.4.tgz", - "integrity": "sha512-Gp6rDldRsFh/7XuouDbxMH3Mx8GMCcgzIb1pDTvNyn8pZGQ22u+Wa+lGV9dQCltFQ7uVw0MhRyb8XDskNFOReA==", - "license": "MIT" - }, "node_modules/devlop": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", @@ -5134,9 +5080,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.325", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.325.tgz", - "integrity": "sha512-PwfIw7WQSt3xX7yOf5OE/unLzsK9CaN2f/FvV3WjPR1Knoc1T9vePRVV4W1EM301JzzysK51K7FNKcusCr0zYA==", + "version": "1.5.321", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.321.tgz", + "integrity": "sha512-L2C7Q279W2D/J4PLZLk7sebOILDSWos7bMsMNN06rK482umHUrh/3lM8G7IlHFOYip2oAg5nha1rCMxr/rs6ZQ==", "dev": true, "license": "ISC" }, @@ -5264,16 +5210,16 @@ } }, "node_modules/eslint": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.1.0.tgz", - "integrity": "sha512-S9jlY/ELKEUwwQnqWDO+f+m6sercqOPSqXM5Go94l7DOmxHVDgmSFGWEzeE/gwgTAr0W103BWt0QLe/7mabIvA==", + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.0.3.tgz", + "integrity": "sha512-COV33RzXZkqhG9P2rZCFl9ZmJ7WL+gQSCRzE7RhkbclbQPtLAWReL7ysA0Sh4c8Im2U9ynybdR56PV0XcKvqaQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", "@eslint/config-array": "^0.23.3", - "@eslint/config-helpers": "^0.5.3", + "@eslint/config-helpers": "^0.5.2", "@eslint/core": "^1.1.1", "@eslint/plugin-kit": "^0.6.1", "@humanfs/node": "^0.16.6", @@ -5286,7 +5232,7 @@ "escape-string-regexp": "^4.0.0", "eslint-scope": "^9.1.2", "eslint-visitor-keys": "^5.0.1", - "espree": "^11.2.0", + "espree": "^11.1.1", "esquery": "^1.7.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -5454,7 +5400,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", @@ -5534,18 +5479,10 @@ "dev": true, "license": "MIT" }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true, - "license": "MIT" - }, "node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dev": true, "license": "MIT", "dependencies": { "is-extendable": "^0.1.0" @@ -5629,37 +5566,6 @@ "reusify": "^1.0.4" } }, - "node_modules/fault": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", - "integrity": "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "format": "^0.2.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -5760,15 +5666,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/format": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", - "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", - "dev": true, - "engines": { - "node": ">=0.4.x" - } - }, "node_modules/fraction.js": { "version": "5.3.4", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", @@ -5799,10 +5696,9 @@ } }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "hasInstallScript": true, "license": "MIT", "optional": true, @@ -5838,9 +5734,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.13.7", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.7.tgz", - "integrity": "sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==", + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -5926,7 +5822,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", - "dev": true, "license": "MIT", "dependencies": { "js-yaml": "^3.13.1", @@ -5942,7 +5837,6 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" @@ -5952,7 +5846,6 @@ "version": "3.14.2", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", - "dev": true, "license": "MIT", "dependencies": { "argparse": "^1.0.7", @@ -6154,7 +6047,6 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -6210,19 +6102,6 @@ "node": ">=0.12.0" } }, - "node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", @@ -6362,14 +6241,14 @@ } }, "node_modules/jsdom": { - "version": "29.0.1", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-29.0.1.tgz", - "integrity": "sha512-z6JOK5gRO7aMybVq/y/MlIpKh8JIi68FBKMUtKkK2KH/wMSRlCxQ682d08LB9fYXplyY/UXG8P4XXTScmdjApg==", + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-29.0.0.tgz", + "integrity": "sha512-9FshNB6OepopZ08unmmGpsF7/qCjxGPbo3NbgfJAnPeHXnsODE9WWffXZtRFRFe0ntzaAOcSKNJFz8wiyvF1jQ==", "dev": true, "license": "MIT", "dependencies": { "@asamuzakjp/css-color": "^5.0.1", - "@asamuzakjp/dom-selector": "^7.0.3", + "@asamuzakjp/dom-selector": "^7.0.2", "@bramus/specificity": "^2.4.2", "@csstools/css-syntax-patches-for-csstree": "^1.1.1", "@exodus/bytes": "^1.15.0", @@ -6383,7 +6262,7 @@ "saxes": "^6.0.0", "symbol-tree": "^3.2.4", "tough-cookie": "^6.0.1", - "undici": "^7.24.5", + "undici": "^7.24.3", "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^8.0.1", "whatwg-mimetype": "^5.0.0", @@ -6459,7 +6338,6 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -6520,7 +6398,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -6541,7 +6418,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -6562,7 +6438,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -6583,7 +6458,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -6604,7 +6478,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -6625,7 +6498,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -6646,7 +6518,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -6667,7 +6538,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -6688,7 +6558,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -6709,7 +6578,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -6730,7 +6598,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -6759,16 +6626,6 @@ "dev": true, "license": "MIT" }, - "node_modules/linkify-it": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", - "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "uc.micro": "^2.0.0" - } - }, "node_modules/load-tsconfig": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/load-tsconfig/-/load-tsconfig-0.2.5.tgz", @@ -6821,17 +6678,6 @@ "dev": true, "license": "MIT" }, - "node_modules/longest-streak": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", - "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/lru-cache": { "version": "11.2.7", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", @@ -6875,401 +6721,57 @@ "dev": true, "license": "MIT" }, - "node_modules/markdown-it": { - "version": "14.1.1", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz", - "integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==", - "dev": true, + "node_modules/marked": { + "version": "17.0.5", + "resolved": "https://registry.npmjs.org/marked/-/marked-17.0.5.tgz", + "integrity": "sha512-6hLvc0/JEbRjRgzI6wnT2P1XuM1/RrrDEX0kPt0N7jGm1133g6X7DlxFasUIx+72aKAr904GTxhSLDrd5DIlZg==", "license": "MIT", - "dependencies": { - "argparse": "^2.0.1", - "entities": "^4.4.0", - "linkify-it": "^5.0.0", - "mdurl": "^2.0.0", - "punycode.js": "^2.3.1", - "uc.micro": "^2.1.0" - }, "bin": { - "markdown-it": "bin/markdown-it.mjs" - } - }, - "node_modules/markdown-it/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" + "marked": "bin/marked.js" }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/markdown-title": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/markdown-title/-/markdown-title-1.0.2.tgz", - "integrity": "sha512-MqIQVVkz+uGEHi3TsHx/czcxxCbRIL7sv5K5DnYw/tI+apY54IbPefV/cmgxp6LoJSEx/TqcHdLs/298afG5QQ==", - "dev": true, - "license": "MIT", "engines": { - "node": ">=6" + "node": ">= 20" } }, - "node_modules/mdast-util-from-markdown": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", - "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==", + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", "dev": true, "license": "MIT", "dependencies": { + "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "decode-named-character-reference": "^1.0.0", + "@ungap/structured-clone": "^1.0.0", "devlop": "^1.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark": "^4.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-stringify-position": "^4.0.0" + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-frontmatter": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-2.0.1.tgz", - "integrity": "sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==", + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", "dev": true, - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "escape-string-regexp": "^5.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0", - "micromark-extension-frontmatter": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } + "license": "CC0-1.0" }, - "node_modules/mdast-util-frontmatter/node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mdast-util-phrasing": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", - "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-hast": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", - "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "@ungap/structured-clone": "^1.0.0", - "devlop": "^1.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "trim-lines": "^3.0.0", - "unist-util-position": "^5.0.0", - "unist-util-visit": "^5.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-markdown": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", - "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "longest-streak": "^3.0.0", - "mdast-util-phrasing": "^4.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "unist-util-visit": "^5.0.0", - "zwitch": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", - "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdn-data": { - "version": "2.27.1", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", - "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", - "dev": true, - "license": "CC0-1.0" - }, - "node_modules/mdurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", - "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", - "dev": true, - "license": "MIT" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, "license": "MIT", "engines": { "node": ">= 8" } }, - "node_modules/micromark": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", - "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-core-commonmark": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", - "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-destination": "^2.0.0", - "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-title": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-html-tag-name": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-frontmatter": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-2.0.0.tgz", - "integrity": "sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==", - "dev": true, - "license": "MIT", - "dependencies": { - "fault": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-factory-destination": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", - "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-label": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", - "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-space": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", - "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-title": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", - "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-whitespace": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", - "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, "node_modules/micromark-util-character": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", @@ -7291,112 +6793,6 @@ "micromark-util-types": "^2.0.0" } }, - "node_modules/micromark-util-chunked": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", - "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-classify-character": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", - "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-combine-extensions": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", - "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-chunked": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", - "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-decode-string": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", - "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, "node_modules/micromark-util-encode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", @@ -7414,63 +6810,6 @@ ], "license": "MIT" }, - "node_modules/micromark-util-html-tag-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", - "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-normalize-identifier": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", - "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-resolve-all": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", - "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-types": "^2.0.0" - } - }, "node_modules/micromark-util-sanitize-uri": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", @@ -7493,29 +6832,6 @@ "micromark-util-symbol": "^2.0.0" } }, - "node_modules/micromark-util-subtokenize": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", - "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, "node_modules/micromark-util-symbol": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", @@ -7564,32 +6880,6 @@ "node": ">=8.6" } }, - "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/millify": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/millify/-/millify-6.1.0.tgz", - "integrity": "sha512-H/E3J6t+DQs/F2YgfDhxUVZz/dF8JXPPKTLHL/yHCcLZLtCXJDUaqvhJXQwqOVBvbyNn4T0WjLpIHd7PAw7fBA==", - "dev": true, - "license": "MIT", - "dependencies": { - "yargs": "^17.0.1" - }, - "bin": { - "millify": "bin/millify" - } - }, "node_modules/minimatch": { "version": "10.2.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", @@ -7963,13 +7253,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/path-to-regexp": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", - "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", - "dev": true, - "license": "MIT" - }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -8001,12 +7284,13 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "license": "MIT", "engines": { - "node": ">=12" + "node": ">=8.6" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" @@ -8076,6 +7360,21 @@ "node": ">=18" } }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/postcss": { "version": "8.5.8", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", @@ -8275,19 +7574,6 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/pretty-bytes": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-7.1.0.tgz", - "integrity": "sha512-nODzvTiYVRGRqAOvE84Vk5JDPyyxsVk0/fbA/bq7RqlnhksGpset09XTxbpvLTIjoaF7K8Z8DG8yHtKGTPSYRw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/prismjs": { "version": "1.30.0", "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", @@ -8315,20 +7601,10 @@ "integrity": "sha512-V9plBAt3qjMlS1+nC8771KNf6oJ12gExvaxnNzN/9yVRLdTv/lc+oJlnSzrdYDAvBfTStPCoiaCOTmTs0adv7Q==", "license": "MIT" }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/punycode.js": { + "node_modules/punycode": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", - "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "license": "MIT", "engines": { @@ -8505,73 +7781,6 @@ "dev": true, "license": "MIT" }, - "node_modules/remark": { - "version": "15.0.1", - "resolved": "https://registry.npmjs.org/remark/-/remark-15.0.1.tgz", - "integrity": "sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "remark-parse": "^11.0.0", - "remark-stringify": "^11.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-frontmatter": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-5.0.0.tgz", - "integrity": "sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-frontmatter": "^2.0.0", - "micromark-extension-frontmatter": "^2.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-parse": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", - "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-from-markdown": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-stringify": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", - "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-to-markdown": "^2.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -8652,14 +7861,14 @@ "license": "MIT" }, "node_modules/rolldown": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.12.tgz", - "integrity": "sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A==", + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.10.tgz", + "integrity": "sha512-q7j6vvarRFmKpgJUT8HCAUljkgzEp4LAhPlJUvQhA5LA1SUL36s5QCysMutErzL3EbNOZOkoziSx9iZC4FddKA==", "license": "MIT", "peer": true, "dependencies": { - "@oxc-project/types": "=0.122.0", - "@rolldown/pluginutils": "1.0.0-rc.12" + "@oxc-project/types": "=0.120.0", + "@rolldown/pluginutils": "1.0.0-rc.10" }, "bin": { "rolldown": "bin/cli.mjs" @@ -8668,21 +7877,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-rc.12", - "@rolldown/binding-darwin-arm64": "1.0.0-rc.12", - "@rolldown/binding-darwin-x64": "1.0.0-rc.12", - "@rolldown/binding-freebsd-x64": "1.0.0-rc.12", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.12", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.12", - "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.12", - "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.12", - "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.12", - "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.12", - "@rolldown/binding-linux-x64-musl": "1.0.0-rc.12", - "@rolldown/binding-openharmony-arm64": "1.0.0-rc.12", - "@rolldown/binding-wasm32-wasi": "1.0.0-rc.12", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.12", - "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.12" + "@rolldown/binding-android-arm64": "1.0.0-rc.10", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.10", + "@rolldown/binding-darwin-x64": "1.0.0-rc.10", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.10", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.10", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.10", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.10", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.10", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.10", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.10", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.10", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.10", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.10", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.10", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.10" } }, "node_modules/rolldown-plugin-dts": { @@ -8929,7 +8138,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", - "dev": true, "license": "MIT", "dependencies": { "extend-shallow": "^2.0.1", @@ -9069,7 +8277,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true, "license": "BSD-3-Clause" }, "node_modules/string-width": { @@ -9129,7 +8336,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -9304,19 +8510,6 @@ "node": ">= 6" } }, - "node_modules/tailwindcss/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/tailwindcss/node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -9404,23 +8597,52 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/tldts": { - "version": "7.0.27", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.27.tgz", - "integrity": "sha512-I4FZcVFcqCRuT0ph6dCDpPuO4Xgzvh+spkcTr1gK7peIvxWauoloVO0vuy1FQnijT63ss6AsHB6+OIM4aXHbPg==", + "version": "7.0.26", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.26.tgz", + "integrity": "sha512-WiGwQjr0qYdNNG8KpMKlSvpxz652lqa3Rd+/hSaDcY4Uo6SKWZq2LAF+hsAhUewTtYhXlorBKgNF3Kk8hnjGoQ==", "dev": true, "license": "MIT", "dependencies": { - "tldts-core": "^7.0.27" + "tldts-core": "^7.0.26" }, "bin": { "tldts": "bin/cli.js" } }, "node_modules/tldts-core": { - "version": "7.0.27", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.27.tgz", - "integrity": "sha512-YQ7uPjgWUibIK6DW5lrKujGwUKhLevU4hcGbP5O6TcIUb+oTjJYJVWPS4nZsIHrEEEG6myk/oqAJUEQmpZrHsg==", + "version": "7.0.26", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.26.tgz", + "integrity": "sha512-5WJ2SqFsv4G2Dwi7ZFVRnz6b2H1od39QME1lc2y5Ew3eWiZMAeqOAfWpRP9jHvhUl881406QtZTODvjttJs+ew==", "dev": true, "license": "MIT" }, @@ -9437,13 +8659,6 @@ "node": ">=8.0" } }, - "node_modules/tokenx": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/tokenx/-/tokenx-1.3.0.tgz", - "integrity": "sha512-NLdXTEZkKiO0gZuLtMoZKjCXTREXeZZt8nnnNeyoXtNZAfG/GKGSbQtLU5STspc0rMSwcA+UJfWZkbNU01iKmQ==", - "dev": true, - "license": "MIT" - }, "node_modules/tough-cookie": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.1.tgz", @@ -9491,17 +8706,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/trough": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", - "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/ts-api-utils": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", @@ -9523,9 +8727,9 @@ "license": "Apache-2.0" }, "node_modules/tsdown": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/tsdown/-/tsdown-0.21.5.tgz", - "integrity": "sha512-TlgNhfPioAD6ECCUnZsxcUsXXuPPR4Rrxz3az741kL/M3oGIET4a9GajSNRNRx+jIva73TYUKQybrEPkDYN+fQ==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/tsdown/-/tsdown-0.21.4.tgz", + "integrity": "sha512-Q/kBi8SXkr4X6JI/NAZKZY1UuiEcbuXtIskL4tZCsgpDiEPM/2W6lC+OonNA31S+V3KsWedFvbFDBs23hvt+Aw==", "dev": true, "license": "MIT", "dependencies": { @@ -9536,15 +8740,15 @@ "hookable": "^6.1.0", "import-without-cache": "^0.2.5", "obug": "^2.1.1", - "picomatch": "^4.0.4", - "rolldown": "1.0.0-rc.11", + "picomatch": "^4.0.3", + "rolldown": "1.0.0-rc.9", "rolldown-plugin-dts": "^0.22.5", "semver": "^7.7.4", "tinyexec": "^1.0.4", "tinyglobby": "^0.2.15", "tree-kill": "^1.2.2", "unconfig-core": "^7.5.0", - "unrun": "^0.2.33" + "unrun": "^0.2.32" }, "bin": { "tsdown": "dist/run.mjs" @@ -9557,11 +8761,11 @@ }, "peerDependencies": { "@arethetypeswrong/core": "^0.18.1", - "@tsdown/css": "0.21.5", - "@tsdown/exe": "0.21.5", + "@tsdown/css": "0.21.4", + "@tsdown/exe": "0.21.4", "@vitejs/devtools": "*", "publint": "^0.3.0", - "typescript": "^5.0.0 || ^6.0.0", + "typescript": "^5.0.0", "unplugin-unused": "^0.5.0" }, "peerDependenciesMeta": { @@ -9588,10 +8792,20 @@ } } }, + "node_modules/tsdown/node_modules/@oxc-project/types": { + "version": "0.115.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.115.0.tgz", + "integrity": "sha512-4n91DKnebUS4yjUHl2g3/b2T+IUdCfmoZGhmwsovZCDaJSs+QkVAM+0AqqTxHSsHfeiMuueT75cZaZcT/m0pSw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, "node_modules/tsdown/node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.11.tgz", - "integrity": "sha512-SJ+/g+xNnOh6NqYxD0V3uVN4W3VfnrGsC9/hoglicgTNfABFG9JjISvkkU0dNY84MNHLWyOgxP9v9Y9pX4S7+A==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.9.tgz", + "integrity": "sha512-lcJL0bN5hpgJfSIz/8PIf02irmyL43P+j1pTCfbD1DbLkmGRuFIA4DD3B3ZOvGqG0XiVvRznbKtN0COQVaKUTg==", "cpu": [ "arm64" ], @@ -9606,9 +8820,9 @@ } }, "node_modules/tsdown/node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.11.tgz", - "integrity": "sha512-7WQgR8SfOPwmDZGFkThUvsmd/nwAWv91oCO4I5LS7RKrssPZmOt7jONN0cW17ydGC1n/+puol1IpoieKqQidmg==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.9.tgz", + "integrity": "sha512-J7Zk3kLYFsLtuH6U+F4pS2sYVzac0qkjcO5QxHS7OS7yZu2LRs+IXo+uvJ/mvpyUljDJ3LROZPoQfgBIpCMhdQ==", "cpu": [ "arm64" ], @@ -9623,9 +8837,9 @@ } }, "node_modules/tsdown/node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.11.tgz", - "integrity": "sha512-39Ks6UvIHq4rEogIfQBoBRusj0Q0nPVWIvqmwBLaT6aqQGIakHdESBVOPRRLacy4WwUPIx4ZKzfZ9PMW+IeyUQ==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.9.tgz", + "integrity": "sha512-iwtmmghy8nhfRGeNAIltcNXzD0QMNaaA5U/NyZc1Ia4bxrzFByNMDoppoC+hl7cDiUq5/1CnFthpT9n+UtfFyg==", "cpu": [ "x64" ], @@ -9640,9 +8854,9 @@ } }, "node_modules/tsdown/node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.11.tgz", - "integrity": "sha512-jfsm0ZHfhiqrvWjJAmzsqiIFPz5e7mAoCOPBNTcNgkiid/LaFKiq92+0ojH+nmJmKYkre4t71BWXUZDNp7vsag==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.9.tgz", + "integrity": "sha512-DLFYI78SCiZr5VvdEplsVC2Vx53lnA4/Ga5C65iyldMVaErr86aiqCoNBLl92PXPfDtUYjUh+xFFor40ueNs4Q==", "cpu": [ "x64" ], @@ -9657,9 +8871,9 @@ } }, "node_modules/tsdown/node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.11.tgz", - "integrity": "sha512-zjQaUtSyq1nVe3nxmlSCuR96T1LPlpvmJ0SZy0WJFEsV4kFbXcq2u68L4E6O0XeFj4aex9bEauqjW8UQBeAvfQ==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.9.tgz", + "integrity": "sha512-CsjTmTwd0Hri6iTw/DRMK7kOZ7FwAkrO4h8YWKoX/kcj833e4coqo2wzIFywtch/8Eb5enQ/lwLM7w6JX1W5RQ==", "cpu": [ "arm" ], @@ -9674,9 +8888,9 @@ } }, "node_modules/tsdown/node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.11.tgz", - "integrity": "sha512-WMW1yE6IOnehTcFE9eipFkm3XN63zypWlrJQ2iF7NrQ9b2LDRjumFoOGJE8RJJTJCTBAdmLMnJ8uVitACUUo1Q==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.9.tgz", + "integrity": "sha512-2x9O2JbSPxpxMDhP9Z74mahAStibTlrBMW0520+epJH5sac7/LwZW5Bmg/E6CXuEF53JJFW509uP+lSedaUNxg==", "cpu": [ "arm64" ], @@ -9691,9 +8905,9 @@ } }, "node_modules/tsdown/node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.11.tgz", - "integrity": "sha512-jfndI9tsfm4APzjNt6QdBkYwre5lRPUgHeDHoI7ydKUuJvz3lZeCfMsI56BZj+7BYqiKsJm7cfd/6KYV7ubrBg==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.9.tgz", + "integrity": "sha512-JA1QRW31ogheAIRhIg9tjMfsYbglXXYGNPLdPEYrwFxdbkQCAzvpSCSHCDWNl4hTtrol8WeboCSEpjdZK8qrCg==", "cpu": [ "arm64" ], @@ -9708,9 +8922,9 @@ } }, "node_modules/tsdown/node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.11.tgz", - "integrity": "sha512-ZlFgw46NOAGMgcdvdYwAGu2Q+SLFA9LzbJLW+iyMOJyhj5wk6P3KEE9Gct4xWwSzFoPI7JCdYmYMzVtlgQ+zfw==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.9.tgz", + "integrity": "sha512-aOKU9dJheda8Kj8Y3w9gnt9QFOO+qKPAl8SWd7JPHP+Cu0EuDAE5wokQubLzIDQWg2myXq2XhTpOVS07qqvT+w==", "cpu": [ "ppc64" ], @@ -9725,9 +8939,9 @@ } }, "node_modules/tsdown/node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.11.tgz", - "integrity": "sha512-hIOYmuT6ofM4K04XAZd3OzMySEO4K0/nc9+jmNcxNAxRi6c5UWpqfw3KMFV4MVFWL+jQsSh+bGw2VqmaPMTLyw==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.9.tgz", + "integrity": "sha512-OalO94fqj7IWRn3VdXWty75jC5dk4C197AWEuMhIpvVv2lw9fiPhud0+bW2ctCxb3YoBZor71QHbY+9/WToadA==", "cpu": [ "s390x" ], @@ -9742,9 +8956,9 @@ } }, "node_modules/tsdown/node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.11.tgz", - "integrity": "sha512-qXBQQO9OvkjjQPLdUVr7Nr2t3QTZI7s4KZtfw7HzBgjbmAPSFwSv4rmET9lLSgq3rH/ndA3ngv3Qb8l2njoPNA==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.9.tgz", + "integrity": "sha512-cVEl1vZtBsBZna3YMjGXNvnYYrOJ7RzuWvZU0ffvJUexWkukMaDuGhUXn0rjnV0ptzGVkvc+vW9Yqy6h8YX4pg==", "cpu": [ "x64" ], @@ -9759,9 +8973,9 @@ } }, "node_modules/tsdown/node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.11.tgz", - "integrity": "sha512-/tpFfoSTzUkH9LPY+cYbqZBDyyX62w5fICq9qzsHLL8uTI6BHip3Q9Uzft0wylk/i8OOwKik8OxW+QAhDmzwmg==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.9.tgz", + "integrity": "sha512-UzYnKCIIc4heAKgI4PZ3dfBGUZefGCJ1TPDuLHoCzgrMYPb5Rv6TLFuYtyM4rWyHM7hymNdsg5ik2C+UD9VDbA==", "cpu": [ "x64" ], @@ -9776,9 +8990,9 @@ } }, "node_modules/tsdown/node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.11.tgz", - "integrity": "sha512-mcp3Rio2w72IvdZG0oQ4bM2c2oumtwHfUfKncUM6zGgz0KgPz4YmDPQfnXEiY5t3+KD/i8HG2rOB/LxdmieK2g==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.9.tgz", + "integrity": "sha512-+6zoiF+RRyf5cdlFQP7nm58mq7+/2PFaY2DNQeD4B87N36JzfF/l9mdBkkmTvSYcYPE8tMh/o3cRlsx1ldLfog==", "cpu": [ "arm64" ], @@ -9793,9 +9007,9 @@ } }, "node_modules/tsdown/node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.11.tgz", - "integrity": "sha512-LXk5Hii1Ph9asuGRjBuz8TUxdc1lWzB7nyfdoRgI0WGPZKmCxvlKk8KfYysqtr4MfGElu/f/pEQRh8fcEgkrWw==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.9.tgz", + "integrity": "sha512-rgFN6sA/dyebil3YTlL2evvi/M+ivhfnyxec7AccTpRPccno/rPoNlqybEZQBkcbZu8Hy+eqNJCqfBR8P7Pg8g==", "cpu": [ "wasm32" ], @@ -9810,9 +9024,9 @@ } }, "node_modules/tsdown/node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.11.tgz", - "integrity": "sha512-dDwf5otnx0XgRY1yqxOC4ITizcdzS/8cQ3goOWv3jFAo4F+xQYni+hnMuO6+LssHHdJW7+OCVL3CoU4ycnh35Q==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.9.tgz", + "integrity": "sha512-lHVNUG/8nlF1IQk1C0Ci574qKYyty2goMiPlRqkC5R+3LkXDkL5Dhx8ytbxq35m+pkHVIvIxviD+TWLdfeuadA==", "cpu": [ "arm64" ], @@ -9827,9 +9041,9 @@ } }, "node_modules/tsdown/node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.11.tgz", - "integrity": "sha512-LN4/skhSggybX71ews7dAj6r2geaMJfm3kMbK2KhFMg9B10AZXnKoLCVVgzhMHL0S+aKtr4p8QbAW8k+w95bAA==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.9.tgz", + "integrity": "sha512-G0oA4+w1iY5AGi5HcDTxWsoxF509hrFIPB2rduV5aDqS9FtDg1CAfa7V34qImbjfhIcA8C+RekocJZA96EarwQ==", "cpu": [ "x64" ], @@ -9844,9 +9058,9 @@ } }, "node_modules/tsdown/node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.11.tgz", - "integrity": "sha512-xQO9vbwBecJRv9EUcQ/y0dzSTJgA7Q6UVN7xp6B81+tBGSLVAK03yJ9NkJaUA7JFD91kbjxRSC/mDnmvXzbHoQ==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.9.tgz", + "integrity": "sha512-w6oiRWgEBl04QkFZgmW+jnU1EC9b57Oihi2ot3HNWIQRqgHp5PnYDia5iZ5FF7rpa4EQdiqMDXjlqKGXBhsoXw==", "dev": true, "license": "MIT" }, @@ -9867,15 +9081,28 @@ "dev": true, "license": "MIT" }, + "node_modules/tsdown/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/tsdown/node_modules/rolldown": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.11.tgz", - "integrity": "sha512-NRjoKMusSjfRbSYiH3VSumlkgFe7kYAa3pzVOsVYVFY3zb5d7nS+a3KGQ7hJKXuYWbzJKPVQ9Wxq2UvyK+ENpw==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.9.tgz", + "integrity": "sha512-9EbgWge7ZH+yqb4d2EnELAntgPTWbfL8ajiTW+SyhJEC4qhBbkCKbqFV4Ge4zmu5ziQuVbWxb/XwLZ+RIO7E8Q==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.122.0", - "@rolldown/pluginutils": "1.0.0-rc.11" + "@oxc-project/types": "=0.115.0", + "@rolldown/pluginutils": "1.0.0-rc.9" }, "bin": { "rolldown": "bin/cli.mjs" @@ -9884,21 +9111,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-rc.11", - "@rolldown/binding-darwin-arm64": "1.0.0-rc.11", - "@rolldown/binding-darwin-x64": "1.0.0-rc.11", - "@rolldown/binding-freebsd-x64": "1.0.0-rc.11", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.11", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.11", - "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.11", - "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.11", - "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.11", - "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.11", - "@rolldown/binding-linux-x64-musl": "1.0.0-rc.11", - "@rolldown/binding-openharmony-arm64": "1.0.0-rc.11", - "@rolldown/binding-wasm32-wasi": "1.0.0-rc.11", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.11", - "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.11" + "@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" } }, "node_modules/tsdown/node_modules/tinyexec": { @@ -9990,21 +9217,6 @@ "fsevents": "~2.3.3" } }, - "node_modules/tsx/node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -10033,16 +9245,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.57.2.tgz", - "integrity": "sha512-VEPQ0iPgWO/sBaZOU1xo4nuNdODVOajPnTIbog2GKYr31nIlZ0fWPoCQgGfF3ETyBl1vn63F/p50Um9Z4J8O8A==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.57.1.tgz", + "integrity": "sha512-fLvZWf+cAGw3tqMCYzGIU6yR8K+Y9NT2z23RwOjlNFF2HwSB3KhdEFI5lSBv8tNmFkkBShSjsCjzx1vahZfISA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.57.2", - "@typescript-eslint/parser": "8.57.2", - "@typescript-eslint/typescript-estree": "8.57.2", - "@typescript-eslint/utils": "8.57.2" + "@typescript-eslint/eslint-plugin": "8.57.1", + "@typescript-eslint/parser": "8.57.1", + "@typescript-eslint/typescript-estree": "8.57.1", + "@typescript-eslint/utils": "8.57.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -10056,13 +9268,6 @@ "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/uc.micro": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", - "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", - "dev": true, - "license": "MIT" - }, "node_modules/ufo": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", @@ -10102,9 +9307,9 @@ "license": "MIT" }, "node_modules/undici": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.6.tgz", - "integrity": "sha512-Xi4agocCbRzt0yYMZGMA6ApD7gvtUFaxm4ZmeacWI4cZxaF6C+8I8QfofC20NAePiB/IcvZmzkJ7XPa471AEtA==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.5.tgz", + "integrity": "sha512-3IWdCpjgxp15CbJnsi/Y9TCDE7HWVN19j1hmzVhoAkY/+CJx449tVxT5wZc1Gwg8J+P0LWvzlBzxYRnHJ+1i7Q==", "dev": true, "license": "MIT", "engines": { @@ -10118,26 +9323,6 @@ "devOptional": true, "license": "MIT" }, - "node_modules/unified": { - "version": "11.0.5", - "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", - "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "bail": "^2.0.0", - "devlop": "^1.0.0", - "extend": "^3.0.0", - "is-plain-obj": "^4.0.0", - "trough": "^2.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/unist-util-is": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", @@ -10166,22 +9351,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-remove": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-remove/-/unist-util-remove-4.0.0.tgz", - "integrity": "sha512-b4gokeGId57UVRX/eVKej5gXqGlc9+trkORhFJpu9raqZkZhU0zm8Doi05+HaiBsMEIJowL+2WtQ5ItjsngPXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/unist-util-stringify-position": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", @@ -10254,14 +9423,27 @@ "url": "https://github.com/sponsors/sxzz" } }, + "node_modules/unplugin-utils/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/unrun": { - "version": "0.2.33", - "resolved": "https://registry.npmjs.org/unrun/-/unrun-0.2.33.tgz", - "integrity": "sha512-urXTjZHOHS6lMnatQerLcBpcTsaKZYGuu9aSZ+HlNfCApkiINRbj7YecC9h9hdZroMT4WQ4KVyzHfBqHKuFX9Q==", + "version": "0.2.32", + "resolved": "https://registry.npmjs.org/unrun/-/unrun-0.2.32.tgz", + "integrity": "sha512-opd3z6791rf281JdByf0RdRQrpcc7WyzqittqIXodM/5meNWdTwrVxeyzbaCp4/Rgls/um14oUaif1gomO8YGg==", "dev": true, "license": "MIT", "dependencies": { - "rolldown": "1.0.0-rc.11" + "rolldown": "1.0.0-rc.9" }, "bin": { "unrun": "dist/cli.mjs" @@ -10281,10 +9463,20 @@ } } }, + "node_modules/unrun/node_modules/@oxc-project/types": { + "version": "0.115.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.115.0.tgz", + "integrity": "sha512-4n91DKnebUS4yjUHl2g3/b2T+IUdCfmoZGhmwsovZCDaJSs+QkVAM+0AqqTxHSsHfeiMuueT75cZaZcT/m0pSw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, "node_modules/unrun/node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.11.tgz", - "integrity": "sha512-SJ+/g+xNnOh6NqYxD0V3uVN4W3VfnrGsC9/hoglicgTNfABFG9JjISvkkU0dNY84MNHLWyOgxP9v9Y9pX4S7+A==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.9.tgz", + "integrity": "sha512-lcJL0bN5hpgJfSIz/8PIf02irmyL43P+j1pTCfbD1DbLkmGRuFIA4DD3B3ZOvGqG0XiVvRznbKtN0COQVaKUTg==", "cpu": [ "arm64" ], @@ -10299,9 +9491,9 @@ } }, "node_modules/unrun/node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.11.tgz", - "integrity": "sha512-7WQgR8SfOPwmDZGFkThUvsmd/nwAWv91oCO4I5LS7RKrssPZmOt7jONN0cW17ydGC1n/+puol1IpoieKqQidmg==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.9.tgz", + "integrity": "sha512-J7Zk3kLYFsLtuH6U+F4pS2sYVzac0qkjcO5QxHS7OS7yZu2LRs+IXo+uvJ/mvpyUljDJ3LROZPoQfgBIpCMhdQ==", "cpu": [ "arm64" ], @@ -10316,9 +9508,9 @@ } }, "node_modules/unrun/node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.11.tgz", - "integrity": "sha512-39Ks6UvIHq4rEogIfQBoBRusj0Q0nPVWIvqmwBLaT6aqQGIakHdESBVOPRRLacy4WwUPIx4ZKzfZ9PMW+IeyUQ==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.9.tgz", + "integrity": "sha512-iwtmmghy8nhfRGeNAIltcNXzD0QMNaaA5U/NyZc1Ia4bxrzFByNMDoppoC+hl7cDiUq5/1CnFthpT9n+UtfFyg==", "cpu": [ "x64" ], @@ -10333,9 +9525,9 @@ } }, "node_modules/unrun/node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.11.tgz", - "integrity": "sha512-jfsm0ZHfhiqrvWjJAmzsqiIFPz5e7mAoCOPBNTcNgkiid/LaFKiq92+0ojH+nmJmKYkre4t71BWXUZDNp7vsag==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.9.tgz", + "integrity": "sha512-DLFYI78SCiZr5VvdEplsVC2Vx53lnA4/Ga5C65iyldMVaErr86aiqCoNBLl92PXPfDtUYjUh+xFFor40ueNs4Q==", "cpu": [ "x64" ], @@ -10350,9 +9542,9 @@ } }, "node_modules/unrun/node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.11.tgz", - "integrity": "sha512-zjQaUtSyq1nVe3nxmlSCuR96T1LPlpvmJ0SZy0WJFEsV4kFbXcq2u68L4E6O0XeFj4aex9bEauqjW8UQBeAvfQ==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.9.tgz", + "integrity": "sha512-CsjTmTwd0Hri6iTw/DRMK7kOZ7FwAkrO4h8YWKoX/kcj833e4coqo2wzIFywtch/8Eb5enQ/lwLM7w6JX1W5RQ==", "cpu": [ "arm" ], @@ -10367,9 +9559,9 @@ } }, "node_modules/unrun/node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.11.tgz", - "integrity": "sha512-WMW1yE6IOnehTcFE9eipFkm3XN63zypWlrJQ2iF7NrQ9b2LDRjumFoOGJE8RJJTJCTBAdmLMnJ8uVitACUUo1Q==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.9.tgz", + "integrity": "sha512-2x9O2JbSPxpxMDhP9Z74mahAStibTlrBMW0520+epJH5sac7/LwZW5Bmg/E6CXuEF53JJFW509uP+lSedaUNxg==", "cpu": [ "arm64" ], @@ -10384,9 +9576,9 @@ } }, "node_modules/unrun/node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.11.tgz", - "integrity": "sha512-jfndI9tsfm4APzjNt6QdBkYwre5lRPUgHeDHoI7ydKUuJvz3lZeCfMsI56BZj+7BYqiKsJm7cfd/6KYV7ubrBg==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.9.tgz", + "integrity": "sha512-JA1QRW31ogheAIRhIg9tjMfsYbglXXYGNPLdPEYrwFxdbkQCAzvpSCSHCDWNl4hTtrol8WeboCSEpjdZK8qrCg==", "cpu": [ "arm64" ], @@ -10401,9 +9593,9 @@ } }, "node_modules/unrun/node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.11.tgz", - "integrity": "sha512-ZlFgw46NOAGMgcdvdYwAGu2Q+SLFA9LzbJLW+iyMOJyhj5wk6P3KEE9Gct4xWwSzFoPI7JCdYmYMzVtlgQ+zfw==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.9.tgz", + "integrity": "sha512-aOKU9dJheda8Kj8Y3w9gnt9QFOO+qKPAl8SWd7JPHP+Cu0EuDAE5wokQubLzIDQWg2myXq2XhTpOVS07qqvT+w==", "cpu": [ "ppc64" ], @@ -10418,9 +9610,9 @@ } }, "node_modules/unrun/node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.11.tgz", - "integrity": "sha512-hIOYmuT6ofM4K04XAZd3OzMySEO4K0/nc9+jmNcxNAxRi6c5UWpqfw3KMFV4MVFWL+jQsSh+bGw2VqmaPMTLyw==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.9.tgz", + "integrity": "sha512-OalO94fqj7IWRn3VdXWty75jC5dk4C197AWEuMhIpvVv2lw9fiPhud0+bW2ctCxb3YoBZor71QHbY+9/WToadA==", "cpu": [ "s390x" ], @@ -10435,9 +9627,9 @@ } }, "node_modules/unrun/node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.11.tgz", - "integrity": "sha512-qXBQQO9OvkjjQPLdUVr7Nr2t3QTZI7s4KZtfw7HzBgjbmAPSFwSv4rmET9lLSgq3rH/ndA3ngv3Qb8l2njoPNA==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.9.tgz", + "integrity": "sha512-cVEl1vZtBsBZna3YMjGXNvnYYrOJ7RzuWvZU0ffvJUexWkukMaDuGhUXn0rjnV0ptzGVkvc+vW9Yqy6h8YX4pg==", "cpu": [ "x64" ], @@ -10452,9 +9644,9 @@ } }, "node_modules/unrun/node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.11.tgz", - "integrity": "sha512-/tpFfoSTzUkH9LPY+cYbqZBDyyX62w5fICq9qzsHLL8uTI6BHip3Q9Uzft0wylk/i8OOwKik8OxW+QAhDmzwmg==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.9.tgz", + "integrity": "sha512-UzYnKCIIc4heAKgI4PZ3dfBGUZefGCJ1TPDuLHoCzgrMYPb5Rv6TLFuYtyM4rWyHM7hymNdsg5ik2C+UD9VDbA==", "cpu": [ "x64" ], @@ -10469,9 +9661,9 @@ } }, "node_modules/unrun/node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.11.tgz", - "integrity": "sha512-mcp3Rio2w72IvdZG0oQ4bM2c2oumtwHfUfKncUM6zGgz0KgPz4YmDPQfnXEiY5t3+KD/i8HG2rOB/LxdmieK2g==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.9.tgz", + "integrity": "sha512-+6zoiF+RRyf5cdlFQP7nm58mq7+/2PFaY2DNQeD4B87N36JzfF/l9mdBkkmTvSYcYPE8tMh/o3cRlsx1ldLfog==", "cpu": [ "arm64" ], @@ -10486,9 +9678,9 @@ } }, "node_modules/unrun/node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.11.tgz", - "integrity": "sha512-LXk5Hii1Ph9asuGRjBuz8TUxdc1lWzB7nyfdoRgI0WGPZKmCxvlKk8KfYysqtr4MfGElu/f/pEQRh8fcEgkrWw==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.9.tgz", + "integrity": "sha512-rgFN6sA/dyebil3YTlL2evvi/M+ivhfnyxec7AccTpRPccno/rPoNlqybEZQBkcbZu8Hy+eqNJCqfBR8P7Pg8g==", "cpu": [ "wasm32" ], @@ -10503,9 +9695,9 @@ } }, "node_modules/unrun/node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.11.tgz", - "integrity": "sha512-dDwf5otnx0XgRY1yqxOC4ITizcdzS/8cQ3goOWv3jFAo4F+xQYni+hnMuO6+LssHHdJW7+OCVL3CoU4ycnh35Q==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.9.tgz", + "integrity": "sha512-lHVNUG/8nlF1IQk1C0Ci574qKYyty2goMiPlRqkC5R+3LkXDkL5Dhx8ytbxq35m+pkHVIvIxviD+TWLdfeuadA==", "cpu": [ "arm64" ], @@ -10520,9 +9712,9 @@ } }, "node_modules/unrun/node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.11.tgz", - "integrity": "sha512-LN4/skhSggybX71ews7dAj6r2geaMJfm3kMbK2KhFMg9B10AZXnKoLCVVgzhMHL0S+aKtr4p8QbAW8k+w95bAA==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.9.tgz", + "integrity": "sha512-G0oA4+w1iY5AGi5HcDTxWsoxF509hrFIPB2rduV5aDqS9FtDg1CAfa7V34qImbjfhIcA8C+RekocJZA96EarwQ==", "cpu": [ "x64" ], @@ -10537,21 +9729,21 @@ } }, "node_modules/unrun/node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.11.tgz", - "integrity": "sha512-xQO9vbwBecJRv9EUcQ/y0dzSTJgA7Q6UVN7xp6B81+tBGSLVAK03yJ9NkJaUA7JFD91kbjxRSC/mDnmvXzbHoQ==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.9.tgz", + "integrity": "sha512-w6oiRWgEBl04QkFZgmW+jnU1EC9b57Oihi2ot3HNWIQRqgHp5PnYDia5iZ5FF7rpa4EQdiqMDXjlqKGXBhsoXw==", "dev": true, "license": "MIT" }, "node_modules/unrun/node_modules/rolldown": { - "version": "1.0.0-rc.11", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.11.tgz", - "integrity": "sha512-NRjoKMusSjfRbSYiH3VSumlkgFe7kYAa3pzVOsVYVFY3zb5d7nS+a3KGQ7hJKXuYWbzJKPVQ9Wxq2UvyK+ENpw==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.9.tgz", + "integrity": "sha512-9EbgWge7ZH+yqb4d2EnELAntgPTWbfL8ajiTW+SyhJEC4qhBbkCKbqFV4Ge4zmu5ziQuVbWxb/XwLZ+RIO7E8Q==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.122.0", - "@rolldown/pluginutils": "1.0.0-rc.11" + "@oxc-project/types": "=0.115.0", + "@rolldown/pluginutils": "1.0.0-rc.9" }, "bin": { "rolldown": "bin/cli.mjs" @@ -10560,21 +9752,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-rc.11", - "@rolldown/binding-darwin-arm64": "1.0.0-rc.11", - "@rolldown/binding-darwin-x64": "1.0.0-rc.11", - "@rolldown/binding-freebsd-x64": "1.0.0-rc.11", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.11", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.11", - "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.11", - "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.11", - "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.11", - "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.11", - "@rolldown/binding-linux-x64-musl": "1.0.0-rc.11", - "@rolldown/binding-openharmony-arm64": "1.0.0-rc.11", - "@rolldown/binding-wasm32-wasi": "1.0.0-rc.11", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.11", - "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.11" + "@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" } }, "node_modules/update-browserslist-db": { @@ -10671,16 +9863,16 @@ } }, "node_modules/vite": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.3.tgz", - "integrity": "sha512-B9ifbFudT1TFhfltfaIPgjo9Z3mDynBTJSUYxTjOQruf/zHH+ezCQKcoqO+h7a9Pw9Nm/OtlXAiGT1axBgwqrQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.1.tgz", + "integrity": "sha512-wt+Z2qIhfFt85uiyRt5LPU4oVEJBXj8hZNWKeqFG4gRG/0RaRGJ7njQCwzFVjO+v4+Ipmf5CY7VdmZRAYYBPHw==", "license": "MIT", "peer": true, "dependencies": { "lightningcss": "^1.32.0", - "picomatch": "^4.0.4", + "picomatch": "^4.0.3", "postcss": "^8.5.8", - "rolldown": "1.0.0-rc.12", + "rolldown": "1.0.0-rc.10", "tinyglobby": "^0.2.15" }, "bin": { @@ -10748,19 +9940,17 @@ } } }, - "node_modules/vite/node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], "peer": true, "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/vitepress": { @@ -10805,35 +9995,6 @@ } } }, - "node_modules/vitepress-plugin-llms": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/vitepress-plugin-llms/-/vitepress-plugin-llms-1.12.0.tgz", - "integrity": "sha512-zuzL7a8UJuGl46le5cAy/QxKMGlpSylcsLjDDn6BYPc1u+eP3nzoQk9ne9XFBqrE7exoJlIYJELVN8HMgYlFKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "gray-matter": "^4.0.3", - "markdown-it": "^14.1.0", - "markdown-title": "^1.0.2", - "mdast-util-from-markdown": "^2.0.3", - "millify": "^6.1.0", - "minimatch": "^10.2.4", - "path-to-regexp": "^6.3.0", - "picocolors": "^1.1.1", - "pretty-bytes": "^7.1.0", - "remark": "^15.0.1", - "remark-frontmatter": "^5.0.0", - "tokenx": "^1.3.0", - "unist-util-remove": "^4.0.0", - "unist-util-visit": "^5.1.0" - }, - "engines": { - "node": ">=18.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/okineadev" - } - }, "node_modules/vitepress/node_modules/@esbuild/aix-ppc64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", @@ -11278,21 +10439,6 @@ "@esbuild/win32-x64": "0.21.5" } }, - "node_modules/vitepress/node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/vitepress/node_modules/vite": { "version": "5.4.21", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", @@ -11438,17 +10584,17 @@ "license": "MIT" }, "node_modules/vue": { - "version": "3.5.31", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.31.tgz", - "integrity": "sha512-iV/sU9SzOlmA/0tygSmjkEN6Jbs3nPoIPFhCMLD2STrjgOU8DX7ZtzMhg4ahVwf5Rp9KoFzcXeB1ZrVbLBp5/Q==", + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.30.tgz", + "integrity": "sha512-hTHLc6VNZyzzEH/l7PFGjpcTvUgiaPK5mdLkbjrTeWSRcEfxFrv56g/XckIYlE9ckuobsdwqd5mk2g1sBkMewg==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.31", - "@vue/compiler-sfc": "3.5.31", - "@vue/runtime-dom": "3.5.31", - "@vue/server-renderer": "3.5.31", - "@vue/shared": "3.5.31" + "@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/shared": "3.5.30" }, "peerDependencies": { "typescript": "*" @@ -11647,11 +10793,8 @@ }, "packages/gea": { "name": "@geajs/core", - "version": "1.0.7", + "version": "1.0.5", "license": "MIT", - "dependencies": { - "@types/react": "^19.0.0" - }, "devDependencies": { "@types/node": "^25.5.0", "c8": "^11.0.0", @@ -11675,22 +10818,21 @@ "@geajs/core": "^1.0.0" } }, - "packages/gea-ssr": { - "name": "@geajs/ssr", + "packages/gea-ssg": { + "name": "@geajs/ssg", "version": "1.0.0", "license": "MIT", "dependencies": { - "devalue": "^5.6.4" + "gray-matter": "^4.0.3", + "marked": "^17.0.5" }, "devDependencies": { - "@types/node": "^25.5.0", - "jsdom": "^29.0.0", "tsup": "^8.5.1", "tsx": "^4.21.0", "typescript": "~5.8.0" }, "peerDependencies": { - "@geajs/core": "*", + "@geajs/core": "^1.0.0", "vite": "^8.0.0" }, "peerDependenciesMeta": { @@ -11699,8 +10841,10 @@ } } }, - "packages/gea-ssr/node_modules/typescript": { + "packages/gea-ssg/node_modules/typescript": { "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -11711,6 +10855,28 @@ "node": ">=14.17" } }, + "packages/gea-ssr": { + "name": "@geajs/ssr", + "version": "1.0.0", + "extraneous": true, + "license": "MIT", + "devDependencies": { + "@types/node": "^25.5.0", + "jsdom": "^29.0.0", + "tsup": "^8.5.1", + "tsx": "^4.21.0", + "typescript": "~5.8.0" + }, + "peerDependencies": { + "@geajs/core": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, "packages/gea-tools": { "version": "1.0.0", "license": "MIT", @@ -11743,7 +10909,7 @@ }, "packages/gea-ui": { "name": "@geajs/ui", - "version": "0.1.3", + "version": "0.1.2", "license": "MIT", "dependencies": { "@zag-js/accordion": "^1.37.0", @@ -11778,7 +10944,6 @@ }, "devDependencies": { "@playwright/test": "^1.58.2", - "@types/react": "^19.0.0", "autoprefixer": "^10.4.27", "postcss": "^8.5.8", "prismjs": "^1.30.0", @@ -11788,22 +10953,7 @@ "typescript": "^5.9.3" }, "peerDependencies": { - "@geajs/core": "^1.0.6" - } - }, - "packages/gea-ui/node_modules/@types/react": { - "version": "19.2.14", - "dev": true, - "license": "MIT", - "dependencies": { - "csstype": "^3.2.2" - } - }, - "packages/gea/node_modules/@types/react": { - "version": "19.2.14", - "license": "MIT", - "dependencies": { - "csstype": "^3.2.2" + "@geajs/core": "^1.0.3" } }, "packages/gea/node_modules/typescript": { @@ -11820,7 +10970,7 @@ }, "packages/vite-plugin-gea": { "name": "@geajs/vite-plugin", - "version": "1.0.7", + "version": "1.0.5", "license": "MIT", "dependencies": { "@acemir/cssom": "^0.9.31", diff --git a/packages/gea-ssg/README.md b/packages/gea-ssg/README.md new file mode 100644 index 0000000..67bf847 --- /dev/null +++ b/packages/gea-ssg/README.md @@ -0,0 +1,168 @@ +# @geajs/ssg + +[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/dashersw/gea/blob/master/LICENSE) + +Static site generation plugin for [Gea](https://www.npmjs.com/package/@geajs/core). Pre-renders your routes to static HTML at build time — zero client JavaScript, instant page loads, SEO-friendly output. + +## Installation + +```bash +npm install -D @geajs/ssg +``` + +Requires `@geajs/core` ^1.0.0 and `vite` ^8.0.0 as peer dependencies. + +## Configuration + +```ts +// vite.config.ts +import { defineConfig } from 'vite' +import { geaPlugin } from '@geajs/vite-plugin' +import { geaSSG } from '@geajs/ssg/vite' + +export default defineConfig({ + plugins: [ + geaPlugin(), + geaSSG({ + contentDir: 'src/content', + sitemap: { hostname: 'https://example.com' }, + }), + ], +}) +``` + +Your `src/App.tsx` must export `routes` (a `RouteMap`) and `App` (or a default export): + +```tsx +export const routes = { + '/': Home, + '/about': About, + '/blog': Blog, + '/blog/:slug': { component: BlogPost, content: 'blog' }, +} + +export default class App extends Component { + template() { + return ( +
+ + +
+ ) + } +} +``` + +Run `vite build` and every route is pre-rendered to `dist/`. + +## Features + +### Static Routes + +Every path in your `RouteMap` is rendered to an `index.html` file: + +``` +/ → dist/index.html +/about → dist/about/index.html +/contact → dist/contact/index.html +``` + +### Markdown Content + +Load markdown files with YAML frontmatter using the `ssg` accessor: + +```tsx +import { ssg } from '@geajs/ssg' + +class Blog extends Component { + posts = ssg.content('blog', { + sort: (a, b) => new Date(b.frontmatter.date).getTime() - new Date(a.frontmatter.date).getTime(), + }) + + template() { + return + } +} +``` + +Each file has: `slug`, `frontmatter`, `content` (raw md), `html` (rendered). + +### Dynamic Routes with Content + +Parameterized routes can auto-generate pages from content files. Each `.md` file's slug becomes a route parameter: + +```tsx +// Route config — one page per markdown file in content/blog/ +export const routes = { + '/blog/:slug': { component: BlogPost, content: 'blog' }, +} + +// Component reads content by slug +class BlogPost extends Component { + template(props) { + const post = ssg.file('blog', props?.slug) + return post ?

{post.frontmatter.title}

{post.html}
: '' + } +} +``` + +### Dynamic Routes with Explicit Paths + +For non-content parameterized routes, provide explicit paths: + +```tsx +export const routes = { + '/user/:id': { + component: UserPage, + paths: [{ params: { id: '1' } }, { params: { id: '2' } }], + }, +} +``` + +### Layouts and Outlets + +Route groups with `layout` components are rendered with proper nesting — the layout wraps the page content through `Outlet`. + +### Sitemap + +Pass `sitemap: { hostname: 'https://example.com' }` to generate a `sitemap.xml` with all rendered pages. + +### Active Link State + +`Link` components automatically get `data-active` attributes in static output, matching the current route — no client JavaScript needed. + +### Dev Mode + +In dev mode (`vite dev`), content is preloaded and injected into the page so `ssg.content()` and `ssg.file()` work without a build step. Content file changes trigger automatic page reload. + +## Plugin Options + +| Option | Type | Default | Description | +| --- | --- | --- | --- | +| `contentDir` | `string` | — | Content directory for markdown files (relative to project root) | +| `sitemap` | `boolean \| SitemapOptions` | — | Generate sitemap.xml | +| `appElementId` | `string` | `'app'` | Mount element id in index.html | +| `routes` | `RouteMap` | — | Override routes (default: from `src/App.tsx`) | +| `app` | `Component` | — | Override app component (default: from `src/App.tsx`) | +| `concurrency` | `number` | `4` | Max concurrent page renders | +| `onBeforeRender` | `function` | — | Hook called before each page render | +| `onAfterRender` | `function` | — | Hook called after render, can transform HTML | +| `onRenderError` | `function` | — | Custom error handler per route | + +## Programmatic API + +```ts +import { ssg, generate, renderToString, crawlRoutes, parseShell, preloadContent } from '@geajs/ssg' +``` + +All exports are available from the main entry point for custom build pipelines. + +## Related Packages + +- **[@geajs/core](https://www.npmjs.com/package/@geajs/core)** — Core framework +- **[@geajs/vite-plugin](https://www.npmjs.com/package/@geajs/vite-plugin)** — Vite plugin for compile-time JSX +- **[create-gea](https://www.npmjs.com/package/create-gea)** — Project scaffolder + +## License + +[MIT](LICENSE) — Copyright (c) 2017-present Armagan Amcalar diff --git a/packages/gea-ssg/package.json b/packages/gea-ssg/package.json new file mode 100644 index 0000000..e400e67 --- /dev/null +++ b/packages/gea-ssg/package.json @@ -0,0 +1,71 @@ +{ + "name": "@geajs/ssg", + "version": "1.0.0", + "description": "Static site generation for Gea framework", + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "source": "./src/index.ts", + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + }, + "./vite": { + "source": "./src/vite-plugin.ts", + "types": "./dist/vite-plugin.d.ts", + "import": "./dist/vite-plugin.js" + }, + "./client": { + "source": "./src/client.ts", + "types": "./dist/client.d.ts", + "import": "./dist/client.js" + } + }, + "files": [ + "dist" + ], + "publishConfig": { + "access": "public" + }, + "sideEffects": false, + "scripts": { + "build": "tsup src/index.ts src/vite-plugin.ts src/client.ts --format esm --dts --clean --external vite --external @geajs/core", + "test": "tsx --conditions source --test 'tests/**/*.test.ts'" + }, + "keywords": [ + "gea", + "ssg", + "static-site-generation", + "vite-plugin", + "pre-rendering" + ], + "author": "Armagan Amcalar ", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/dashersw/gea.git" + }, + "bugs": { + "url": "https://github.com/dashersw/gea/issues" + }, + "homepage": "https://github.com/dashersw/gea#readme", + "peerDependencies": { + "@geajs/core": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + }, + "devDependencies": { + "tsup": "^8.5.1", + "tsx": "^4.21.0", + "typescript": "~5.8.0" + }, + "dependencies": { + "gray-matter": "^4.0.3", + "marked": "^17.0.5" + } +} diff --git a/packages/gea-ssg/src/client.ts b/packages/gea-ssg/src/client.ts new file mode 100644 index 0000000..c97a312 --- /dev/null +++ b/packages/gea-ssg/src/client.ts @@ -0,0 +1,30 @@ +export interface ContentFile> { + slug: string + frontmatter: T + content: string + html: string +} + +function getData(): Record { + const g = globalThis as any + if (g.__SSG_CONTENT__) { + return g.__SSG_CONTENT__ + } + return {} +} + +export const ssg = { + content>( + subdir: string, + options?: { sort?: (a: ContentFile, b: ContentFile) => number }, + ): ContentFile[] { + const items = [...(getData()[subdir] || [])] as ContentFile[] + if (options?.sort) items.sort(options.sort) + return items + }, + + file>(subdir: string, slug: string): ContentFile | null { + const items = (getData()[subdir] || []) as ContentFile[] + return items.find((f) => f.slug === slug) || null + }, +} diff --git a/packages/gea-ssg/src/content.ts b/packages/gea-ssg/src/content.ts new file mode 100644 index 0000000..1d25e8d --- /dev/null +++ b/packages/gea-ssg/src/content.ts @@ -0,0 +1,93 @@ +const cache = new Map() + +export interface ContentFile> { + slug: string + frontmatter: T + content: string + html: string +} + +export async function preloadContent(rootDir: string): Promise { + const { readdir, readFile } = await import('node:fs/promises') + const { join, basename, extname } = await import('node:path') + const matter = (await import('gray-matter')).default + const { marked } = await import('marked') + + cache.clear() + + const entries = await readdir(rootDir, { withFileTypes: true }) + for (const entry of entries) { + if (!entry.isDirectory()) continue + + const subdir = entry.name + const dirPath = join(rootDir, subdir) + const files = (await readdir(dirPath)).filter((f) => f.endsWith('.md')).sort() + + const items: ContentFile[] = [] + for (const file of files) { + const raw = await readFile(join(dirPath, file), 'utf-8') + const { data, content } = matter(raw) + const html = await marked(content.trim()) + + for (const [key, value] of Object.entries(data)) { + if (value instanceof Date) { + data[key] = value.toISOString() + } + } + + items.push({ + slug: basename(file, extname(file)), + frontmatter: data, + content: content.trim(), + html, + }) + } + + cache.set(subdir, items) + } +} + +export function clearContentCache(): void { + cache.clear() +} + +export function serializeContentCache(): string { + const obj: Record = {} + for (const [key, value] of cache) { + obj[key] = value + } + return JSON.stringify(obj) +} + +export function getContentSlugs(subdir: string): string[] { + return (cache.get(subdir) || []).map((f) => f.slug) +} + +export const ssg = { + content>( + subdir: string, + options?: { sort?: (a: ContentFile, b: ContentFile) => number }, + ): ContentFile[] { + const g = globalThis as any + if (g.__SSG_CONTENT__) { + const items = [...(g.__SSG_CONTENT__[subdir] || [])] as ContentFile[] + if (options?.sort) items.sort(options.sort) + return items + } + + const items = [...(cache.get(subdir) || [])] as ContentFile[] + if (options?.sort) items.sort(options.sort) + return items + }, + + file>(subdir: string, slug: string): ContentFile | null { + const g = globalThis as any + if (g.__SSG_CONTENT__) { + const items = (g.__SSG_CONTENT__[subdir] || []) as ContentFile[] + return items.find((f) => f.slug === slug) || null + } + + const items = (cache.get(subdir) || []) as ContentFile[] + return items.find((f) => f.slug === slug) || null + }, +} diff --git a/packages/gea-ssg/src/crawl.ts b/packages/gea-ssg/src/crawl.ts new file mode 100644 index 0000000..d9144df --- /dev/null +++ b/packages/gea-ssg/src/crawl.ts @@ -0,0 +1,138 @@ +import type { RouteMap, RouteEntry, RouteGroupConfig } from '@geajs/core' +import type { StaticRoute } from './types' +import { getContentSlugs } from './content' + +export async function crawlRoutes(routes: RouteMap, basePath: string = ''): Promise { + const result: StaticRoute[] = [] + + for (const [pattern, entry] of Object.entries(routes)) { + await collectPaths(pattern, entry, basePath, [], result) + } + + return result +} + +async function collectPaths( + pattern: string, + entry: RouteEntry, + basePath: string, + parentLayouts: any[], + result: StaticRoute[], +): Promise { + const fullPath = normalizePath(basePath + pattern) + + if (typeof entry === 'string') return + + if (isRedirectConfig(entry)) return + + if (isRouteGroupConfig(entry)) { + const layouts = entry.layout ? [...parentLayouts, entry.layout] : parentLayouts + + for (const [childPattern, childEntry] of Object.entries(entry.children)) { + await collectPaths(childPattern, childEntry, fullPath, layouts, result) + } + return + } + + if (isSSGRouteConfig(entry)) { + if ((entry as any).client === true) return + + const component = (entry as any).component + + if ((entry as any).content) { + const subdir = (entry as any).content as string + const slugs = getContentSlugs(subdir) + const paramName = extractParamName(pattern) + + if (!paramName) { + console.warn(`[gea-ssg] Route "${fullPath}" has content but no param in pattern, skipping.`) + return + } + + if (!slugs.length) { + console.warn(`[gea-ssg] No content found for "${subdir}" — route "${fullPath}" will have no pages.`) + return + } + + for (const slug of slugs) { + const params = { [paramName]: slug } + result.push({ + path: resolveParams(fullPath, params), + component, + layouts: parentLayouts, + params, + }) + } + return + } + + if ((entry as any).paths) { + const paths = (entry as any).paths as Array<{ params: Record }> + for (const pathEntry of paths) { + result.push({ + path: resolveParams(fullPath, pathEntry.params), + component, + layouts: parentLayouts, + params: pathEntry.params, + }) + } + return + } + + if (pattern === '*') return + + result.push({ path: fullPath, component, layouts: parentLayouts, params: {} }) + return + } + + let component = entry + if (isLazyComponent(entry)) { + const mod = await (entry as () => Promise)() + component = 'default' in mod ? mod.default : mod + } + + if (pattern.includes(':') || pattern === '*') return + + result.push({ + path: fullPath, + component, + layouts: parentLayouts, + params: {}, + }) +} + +function extractParamName(pattern: string): string | null { + const match = pattern.match(/:(\w+)/) + return match ? match[1] : null +} + +function resolveParams(path: string, params: Record): string { + return Object.entries(params).reduce((p, [key, value]) => p.replace(`:${key}`, value), path) +} + +function normalizePath(path: string): string { + const cleaned = '/' + path.replace(/\/+/g, '/').replace(/^\/|\/$/g, '') + return cleaned === '/' ? '/' : cleaned.replace(/\/$/, '') +} + +function isRouteGroupConfig(entry: RouteEntry): entry is RouteGroupConfig { + return typeof entry === 'object' && entry !== null && 'children' in entry +} + +function isRedirectConfig(entry: RouteEntry): boolean { + return typeof entry === 'object' && entry !== null && 'redirect' in entry +} + +function isLazyComponent(entry: RouteEntry): boolean { + return typeof entry === 'function' && !(entry as any).prototype +} + +function isSSGRouteConfig(entry: RouteEntry): boolean { + return ( + typeof entry === 'object' && + entry !== null && + 'component' in entry && + !('children' in entry) && + !('redirect' in entry) + ) +} diff --git a/packages/gea-ssg/src/generate.ts b/packages/gea-ssg/src/generate.ts new file mode 100644 index 0000000..bc83383 --- /dev/null +++ b/packages/gea-ssg/src/generate.ts @@ -0,0 +1,190 @@ +import { writeFile, mkdir, readFile } from 'node:fs/promises' +import { join, dirname, resolve, relative } from 'node:path' + +import { RouterView, Link } from '@geajs/core' +import { renderToString } from './render' +import { crawlRoutes } from './crawl' +import { parseShell, injectIntoShell, stripScripts } from './shell' +import { preloadContent, clearContentCache, serializeContentCache } from './content' +import type { SSGOptions, GenerateResult, GeneratedPage, StaticRoute } from './types' + +export async function generate(options: SSGOptions): Promise { + const { + routes, + shell: shellPath, + outDir = 'dist', + appElementId = 'app', + onBeforeRender, + onAfterRender, + onRenderError, + concurrency = 4, + sitemap, + } = options + + const startTime = performance.now() + const pages: GeneratedPage[] = [] + const errors: Array<{ path: string; error: Error }> = [] + + try { + if (options.contentDir) { + await preloadContent(options.contentDir) + ;(globalThis as any).__SSG_CONTENT__ = JSON.parse(serializeContentCache()) + } + + const shellHtml = await readFile(shellPath, 'utf-8') + const shellParts = parseShell(shellHtml, appElementId) + + const staticRoutes = await crawlRoutes(routes) + + if (!staticRoutes.length) { + console.warn('[gea-ssg] No static routes found.') + return { pages, duration: performance.now() - startTime, errors } + } + + const absOut = resolve(outDir) + const seenPaths = new Set() + for (const route of staticRoutes) { + const target = resolve(join(outDir, route.path, 'index.html')) + const rel = relative(absOut, target) + if (rel.startsWith('..') || resolve(rel) === rel) { + throw new Error(`[gea-ssg] Path traversal detected: "${route.path}" escapes outDir.`) + } + if (seenPaths.has(route.path)) { + console.warn(`[gea-ssg] Duplicate path "${route.path}" — later render will overwrite.`) + } + seenPaths.add(route.path) + } + + console.log(`[gea-ssg] Found ${staticRoutes.length} routes, rendering...`) + + const renderRoute = async (route: StaticRoute, index: number): Promise => { + try { + if (onBeforeRender) { + await onBeforeRender({ + path: route.path, + params: route.params, + component: route.component, + layouts: route.layouts, + }) + } + + let html: string + try { + RouterView._ssgRoute = { + component: route.component, + layouts: route.layouts, + params: route.params, + } + Link._ssgCurrentPath = route.path + html = renderToString(options.app, undefined, { seed: index }) + } finally { + RouterView._ssgRoute = null + Link._ssgCurrentPath = null + } + + let fullHtml = stripScripts(injectIntoShell(shellParts, html)) + + if (onAfterRender) { + const transformed = await onAfterRender( + { + path: route.path, + params: route.params, + component: route.component, + layouts: route.layouts, + }, + fullHtml, + ) + if (transformed) fullHtml = transformed + } + + const outputPath = getOutputPath(route.path, outDir) + await mkdir(dirname(outputPath), { recursive: true }) + await writeFile(outputPath, fullHtml, 'utf-8') + + pages.push({ + path: route.path, + outputPath, + size: Buffer.byteLength(fullHtml, 'utf-8'), + }) + } catch (error) { + const err = error as Error + errors.push({ path: route.path, error: err }) + if (onRenderError) { + onRenderError(route.path, err) + } else { + console.error(`[gea-ssg] Render error: ${route.path}`, err.message) + } + } + } + + await runWithConcurrency(staticRoutes, renderRoute, concurrency) + + if (sitemap) { + const sitemapOpts = typeof sitemap === 'boolean' ? { hostname: 'https://example.com' } : sitemap + await generateSitemap(pages, sitemapOpts, outDir) + } + + const duration = performance.now() - startTime + console.log(`[gea-ssg] ✓ ${pages.length} pages generated (${errors.length} errors), ${Math.round(duration)}ms`) + + return { pages, duration, errors } + } finally { + clearContentCache() + delete (globalThis as any).__SSG_CONTENT__ + } +} + +function getOutputPath(routePath: string, outDir: string): string { + if (routePath === '/' || routePath === '') { + return join(outDir, 'index.html') + } + return join(outDir, routePath, 'index.html') +} + +async function runWithConcurrency( + items: T[], + fn: (item: T, index: number) => Promise, + limit: number, +): Promise { + const executing = new Set>() + + for (let i = 0; i < items.length; i++) { + const p = fn(items[i], i).then(() => { + executing.delete(p) + }) + executing.add(p) + + if (executing.size >= limit) { + await Promise.race(executing) + } + } + + await Promise.all(executing) +} + +async function generateSitemap( + pages: GeneratedPage[], + options: { hostname: string; changefreq?: string; priority?: number; exclude?: string[] }, + outDir: string, +): Promise { + const { hostname, changefreq = 'weekly', priority = 0.8, exclude = [] } = options + + const urls = pages + .filter((p) => !exclude.includes(p.path)) + .map( + (p) => ` + ${hostname}${p.path} + ${changefreq} + ${priority} + `, + ) + .join('\n') + + const xml = ` + +${urls} +` + + await mkdir(outDir, { recursive: true }) + await writeFile(join(outDir, 'sitemap.xml'), xml, 'utf-8') +} diff --git a/packages/gea-ssg/src/index.ts b/packages/gea-ssg/src/index.ts new file mode 100644 index 0000000..da92602 --- /dev/null +++ b/packages/gea-ssg/src/index.ts @@ -0,0 +1,24 @@ +export { renderToString } from './render' +export type { RenderOptions } from './render' + +export { crawlRoutes } from './crawl' + +export { generate } from './generate' + +export { parseShell, injectIntoShell, stripScripts } from './shell' +export type { ShellParts } from './shell' + +export { ssg, preloadContent, clearContentCache, serializeContentCache, getContentSlugs } from './content' +export type { ContentFile } from './content' + +export { geaSSG } from './vite-plugin' + +export type { + SSGOptions, + SSGPluginOptions, + StaticRoute, + RenderContext, + SitemapOptions, + GenerateResult, + GeneratedPage, +} from './types' diff --git a/packages/gea-ssg/src/render.ts b/packages/gea-ssg/src/render.ts new file mode 100644 index 0000000..beebe4f --- /dev/null +++ b/packages/gea-ssg/src/render.ts @@ -0,0 +1,37 @@ +import { resetUidCounter, Component } from '@geajs/core' + +export interface RenderOptions { + seed?: number + onRenderError?: (error: Error) => void +} + +export function renderToString( + ComponentClass: new (props?: any) => any, + props?: Record, + options: RenderOptions = {}, +): string { + const { seed = 0, onRenderError } = options + + resetUidCounter(seed) + Component._ssgMode = true + + let instance: any = null + + try { + instance = new ComponentClass(props) + return String(instance.template(instance.props)).trim() + } catch (error) { + if (onRenderError) { + onRenderError(error as Error) + return '' + } + throw error + } finally { + Component._ssgMode = false + if (instance && typeof instance.dispose === 'function') { + try { + instance.dispose() + } catch {} + } + } +} diff --git a/packages/gea-ssg/src/shell.ts b/packages/gea-ssg/src/shell.ts new file mode 100644 index 0000000..960eda9 --- /dev/null +++ b/packages/gea-ssg/src/shell.ts @@ -0,0 +1,54 @@ +export interface ShellParts { + before: string + after: string + headEnd: number +} + +export function parseShell(html: string, appElementId: string = 'app'): ShellParts { + const openTagRegex = new RegExp(`(<\\s*div[^>]*\\bid\\s*=\\s*["']${appElementId}["'][^>]*>)`, 'i') + const match = html.match(openTagRegex) + + if (!match || match.index === undefined) { + throw new Error(`[gea-ssg]
not found in shell HTML.`) + } + + const openTagEnd = match.index + match[0].length + const closeIndex = html.indexOf('
', openTagEnd) + + if (closeIndex === -1) { + throw new Error(`[gea-ssg] Closing not found for
.`) + } + + const before = html.slice(0, openTagEnd) + const after = html.slice(closeIndex) + + const headEnd = html.toLowerCase().indexOf('') + + return { before, after, headEnd } +} + +export function injectIntoShell(shell: ShellParts, renderedHtml: string, headTags?: string): string { + let result = shell.before + renderedHtml + shell.after + + if (headTags && shell.headEnd !== -1) { + const headInsertPos = result.toLowerCase().indexOf('') + if (headInsertPos !== -1) { + result = result.slice(0, headInsertPos) + headTags + result.slice(headInsertPos) + } + } + + return result +} + +export function stripScripts(html: string): string { + return html.replace(/]*)>[\s\S]*?<\/script>/gi, (_match, attrs: string) => { + const typeMatch = attrs.match(/type\s*=\s*["']([^"']+)["']/i) + if (typeMatch) { + const type = typeMatch[1].toLowerCase() + if (type !== 'module' && type !== 'text/javascript' && type !== 'application/javascript') { + return _match + } + } + return '' + }) +} diff --git a/packages/gea-ssg/src/types.ts b/packages/gea-ssg/src/types.ts new file mode 100644 index 0000000..16f52b3 --- /dev/null +++ b/packages/gea-ssg/src/types.ts @@ -0,0 +1,53 @@ +export interface SSGOptions { + routes: Record + app: new (props?: any) => any + shell: string + outDir?: string + appElementId?: string + contentDir?: string + sitemap?: SitemapOptions | boolean + onBeforeRender?: (context: RenderContext) => void | Promise + onAfterRender?: (context: RenderContext, html: string) => string | Promise + onRenderError?: (path: string, error: Error) => void + concurrency?: number +} + +export interface RenderContext { + path: string + params: Record + component: any + layouts: any[] +} + +export interface StaticRoute { + path: string + component: any + layouts: any[] + params: Record +} + +export interface SitemapOptions { + hostname: string + changefreq?: string + priority?: number + exclude?: string[] +} + +export interface SSGPluginOptions extends Omit { + entry?: string + contentDir?: string + routes?: Record + app?: new (props?: any) => any +} + +export interface GenerateResult { + pages: GeneratedPage[] + duration: number + errors: Array<{ path: string; error: Error }> +} + +export interface GeneratedPage { + path: string + outputPath: string + size: number +} diff --git a/packages/gea-ssg/src/vite-plugin.ts b/packages/gea-ssg/src/vite-plugin.ts new file mode 100644 index 0000000..4bd6b92 --- /dev/null +++ b/packages/gea-ssg/src/vite-plugin.ts @@ -0,0 +1,164 @@ +import { dirname, join, extname, resolve } from 'node:path' +import { existsSync } from 'node:fs' +import { fileURLToPath } from 'node:url' +import type { Plugin, ResolvedConfig } from 'vite' +import type { SSGPluginOptions } from './types' + +// Resolve to src/ directory — import.meta.url may point to dist/ at runtime +const __dir = dirname(fileURLToPath(import.meta.url)) +const SSG_SRC_DIR = __dir.endsWith('/dist') || __dir.endsWith('\\dist') ? join(__dir, '..', 'src') : __dir + +export function geaSSG(options: SSGPluginOptions = {}): Plugin[] { + let config: ResolvedConfig + let contentLoaded = false + let cachedContentJson = '{}' + + return [ + { + name: 'gea-ssg', + apply: 'build', + + config() { + return { + build: { + rollupOptions: { + external: ['@geajs/ssg'], + }, + }, + } + }, + + configResolved(resolvedConfig) { + config = resolvedConfig + }, + + async closeBundle() { + console.log('[gea-ssg] Starting static page generation...') + + try { + const { createServer } = await import('vite') + const viteServer = await createServer({ + configFile: config.configFile, + server: { middlewareMode: true }, + appType: 'custom', + resolve: { + alias: { '@geajs/ssg': SSG_SRC_DIR + '/index.ts' }, + }, + }) + + try { + const { generate } = await viteServer.ssrLoadModule(`${SSG_SRC_DIR}/generate.ts`) + + const ssgOpts: Record = { + shell: `${config.build.outDir}/index.html`, + outDir: config.build.outDir, + appElementId: options.appElementId || 'app', + contentDir: options.contentDir ? resolve(config.root, options.contentDir) : undefined, + sitemap: options.sitemap, + onBeforeRender: options.onBeforeRender, + onAfterRender: options.onAfterRender, + onRenderError: options.onRenderError, + concurrency: options.concurrency, + } + + if (options.routes && options.app) { + ssgOpts.routes = options.routes + ssgOpts.app = options.app + } else { + const entry = options.entry || 'src/App.tsx' + const ssgEntry = await viteServer.ssrLoadModule(entry) + ssgOpts.routes = ssgEntry.routes + ssgOpts.app = ssgEntry.App || ssgEntry.default + + if (!ssgOpts.routes || !ssgOpts.app) { + throw new Error(`[gea-ssg] ${entry} must export "routes" and "App" (or default).`) + } + } + + await generate(ssgOpts) + } finally { + await viteServer.close() + } + } catch (error) { + console.error('[gea-ssg] SSG error:', error) + throw error + } + }, + }, + + { + name: 'gea-ssg:dev', + apply: 'serve', + + config() { + return { + resolve: { + alias: { '@geajs/ssg': SSG_SRC_DIR + '/client.ts' }, + }, + } + }, + + configResolved(resolvedConfig) { + config = resolvedConfig + }, + + async transformIndexHtml(_html, ctx) { + if (!options.contentDir || !ctx.server) return + + if (!contentLoaded) { + const mod = await ctx.server.ssrLoadModule(`${SSG_SRC_DIR}/content.ts`) + await mod.preloadContent(resolve(config.root, options.contentDir)) + cachedContentJson = mod.serializeContentCache() + contentLoaded = true + } + + const safeJson = cachedContentJson.replace(/<\//g, '<\\/') + return [ + { + tag: 'script', + children: `window.__SSG_CONTENT__=${safeJson}`, + injectTo: 'head-prepend' as const, + }, + ] + }, + + configureServer(server) { + if (!options.contentDir) return + + const contentDir = resolve(config.root, options.contentDir) + + server.watcher.add(contentDir) + const invalidate = (file: string) => { + if (file.startsWith(contentDir) && file.endsWith('.md')) { + contentLoaded = false + server.ws.send({ type: 'full-reload' }) + } + } + server.watcher.on('change', invalidate) + server.watcher.on('add', invalidate) + server.watcher.on('unlink', invalidate) + }, + }, + + { + name: 'gea-ssg:preview', + + configResolved(resolvedConfig) { + config = resolvedConfig + }, + + configurePreviewServer(server) { + server.middlewares.use((req, _res, next) => { + if (req.url && !extname(req.url)) { + const url = req.url.split('?')[0] + const indexPath = join(config.build.outDir, url, 'index.html') + if (url !== '/' && existsSync(indexPath)) { + req.url = url.endsWith('/') ? url + 'index.html' : url + '/index.html' + } + } + next() + }) + }, + }, + ] +} diff --git a/packages/gea-ssg/tests/content.test.ts b/packages/gea-ssg/tests/content.test.ts new file mode 100644 index 0000000..5434f8b --- /dev/null +++ b/packages/gea-ssg/tests/content.test.ts @@ -0,0 +1,186 @@ +import { describe, it, beforeEach, afterEach } from 'node:test' +import assert from 'node:assert/strict' +import { writeFile, mkdir, rm } from 'node:fs/promises' +import { join } from 'node:path' + +import { preloadContent, clearContentCache, serializeContentCache, ssg, getContentSlugs } from '../src/content' + +const tmpDir = join(import.meta.dirname, '.tmp-content-test') + +beforeEach(async () => { + await mkdir(join(tmpDir, 'posts'), { recursive: true }) +}) + +afterEach(async () => { + clearContentCache() + await rm(tmpDir, { recursive: true, force: true }) +}) + +describe('preloadContent', () => { + it('loads all markdown files from subdirectories', async () => { + await writeFile( + join(tmpDir, 'posts', 'hello-world.md'), + '---\ntitle: Hello World\ndate: 2025-03-15\n---\n\n# Introduction\n\nThis is a **bold** paragraph.', + ) + await writeFile(join(tmpDir, 'posts', 'second-post.md'), '---\ntitle: Second Post\n---\n\n# Second') + + await preloadContent(tmpDir) + + const posts = ssg.content('posts') + assert.equal(posts.length, 2) + assert.equal(posts[0].slug, 'hello-world') + assert.equal(posts[1].slug, 'second-post') + }) + + it('parses frontmatter and renders markdown to html', async () => { + await writeFile( + join(tmpDir, 'posts', 'test.md'), + '---\ntitle: Test Post\ntags:\n - a\n - b\n---\n\nA paragraph with *emphasis*.', + ) + + await preloadContent(tmpDir) + + const posts = ssg.content('posts') + assert.equal(posts[0].frontmatter.title, 'Test Post') + assert.deepEqual(posts[0].frontmatter.tags, ['a', 'b']) + assert.ok(posts[0].content.includes('*emphasis*')) + assert.ok(posts[0].html.includes('emphasis')) + }) + + it('normalizes Date values to ISO strings', async () => { + await writeFile(join(tmpDir, 'posts', 'dated.md'), '---\ntitle: Dated\ndate: 2025-03-15\n---\n\nContent') + + await preloadContent(tmpDir) + + const posts = ssg.content('posts') + assert.equal(typeof posts[0].frontmatter.date, 'string') + assert.ok(posts[0].frontmatter.date.startsWith('2025-03-15')) + }) + + it('handles files without frontmatter', async () => { + await writeFile(join(tmpDir, 'posts', 'no-meta.md'), '# Just content\n\nSome text.') + + await preloadContent(tmpDir) + + const posts = ssg.content('posts') + assert.equal(posts[0].slug, 'no-meta') + assert.deepEqual(posts[0].frontmatter, {}) + assert.ok(posts[0].html.includes('

Just content

')) + }) + + it('ignores non-directory entries', async () => { + await writeFile(join(tmpDir, 'readme.md'), '# Root file') + await writeFile(join(tmpDir, 'posts', 'post.md'), '---\ntitle: Post\n---\n# Post') + + await preloadContent(tmpDir) + + const posts = ssg.content('posts') + assert.equal(posts.length, 1) + assert.equal(ssg.content('readme.md').length, 0) + }) + + it('ignores non-md files in subdirectories', async () => { + await writeFile(join(tmpDir, 'posts', 'post.md'), '---\ntitle: MD\n---\n# MD') + await writeFile(join(tmpDir, 'posts', 'readme.txt'), 'not markdown') + + await preloadContent(tmpDir) + + assert.equal(ssg.content('posts').length, 1) + }) +}) + +describe('ssg.content', () => { + it('returns empty array for unknown subdir', async () => { + await preloadContent(tmpDir) + assert.deepEqual(ssg.content('unknown'), []) + }) + + it('supports sort option', async () => { + await writeFile(join(tmpDir, 'posts', 'aaa.md'), '---\norder: 2\n---\n# A') + await writeFile(join(tmpDir, 'posts', 'bbb.md'), '---\norder: 1\n---\n# B') + + await preloadContent(tmpDir) + + const sorted = ssg.content('posts', { + sort: (a: any, b: any) => a.frontmatter.order - b.frontmatter.order, + }) + assert.equal(sorted[0].slug, 'bbb') + assert.equal(sorted[1].slug, 'aaa') + }) + + it('does not mutate original cache when sorting', async () => { + await writeFile(join(tmpDir, 'posts', 'bbb.md'), '---\norder: 1\n---\n# B') + await writeFile(join(tmpDir, 'posts', 'aaa.md'), '---\norder: 2\n---\n# A') + + await preloadContent(tmpDir) + + ssg.content('posts', { sort: (a: any, b: any) => a.frontmatter.order - b.frontmatter.order }) + + const unsorted = ssg.content('posts') + assert.equal(unsorted[0].slug, 'aaa') + }) +}) + +describe('ssg.file', () => { + it('finds a file by slug', async () => { + await writeFile(join(tmpDir, 'posts', 'hello.md'), '---\ntitle: Hello\n---\n# Hello') + await writeFile(join(tmpDir, 'posts', 'world.md'), '---\ntitle: World\n---\n# World') + + await preloadContent(tmpDir) + + const file = ssg.file('posts', 'hello') + assert.ok(file) + assert.equal(file!.frontmatter.title, 'Hello') + }) + + it('returns null for unknown slug', async () => { + await preloadContent(tmpDir) + assert.equal(ssg.file('posts', 'nonexistent'), null) + }) + + it('returns null for unknown subdir', async () => { + await preloadContent(tmpDir) + assert.equal(ssg.file('unknown', 'anything'), null) + }) +}) + +describe('getContentSlugs', () => { + it('returns slugs for a subdir', async () => { + await writeFile(join(tmpDir, 'posts', 'aaa.md'), '# A') + await writeFile(join(tmpDir, 'posts', 'bbb.md'), '# B') + + await preloadContent(tmpDir) + + const slugs = getContentSlugs('posts') + assert.deepEqual(slugs, ['aaa', 'bbb']) + }) + + it('returns empty for unknown subdir', () => { + assert.deepEqual(getContentSlugs('nope'), []) + }) +}) + +describe('serializeContentCache', () => { + it('returns valid JSON', async () => { + await writeFile(join(tmpDir, 'posts', 'test.md'), '---\ntitle: Test\n---\n# Test') + + await preloadContent(tmpDir) + + const json = serializeContentCache() + const parsed = JSON.parse(json) + assert.ok(Array.isArray(parsed.posts)) + assert.equal(parsed.posts[0].slug, 'test') + }) +}) + +describe('clearContentCache', () => { + it('clears all cached content', async () => { + await writeFile(join(tmpDir, 'posts', 'test.md'), '# Test') + + await preloadContent(tmpDir) + assert.equal(ssg.content('posts').length, 1) + + clearContentCache() + assert.equal(ssg.content('posts').length, 0) + }) +}) diff --git a/packages/gea-ssg/tests/crawl.test.ts b/packages/gea-ssg/tests/crawl.test.ts new file mode 100644 index 0000000..a6eb851 --- /dev/null +++ b/packages/gea-ssg/tests/crawl.test.ts @@ -0,0 +1,169 @@ +import { describe, it, beforeEach, afterEach } from 'node:test' +import assert from 'node:assert/strict' +import { writeFile, mkdir, rm } from 'node:fs/promises' +import { join } from 'node:path' +import { crawlRoutes } from '../src/crawl' +import { preloadContent, clearContentCache } from '../src/content' + +class HomePage { + template() { + return '
home
' + } +} +class AboutPage { + template() { + return '
about
' + } +} +class NotFoundPage { + template() { + return '
404
' + } +} +class LayoutComponent { + template() { + return '
layout
' + } +} +class BlogPostPage { + template() { + return '
post
' + } +} + +const tmpDir = join(import.meta.dirname, '.tmp-crawl-test') + +beforeEach(async () => { + await mkdir(join(tmpDir, 'blog'), { recursive: true }) +}) + +afterEach(async () => { + clearContentCache() + await rm(tmpDir, { recursive: true, force: true }) +}) + +describe('crawlRoutes', () => { + it('collects static routes', async () => { + const routes = { '/': HomePage, '/about': AboutPage } + const result = await crawlRoutes(routes as any) + assert.equal(result.length, 2) + assert.equal(result[0].path, '/') + assert.equal(result[1].path, '/about') + }) + + it('skips string redirects', async () => { + const routes = { '/': HomePage, '/old': '/new' } + const result = await crawlRoutes(routes as any) + assert.equal(result.length, 1) + }) + + it('skips redirect configs', async () => { + const routes = { '/': HomePage, '/legacy': { redirect: '/modern' } } + const result = await crawlRoutes(routes as any) + assert.equal(result.length, 1) + }) + + it('skips wildcard routes', async () => { + const routes = { '/': HomePage, '*': NotFoundPage } + const result = await crawlRoutes(routes as any) + assert.equal(result.length, 1) + }) + + it('resolves lazy components', async () => { + const routes = { '/': HomePage, '/lazy': () => Promise.resolve({ default: AboutPage }) } + const result = await crawlRoutes(routes as any) + assert.equal(result.length, 2) + assert.equal(result[1].component, AboutPage) + }) + + it('handles route groups with layouts', async () => { + const routes = { + '/': { layout: LayoutComponent, children: { '/': HomePage, '/about': AboutPage } }, + } + const result = await crawlRoutes(routes as any) + assert.equal(result.length, 2) + assert.equal(result[0].layouts.length, 1) + assert.equal(result[0].layouts[0], LayoutComponent) + }) + + it('handles nested route groups', async () => { + const routes = { + '/admin': { + layout: LayoutComponent, + children: { + '/dashboard': HomePage, + '/settings': { children: { '/profile': AboutPage } }, + }, + }, + } + const result = await crawlRoutes(routes as any) + assert.equal(result.length, 2) + assert.equal(result[0].path, '/admin/dashboard') + assert.equal(result[1].path, '/admin/settings/profile') + }) + + it('normalizes double slashes', async () => { + const routes = { '/': { children: { '/about': AboutPage } } } + const result = await crawlRoutes(routes as any) + assert.equal(result[0].path, '/about') + }) + + it('returns empty array for empty routes', async () => { + const result = await crawlRoutes({}) + assert.equal(result.length, 0) + }) + + it('generates routes from content slugs', async () => { + await writeFile(join(tmpDir, 'blog', 'hello-world.md'), '---\ntitle: Hello\n---\n# Hello') + await writeFile(join(tmpDir, 'blog', 'second-post.md'), '---\ntitle: Second\n---\n# Second') + await preloadContent(tmpDir) + + const routes = { + '/blog/:slug': { component: BlogPostPage, content: 'blog' }, + } + const result = await crawlRoutes(routes as any) + assert.equal(result.length, 2) + assert.equal(result[0].path, '/blog/hello-world') + assert.equal(result[0].params.slug, 'hello-world') + assert.equal(result[1].path, '/blog/second-post') + }) + + it('generates routes from explicit paths', async () => { + const routes = { + '/users/:id': { + component: HomePage, + paths: [{ params: { id: '1' } }, { params: { id: '2' } }], + }, + } + const result = await crawlRoutes(routes as any) + assert.equal(result.length, 2) + assert.equal(result[0].path, '/users/1') + assert.equal(result[1].path, '/users/2') + }) + + it('treats { component } without content/paths as static route', async () => { + const routes = { '/about': { component: AboutPage } } + const result = await crawlRoutes(routes as any) + assert.equal(result.length, 1) + assert.equal(result[0].path, '/about') + assert.equal(result[0].component, AboutPage) + }) + + it('skips parameterized routes without content or paths', async () => { + const routes = { '/user/:id': HomePage } + const result = await crawlRoutes(routes as any) + assert.equal(result.length, 0) + }) + + it('skips routes with client: true', async () => { + const routes = { + '/': HomePage, + '/dashboard': { component: AboutPage, client: true }, + '/about': AboutPage, + } + const result = await crawlRoutes(routes as any) + assert.equal(result.length, 2) + assert.equal(result[0].path, '/') + assert.equal(result[1].path, '/about') + }) +}) diff --git a/packages/gea-ssg/tests/generate.test.ts b/packages/gea-ssg/tests/generate.test.ts new file mode 100644 index 0000000..6e60edb --- /dev/null +++ b/packages/gea-ssg/tests/generate.test.ts @@ -0,0 +1,393 @@ +import { describe, it, beforeEach, afterEach } from 'node:test' +import assert from 'node:assert/strict' +import { mkdtemp, rm, readFile, writeFile, mkdir } from 'node:fs/promises' +import { join } from 'node:path' +import { tmpdir } from 'node:os' +import { generate } from '../src/generate' +import { RouterView, Outlet } from '@geajs/core' + +const SHELL_HTML = ` + + + Test App + + + +
+ +` + +class HomePage { + props: any + constructor(props?: any) { + this.props = props || {} + } + template() { + return '

Home

' + } + dispose() {} +} + +class AboutPage { + props: any + constructor(props?: any) { + this.props = props || {} + } + template() { + return '

About

' + } + dispose() {} +} + +class UserPage { + props: any + constructor(props?: any) { + this.props = props || {} + } + template() { + return `

User ${this.props.id || 'unknown'}

` + } + dispose() {} +} + +class ThrowingPage { + constructor() { + throw new Error('render failed') + } + template() { + return '' + } +} + +class MockLayout { + props: any + constructor(props?: any) { + this.props = props || {} + } + template() { + const outletHtml = Outlet._ssgHtml || '' + return `
Layout Header
${outletHtml}
` + } + dispose() {} +} + +class MockNestedLayout { + props: any + constructor(props?: any) { + this.props = props || {} + } + template() { + const outletHtml = Outlet._ssgHtml || '' + return `
${outletHtml}
` + } + dispose() {} +} + +class MockApp { + props: any + constructor(props?: any) { + this.props = props || {} + } + template() { + let routeContent = '' + if (RouterView._ssgRoute) { + const { component, layouts, params } = RouterView._ssgRoute + + if (!layouts.length) { + const child = new component(params) + routeContent = String(child.template(child.props)).trim() + if (typeof child.dispose === 'function') child.dispose() + } else { + const leaf = new component(params) + let innerHtml = String(leaf.template(leaf.props)).trim() + if (typeof leaf.dispose === 'function') leaf.dispose() + + for (let i = layouts.length - 1; i >= 0; i--) { + Outlet._ssgHtml = innerHtml + const layout = new layouts[i]({ ...params }) + innerHtml = String(layout.template(layout.props)).trim() + if (typeof layout.dispose === 'function') layout.dispose() + Outlet._ssgHtml = null + } + routeContent = innerHtml + } + } + return `
${routeContent}
` + } + dispose() {} +} + +let tempDir: string +let shellPath: string + +describe('generate', () => { + beforeEach(async () => { + tempDir = await mkdtemp(join(tmpdir(), 'gea-ssg-test-')) + shellPath = join(tempDir, 'index.html') + await writeFile(shellPath, SHELL_HTML, 'utf-8') + }) + + afterEach(async () => { + await rm(tempDir, { recursive: true, force: true }) + }) + + it('generates HTML files for static routes', async () => { + const result = await generate({ + routes: { '/': HomePage, '/about': AboutPage } as any, + app: MockApp as any, + shell: shellPath, + outDir: tempDir, + }) + + assert.equal(result.pages.length, 2) + assert.equal(result.errors.length, 0) + + const indexHtml = await readFile(join(tempDir, 'index.html'), 'utf-8') + assert.ok(indexHtml.includes('

Home

')) + assert.ok(indexHtml.includes('')) + + const aboutHtml = await readFile(join(tempDir, 'about', 'index.html'), 'utf-8') + assert.ok(aboutHtml.includes('

About

')) + }) + + it('creates nested directories', async () => { + const result = await generate({ + routes: { '/docs/getting-started': AboutPage } as any, + app: MockApp as any, + shell: shellPath, + outDir: tempDir, + }) + + assert.equal(result.pages.length, 1) + const html = await readFile(join(tempDir, 'docs', 'getting-started', 'index.html'), 'utf-8') + assert.ok(html.includes('

About

')) + }) + + it('catches render errors per route', async () => { + const capturedErrors: string[] = [] + const result = await generate({ + routes: { '/': HomePage, '/broken': ThrowingPage } as any, + app: MockApp as any, + shell: shellPath, + outDir: tempDir, + onRenderError: (path, err) => { + capturedErrors.push(`${path}: ${err.message}`) + }, + }) + + assert.equal(result.pages.length, 1) + assert.equal(result.errors.length, 1) + assert.equal(capturedErrors[0], '/broken: render failed') + }) + + it('passes params to route components via { component, paths }', async () => { + const result = await generate({ + routes: { + '/users/:id': { + component: UserPage, + paths: [{ params: { id: '1' } }, { params: { id: '2' } }], + }, + } as any, + app: MockApp as any, + shell: shellPath, + outDir: tempDir, + }) + + assert.equal(result.pages.length, 2) + + const user1 = await readFile(join(tempDir, 'users', '1', 'index.html'), 'utf-8') + assert.ok(user1.includes('

User 1

')) + + const user2 = await readFile(join(tempDir, 'users', '2', 'index.html'), 'utf-8') + assert.ok(user2.includes('

User 2

')) + }) + + it('generates routes from { component, content } config', async () => { + const contentDir = join(tempDir, 'content') + await mkdir(join(contentDir, 'blog'), { recursive: true }) + await writeFile(join(contentDir, 'blog', 'hello.md'), '---\ntitle: Hello\n---\n# Hello') + await writeFile(join(contentDir, 'blog', 'world.md'), '---\ntitle: World\n---\n# World') + + class PostPage { + props: any + constructor(props?: any) { + this.props = props || {} + } + template() { + return `

Post: ${this.props.slug}

` + } + dispose() {} + } + + const result = await generate({ + routes: { + '/blog/:slug': { component: PostPage, content: 'blog' }, + } as any, + app: MockApp as any, + shell: shellPath, + outDir: tempDir, + contentDir, + }) + + assert.equal(result.pages.length, 2) + + const hello = await readFile(join(tempDir, 'blog', 'hello', 'index.html'), 'utf-8') + assert.ok(hello.includes('

Post: hello

')) + + const world = await readFile(join(tempDir, 'blog', 'world', 'index.html'), 'utf-8') + assert.ok(world.includes('

Post: world

')) + }) + + it('renders with a single layout wrapping the component', async () => { + const result = await generate({ + routes: { + '/': { + layout: MockLayout, + children: { '/': HomePage, '/about': AboutPage }, + }, + } as any, + app: MockApp as any, + shell: shellPath, + outDir: tempDir, + }) + + assert.equal(result.pages.length, 2) + + const indexHtml = await readFile(join(tempDir, 'index.html'), 'utf-8') + assert.ok(indexHtml.includes('
Layout Header
')) + assert.ok(indexHtml.includes('

Home

')) + }) + + it('renders with nested layouts', async () => { + const result = await generate({ + routes: { + '/': { + layout: MockLayout, + children: { + '/dashboard': { + layout: MockNestedLayout, + children: { '/': HomePage }, + }, + }, + }, + } as any, + app: MockApp as any, + shell: shellPath, + outDir: tempDir, + }) + + assert.equal(result.pages.length, 1) + + const html = await readFile(join(tempDir, 'dashboard', 'index.html'), 'utf-8') + assert.ok(html.includes('
Layout Header
')) + assert.ok(html.includes('')) + assert.ok(html.includes('

Home

')) + }) + + it('calls onBeforeRender hook', async () => { + const paths: string[] = [] + await generate({ + routes: { '/': HomePage, '/about': AboutPage } as any, + app: MockApp as any, + shell: shellPath, + outDir: tempDir, + onBeforeRender: (ctx) => { + paths.push(ctx.path) + }, + }) + + assert.ok(paths.includes('/')) + assert.ok(paths.includes('/about')) + }) + + it('calls onAfterRender hook and uses transformed HTML', async () => { + await generate({ + routes: { '/': HomePage } as any, + app: MockApp as any, + shell: shellPath, + outDir: tempDir, + onAfterRender: (_ctx, html) => html.replace('', '
SSG
'), + }) + + const html = await readFile(join(tempDir, 'index.html'), 'utf-8') + assert.ok(html.includes('
SSG
')) + }) + + it('strips module scripts from output', async () => { + await generate({ + routes: { '/': HomePage } as any, + app: MockApp as any, + shell: shellPath, + outDir: tempDir, + }) + + const html = await readFile(join(tempDir, 'index.html'), 'utf-8') + assert.ok(!html.includes('main.js')) + }) + + it('preserves non-JS scripts like JSON-LD', async () => { + const shellWithJsonLd = SHELL_HTML.replace( + '', + '\n', + ) + await writeFile(shellPath, shellWithJsonLd, 'utf-8') + + await generate({ + routes: { '/': HomePage } as any, + app: MockApp as any, + shell: shellPath, + outDir: tempDir, + }) + + const html = await readFile(join(tempDir, 'index.html'), 'utf-8') + assert.ok(html.includes('application/ld+json')) + assert.ok(!html.includes('main.js')) + }) + + it('generates sitemap when enabled', async () => { + await generate({ + routes: { '/': HomePage, '/about': AboutPage } as any, + app: MockApp as any, + shell: shellPath, + outDir: tempDir, + sitemap: { hostname: 'https://example.com' }, + }) + + const sitemap = await readFile(join(tempDir, 'sitemap.xml'), 'utf-8') + assert.ok(sitemap.includes('https://example.com/')) + assert.ok(sitemap.includes('https://example.com/about')) + }) + + it('returns duration in result', async () => { + const result = await generate({ + routes: { '/': HomePage } as any, + app: MockApp as any, + shell: shellPath, + outDir: tempDir, + }) + assert.ok(result.duration > 0) + }) + + it('returns page sizes in result', async () => { + const result = await generate({ + routes: { '/': HomePage } as any, + app: MockApp as any, + shell: shellPath, + outDir: tempDir, + }) + assert.ok(result.pages[0].size > 0) + }) + + it('rejects path traversal in route paths', async () => { + await assert.rejects( + () => + generate({ + routes: { '/../../escape': HomePage } as any, + app: MockApp as any, + shell: shellPath, + outDir: tempDir, + }), + /Path traversal detected/, + ) + }) +}) diff --git a/packages/gea-ssg/tests/render.test.ts b/packages/gea-ssg/tests/render.test.ts new file mode 100644 index 0000000..bb4d731 --- /dev/null +++ b/packages/gea-ssg/tests/render.test.ts @@ -0,0 +1,87 @@ +import { describe, it } from 'node:test' +import assert from 'node:assert/strict' +import { renderToString } from '../src/render' + +// Minimal mock component — simulates what Gea components do +class MockComponent { + props: any + constructor(props?: any) { + this.props = props || {} + } + template(_props: any) { + return '
Hello World
' + } +} + +class MockComponentWithProps { + props: any + constructor(props?: any) { + this.props = props || {} + } + template(props: any) { + return `

${props.title || 'default'}

` + } +} + +class ThrowingComponent { + props: any + constructor() { + throw new Error('Component init failed') + } + template() { + return '' + } +} + +describe('renderToString', () => { + it('renders a simple component to HTML', () => { + const html = renderToString(MockComponent) + assert.equal(html, '
Hello World
') + }) + + it('passes props to the component', () => { + const html = renderToString(MockComponentWithProps, { title: 'SSG Test' }) + assert.equal(html, '

SSG Test

') + }) + + it('uses default props when none provided', () => { + const html = renderToString(MockComponentWithProps) + assert.equal(html, '

default

') + }) + + it('trims whitespace from output', () => { + class SpaceyComponent { + props: any + constructor() { + this.props = {} + } + template() { + return '
spaced
' + } + } + const html = renderToString(SpaceyComponent) + assert.equal(html, '
spaced
') + }) + + it('throws on render error by default', () => { + assert.throws(() => renderToString(ThrowingComponent), { message: 'Component init failed' }) + }) + + it('catches errors when onRenderError is provided', () => { + let capturedError: Error | null = null + const html = renderToString(ThrowingComponent, undefined, { + onRenderError: (err) => { + capturedError = err + }, + }) + assert.equal(html, '') + assert.ok(capturedError) + assert.equal((capturedError as Error).message, 'Component init failed') + }) + + it('produces deterministic output with same seed', () => { + const html1 = renderToString(MockComponent, undefined, { seed: 42 }) + const html2 = renderToString(MockComponent, undefined, { seed: 42 }) + assert.equal(html1, html2) + }) +}) diff --git a/packages/gea-ssg/tests/shell.test.ts b/packages/gea-ssg/tests/shell.test.ts new file mode 100644 index 0000000..2a2fd5d --- /dev/null +++ b/packages/gea-ssg/tests/shell.test.ts @@ -0,0 +1,74 @@ +import { describe, it } from 'node:test' +import assert from 'node:assert/strict' +import { parseShell, injectIntoShell } from '../src/shell' + +const BASIC_SHELL = ` + + + Test + + +
+ + +` + +describe('parseShell', () => { + it('parses a basic HTML shell', () => { + const parts = parseShell(BASIC_SHELL) + assert.ok(parts.before.endsWith('
')) + assert.ok(parts.after.startsWith('
')) + assert.ok(parts.headEnd > 0) + }) + + it('throws when app element is not found', () => { + assert.throws(() => parseShell(''), { message: /not found in shell HTML/ }) + }) + + it('throws when closing div is missing', () => { + assert.throws(() => parseShell('
'), { + message: /Closing <\/div> not found/, + }) + }) + + it('supports custom appElementId', () => { + const html = '
' + const parts = parseShell(html, 'root') + assert.ok(parts.before.endsWith('
')) + }) + + it('handles existing content inside app div', () => { + const html = '
loading...
' + const parts = parseShell(html) + assert.ok(parts.before.endsWith('
')) + assert.ok(parts.after.startsWith('
')) + }) +}) + +describe('injectIntoShell', () => { + it('injects rendered HTML between shell parts', () => { + const parts = parseShell(BASIC_SHELL) + const result = injectIntoShell(parts, '

Hello

') + assert.ok(result.includes('

Hello

')) + }) + + it('injects head tags before ', () => { + const parts = parseShell(BASIC_SHELL) + const result = injectIntoShell(parts, '

content

', '') + assert.ok(result.includes('')) + }) + + it('skips head injection when no headTags provided', () => { + const parts = parseShell(BASIC_SHELL) + const result = injectIntoShell(parts, '

content

') + assert.equal(result.includes('undefined'), false) + }) + + it('produces valid full HTML', () => { + const parts = parseShell(BASIC_SHELL) + const result = injectIntoShell(parts, '
SSG Content
') + assert.ok(result.startsWith('')) + assert.ok(result.includes('
SSG Content
')) + assert.ok(result.includes('')) + }) +}) diff --git a/packages/gea-ssg/tsconfig.json b/packages/gea-ssg/tsconfig.json new file mode 100644 index 0000000..0b27536 --- /dev/null +++ b/packages/gea-ssg/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "emitDeclarationOnly": true, + "lib": ["ES2020"], + "types": ["node"], + "declaration": true, + "strict": false, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "skipLibCheck": true + }, + "include": ["./src/**/*.ts", "./tests/**/*.ts"] +} diff --git a/packages/gea/src/index.ts b/packages/gea/src/index.ts index 1c9bb3c..2a2cd75 100644 --- a/packages/gea/src/index.ts +++ b/packages/gea/src/index.ts @@ -4,13 +4,15 @@ export { Store, isInternalProp } from './lib/store' export { h } from './lib/h' export type { DOMEvent } from './lib/types' export { default as ComponentManager } from './lib/base/component-manager' +export { resetUidCounter } from './lib/base/uid' export { applyListChanges } from './lib/base/list' export type { ListConfig } from './lib/base/list' -export { createRouter, Router, router, matchRoute, Link, Outlet, RouterView } from './lib/router' +export { createRouter, Router, router, matchRoute, resolveRoute, Link, Outlet, RouterView } from './lib/router' export type { RouteMap, RouteEntry, RouteGroupConfig, + ResolvedRoute, RouterOptions, GuardFn, GuardResult, diff --git a/packages/gea/src/lib/base/component-manager.ts b/packages/gea/src/lib/base/component-manager.ts index 09cbdcb..ee7ca83 100644 --- a/packages/gea/src/lib/base/component-manager.ts +++ b/packages/gea/src/lib/base/component-manager.ts @@ -136,6 +136,10 @@ interface ComponentLike { } const createElement = (() => { + if (typeof document === 'undefined') { + return (htmlString: string): HTMLElement => htmlString as any + } + let template: HTMLTemplateElement | null = null return (htmlString: string): HTMLElement => { diff --git a/packages/gea/src/lib/base/component.tsx b/packages/gea/src/lib/base/component.tsx index fa34aae..b3a55da 100644 --- a/packages/gea/src/lib/base/component.tsx +++ b/packages/gea/src/lib/base/component.tsx @@ -15,6 +15,7 @@ export default class Component

> extends Store { declare setState: (...args: any[]) => void declare forceUpdate: (...args: any[]) => void static __componentClasses: Map = new Map() + static _ssgMode = false id_: string element_: HTMLElement | null @@ -78,10 +79,13 @@ export default class Component

> extends Store { ComponentManager.getInstance().setComponent(this) this.created(this.props) - this.createdHooks(this.props) - if (typeof (this as any).__setupLocalStateObservers === 'function') { - ;(this as any).__setupLocalStateObservers() + if (!Component._ssgMode) { + this.createdHooks(this.props) + + if (typeof (this as any).__setupLocalStateObservers === 'function') { + ;(this as any).__setupLocalStateObservers() + } } } diff --git a/packages/gea/src/lib/base/uid.ts b/packages/gea/src/lib/base/uid.ts index d7419f8..8cb0c9a 100644 --- a/packages/gea/src/lib/base/uid.ts +++ b/packages/gea/src/lib/base/uid.ts @@ -38,4 +38,8 @@ export function clearUidProvider(): void { resetProvider = null } +export function resetUidCounter(seed: number = 0): void { + counter = seed +} + export default getUid diff --git a/packages/gea/src/lib/router/index.ts b/packages/gea/src/lib/router/index.ts index a0e5ffe..1ee997f 100644 --- a/packages/gea/src/lib/router/index.ts +++ b/packages/gea/src/lib/router/index.ts @@ -32,10 +32,12 @@ export { Link } export { Outlet } export { RouterView } export { matchRoute } from './match' +export { resolveRoute } from './resolve' export type { RouteMap, RouteEntry, RouteGroupConfig, + ResolvedRoute, RouterOptions, GuardFn, GuardResult, diff --git a/packages/gea/src/lib/router/link.ts b/packages/gea/src/lib/router/link.ts index 3c55aef..a503454 100644 --- a/packages/gea/src/lib/router/link.ts +++ b/packages/gea/src/lib/router/link.ts @@ -18,6 +18,7 @@ export interface LinkProps { export default class Link extends Component { static _router: any = null + static _ssgCurrentPath: string | null = null private _clickHandler: ((e: MouseEvent) => void) | null = null private _observerRemover: (() => void) | null = null @@ -27,7 +28,20 @@ export default class Link extends Component { const target = props.target ? ` target="${escapeAttr(props.target)}"` : '' const rel = props.rel ? ` rel="${escapeAttr(props.rel)}"` : '' const content = props.children ?? props.label ?? '' - return `${content}` as any + + let activeAttr = '' + const ssgPath = Link._ssgCurrentPath + if (ssgPath !== null) { + const to = props.to + const active = props.exact + ? ssgPath === to + : to === '/' + ? ssgPath === '/' + : ssgPath === to || ssgPath.startsWith(to + '/') + if (active) activeAttr = ' data-active' + } + + return `${content}` as any } onAfterRender() { diff --git a/packages/gea/src/lib/router/outlet.ts b/packages/gea/src/lib/router/outlet.ts index 2b683b9..ef410ff 100644 --- a/packages/gea/src/lib/router/outlet.ts +++ b/packages/gea/src/lib/router/outlet.ts @@ -3,6 +3,7 @@ import type { Router } from './router' export default class Outlet extends Component<{ router?: Router | null }> { static _router: Router | null = null + static _ssgHtml: string | null = null __isRouterOutlet = true _routerDepth = -1 @@ -14,6 +15,9 @@ export default class Outlet extends Component<{ router?: Router | null }> { private _observerRemovers: Array<() => void> = [] template() { + if (Outlet._ssgHtml) { + return `

${Outlet._ssgHtml}
` as any + } return `
` as any } diff --git a/packages/gea/src/lib/router/resolve.ts b/packages/gea/src/lib/router/resolve.ts index 3b1bf7d..7342ffe 100644 --- a/packages/gea/src/lib/router/resolve.ts +++ b/packages/gea/src/lib/router/resolve.ts @@ -195,6 +195,17 @@ function tryResolveEntry( return childResult } + // --- SSG route config: { component, ... } --- + if ( + typeof entry === 'object' && + entry !== null && + 'component' in entry && + !('children' in entry) && + !('redirect' in entry) + ) { + return tryResolveEntry(pattern, (entry as any).component, path, search, result) + } + // --- Leaf: function or component --- const match = matchRoute(pattern, path) if (!match) return null diff --git a/packages/gea/src/lib/router/router-view.ts b/packages/gea/src/lib/router/router-view.ts index 571e797..0ff318f 100644 --- a/packages/gea/src/lib/router/router-view.ts +++ b/packages/gea/src/lib/router/router-view.ts @@ -1,9 +1,17 @@ import Component from '../base/component' -import type { Router } from './router' +import { Router } from './router' import type { RouteMap } from './types' import Outlet from './outlet' +export interface SSGRoute { + component: any + layouts: any[] + params: Record +} + export default class RouterView extends Component<{ router?: Router; routes?: RouteMap }> { + static _ssgRoute: SSGRoute | null = null + __isRouterOutlet = true _routerDepth = 0 @@ -15,6 +23,30 @@ export default class RouterView extends Component<{ router?: Router; routes?: Ro private _routesApplied = false template() { + if (RouterView._ssgRoute) { + const { component, layouts, params } = RouterView._ssgRoute + + if (!layouts.length) { + const child = new component(params) + const html = String(child.template(child.props)).trim() + if (typeof child.dispose === 'function') child.dispose() + return `
${html}
` as any + } + + const leaf = new component(params) + let innerHtml = String(leaf.template(leaf.props)).trim() + if (typeof leaf.dispose === 'function') leaf.dispose() + + for (let i = layouts.length - 1; i >= 0; i--) { + Outlet._ssgHtml = innerHtml + const layout = new layouts[i]({ ...params }) + innerHtml = String(layout.template(layout.props)).trim() + if (typeof layout.dispose === 'function') layout.dispose() + Outlet._ssgHtml = null + } + + return `
${innerHtml}
` as any + } return `
` as any } @@ -36,7 +68,17 @@ export default class RouterView extends Component<{ router?: Router; routes?: Ro } onAfterRender() { - const router = this._getRouter() + let router = this._getRouter() + + if (!router && this.props?.routes) { + router = new Router(this.props.routes) + this._router = router + this._routesApplied = true + this._rebindRouter(router) + this._updateView() + return + } + if (!router) return if (this.props?.routes && !this._routesApplied) { From 3e672ff84814e12f9cc4de17cc4070add4b6c095 Mon Sep 17 00:00:00 2001 From: cemalturkcan Date: Wed, 25 Mar 2026 09:30:29 +0300 Subject: [PATCH 02/26] docs: add @geajs/ssg to root README packages, examples, and docs --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index fe1a1b5..a5817bf 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,7 @@ This scaffolds a Vite-powered project with TypeScript, a sample store, class and | [`@geajs/core`](packages/gea) | Core framework — stores, components, reactivity, DOM patching | [![npm](https://img.shields.io/npm/v/@geajs/core.svg)](https://www.npmjs.com/package/@geajs/core) | | [`@geajs/ui`](packages/gea-ui) | Headless UI primitives — accessible, composable components built on [Zag.js](https://zagjs.com) | [![npm](https://img.shields.io/npm/v/@geajs/ui.svg)](https://www.npmjs.com/package/@geajs/ui) | | [`@geajs/mobile`](packages/gea-mobile) | Mobile UI primitives — views, navigation, gestures, layout | [![npm](https://img.shields.io/npm/v/@geajs/mobile.svg)](https://www.npmjs.com/package/@geajs/mobile) | +| [`@geajs/ssg`](packages/gea-ssg) | Static site generation — markdown content, dynamic routes, sitemap | [![npm](https://img.shields.io/npm/v/@geajs/ssg.svg)](https://www.npmjs.com/package/@geajs/ssg) | | [`@geajs/vite-plugin`](packages/vite-plugin-gea) | Vite plugin — JSX transform, reactivity wiring, HMR | [![npm](https://img.shields.io/npm/v/@geajs/vite-plugin.svg)](https://www.npmjs.com/package/@geajs/vite-plugin) | | [`create-gea`](packages/create-gea) | Project scaffolder — `npm create gea@latest` | [![npm](https://img.shields.io/npm/v/create-gea.svg)](https://www.npmjs.com/package/create-gea) | | [`gea-tools`](packages/gea-tools) | VS Code / Cursor extension — completions, hover, diagnostics | — | @@ -117,6 +118,7 @@ See the full comparisons: [React vs Gea](docs/comparison/react-vs-gea.md) | [Vue | [router](examples/router) | Client-side routing with `RouterView`, `Link`, and dynamic params | | [kanban](examples/kanban) | Kanban board with drag semantics | | [mobile-showcase](examples/mobile-showcase) | Mobile UI showcase using `@geajs/mobile` components | +| [ssg-basic](examples/ssg-basic) | Static site with markdown content, dynamic routes, and sitemap | ## Documentation @@ -126,6 +128,7 @@ Full documentation is available in the [docs](docs/) directory, covering: - [Stores](docs/core-concepts/stores.md) and [Components](docs/core-concepts/components.md) - [JSX Syntax](docs/core-concepts/jsx-syntax.md) - [Router](docs/gea-router/overview.md) +- [Static Site Generation](docs/tooling/ssg.md) - [Gea UI](docs/gea-ui/overview.md) - [Gea Mobile](docs/gea-mobile/overview.md) - [API Reference](docs/api-reference.md) From b87be2726ae9a188931f90e94f2ce9e8406ff30a Mon Sep 17 00:00:00 2001 From: cemalturkcan Date: Wed, 25 Mar 2026 09:35:17 +0300 Subject: [PATCH 03/26] docs: add client-only routes (skip) to SSG README and docs --- docs/tooling/ssg.md | 15 +++++++++++++++ packages/gea-ssg/README.md | 12 ++++++++++++ 2 files changed, 27 insertions(+) diff --git a/docs/tooling/ssg.md b/docs/tooling/ssg.md index 75770fe..5847536 100644 --- a/docs/tooling/ssg.md +++ b/docs/tooling/ssg.md @@ -161,6 +161,21 @@ export const routes = { } ``` +## Client-Only Routes + +Some routes should not be pre-rendered — for example, pages that require authentication or depend entirely on client-side state. Mark them with `client: true`: + +```tsx +export const routes = { + '/': Home, + '/about': About, + '/dashboard': { component: Dashboard, client: true }, + '/settings': { component: Settings, client: true }, +} +``` + +These routes are skipped during static generation and only rendered by the client-side router at runtime. + ## Layouts Route groups with `layout` components work automatically. The SSG renders layouts wrapping page content through `Outlet`, just like client-side rendering: diff --git a/packages/gea-ssg/README.md b/packages/gea-ssg/README.md index 67bf847..7302777 100644 --- a/packages/gea-ssg/README.md +++ b/packages/gea-ssg/README.md @@ -119,6 +119,18 @@ export const routes = { } ``` +### Client-Only Routes + +Mark routes that should not be pre-rendered with `client: true`. These routes are skipped during SSG and only rendered client-side: + +```tsx +export const routes = { + '/': Home, + '/about': About, + '/dashboard': { component: Dashboard, client: true }, +} +``` + ### Layouts and Outlets Route groups with `layout` components are rendered with proper nesting — the layout wraps the page content through `Outlet`. From 7b72414627a100a0487f1de77d020a462141d91c Mon Sep 17 00:00:00 2001 From: cemalturkcan Date: Wed, 25 Mar 2026 09:45:36 +0300 Subject: [PATCH 04/26] refactor: replace client:true route config with component tag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Client component renders an empty placeholder during SSG — child components only mount in the browser. This keeps route config clean and gives per-section control instead of per-route. --- docs/tooling/ssg.md | 25 +++++++++++++++++-------- packages/gea-ssg/README.md | 24 ++++++++++++++++++------ packages/gea-ssg/src/crawl.ts | 2 -- packages/gea-ssg/tests/crawl.test.ts | 12 ------------ packages/gea/src/index.ts | 1 + packages/gea/src/lib/client.ts | 7 +++++++ 6 files changed, 43 insertions(+), 28 deletions(-) create mode 100644 packages/gea/src/lib/client.ts diff --git a/docs/tooling/ssg.md b/docs/tooling/ssg.md index 5847536..fa17b68 100644 --- a/docs/tooling/ssg.md +++ b/docs/tooling/ssg.md @@ -161,20 +161,29 @@ export const routes = { } ``` -## Client-Only Routes +## Client-Only Content -Some routes should not be pre-rendered — for example, pages that require authentication or depend entirely on client-side state. Mark them with `client: true`: +Wrap parts of a component's template with `` to exclude them from static output. The wrapped content renders only in the browser: ```tsx -export const routes = { - '/': Home, - '/about': About, - '/dashboard': { component: Dashboard, client: true }, - '/settings': { component: Settings, client: true }, +import { Component, Client } from '@geajs/core' + +class Dashboard extends Component { + template() { + return ( +
+

Dashboard

+ + + + +
+ ) + } } ``` -These routes are skipped during static generation and only rendered by the client-side router at runtime. +During SSG the `` section becomes an empty placeholder. At runtime the child components mount normally. This lets you pre-render the page shell (nav, layout, headings) while deferring interactive parts to the client. ## Layouts diff --git a/packages/gea-ssg/README.md b/packages/gea-ssg/README.md index 7302777..82ad48f 100644 --- a/packages/gea-ssg/README.md +++ b/packages/gea-ssg/README.md @@ -119,18 +119,30 @@ export const routes = { } ``` -### Client-Only Routes +### Client-Only Content -Mark routes that should not be pre-rendered with `client: true`. These routes are skipped during SSG and only rendered client-side: +Wrap parts of a template with the `` tag to exclude them from static output. The wrapped content only renders in the browser: ```tsx -export const routes = { - '/': Home, - '/about': About, - '/dashboard': { component: Dashboard, client: true }, +import { Component, Client } from '@geajs/core' + +class Dashboard extends Component { + template() { + return ( +
+

Dashboard

+ + + + +
+ ) + } } ``` +During SSG the `` section becomes an empty placeholder. At runtime the child components mount normally. + ### Layouts and Outlets Route groups with `layout` components are rendered with proper nesting — the layout wraps the page content through `Outlet`. diff --git a/packages/gea-ssg/src/crawl.ts b/packages/gea-ssg/src/crawl.ts index d9144df..acbbef7 100644 --- a/packages/gea-ssg/src/crawl.ts +++ b/packages/gea-ssg/src/crawl.ts @@ -35,8 +35,6 @@ async function collectPaths( } if (isSSGRouteConfig(entry)) { - if ((entry as any).client === true) return - const component = (entry as any).component if ((entry as any).content) { diff --git a/packages/gea-ssg/tests/crawl.test.ts b/packages/gea-ssg/tests/crawl.test.ts index a6eb851..e6142aa 100644 --- a/packages/gea-ssg/tests/crawl.test.ts +++ b/packages/gea-ssg/tests/crawl.test.ts @@ -154,16 +154,4 @@ describe('crawlRoutes', () => { const result = await crawlRoutes(routes as any) assert.equal(result.length, 0) }) - - it('skips routes with client: true', async () => { - const routes = { - '/': HomePage, - '/dashboard': { component: AboutPage, client: true }, - '/about': AboutPage, - } - const result = await crawlRoutes(routes as any) - assert.equal(result.length, 2) - assert.equal(result[0].path, '/') - assert.equal(result[1].path, '/about') - }) }) diff --git a/packages/gea/src/index.ts b/packages/gea/src/index.ts index 2a2cd75..05f8d9c 100644 --- a/packages/gea/src/index.ts +++ b/packages/gea/src/index.ts @@ -8,6 +8,7 @@ export { resetUidCounter } from './lib/base/uid' export { applyListChanges } from './lib/base/list' export type { ListConfig } from './lib/base/list' export { createRouter, Router, router, matchRoute, resolveRoute, Link, Outlet, RouterView } from './lib/router' +export { Client } from './lib/client' export type { RouteMap, RouteEntry, diff --git a/packages/gea/src/lib/client.ts b/packages/gea/src/lib/client.ts new file mode 100644 index 0000000..4480268 --- /dev/null +++ b/packages/gea/src/lib/client.ts @@ -0,0 +1,7 @@ +import Component from './base/component' + +export class Client extends Component { + template() { + return `
` + } +} From 65080e9784e9ebc69ef4bda259cbbb2eccd48890 Mon Sep 17 00:00:00 2001 From: cemalturkcan Date: Wed, 25 Mar 2026 10:54:44 +0300 Subject: [PATCH 05/26] feat(ssg): add Head management, 404, robots.txt, minification, and trailing slash - Add component for per-page title, meta, og, twitter, canonical, JSON-LD - Generate 404.html from wildcard (*) routes - Generate robots.txt with configurable allow/disallow rules - Add sitemap lastmod from Head config dates - Add HTML minification (preserves pre/code/script/style) - Add trailing slash configuration for output paths - Add 29 head tests, 10 generate tests for new features - Update README and docs with new feature documentation --- docs/tooling/ssg.md | 172 ++++++++++++++-- examples/ssg-basic/src/App.tsx | 5 +- examples/ssg-basic/src/views/About.tsx | 3 +- examples/ssg-basic/src/views/Blog.tsx | 3 +- examples/ssg-basic/src/views/BlogPost.tsx | 15 +- examples/ssg-basic/src/views/Contact.tsx | 3 +- examples/ssg-basic/src/views/Home.tsx | 3 +- examples/ssg-basic/src/views/NotFound.tsx | 16 ++ examples/ssg-basic/vite.config.ts | 2 + packages/gea-ssg/README.md | 140 +++++++++++-- packages/gea-ssg/src/crawl.ts | 12 +- packages/gea-ssg/src/generate.ts | 97 +++++++-- packages/gea-ssg/src/head.ts | 91 +++++++++ packages/gea-ssg/src/index.ts | 4 + packages/gea-ssg/src/types.ts | 9 + packages/gea-ssg/src/vite-plugin.ts | 29 ++- packages/gea-ssg/tests/crawl.test.ts | 7 +- packages/gea-ssg/tests/generate.test.ts | 230 +++++++++++++++++++++- packages/gea-ssg/tests/head.test.ts | 151 ++++++++++++++ packages/gea/src/index.ts | 1 + packages/gea/src/lib/head.ts | 64 ++++++ 21 files changed, 998 insertions(+), 59 deletions(-) create mode 100644 examples/ssg-basic/src/views/NotFound.tsx create mode 100644 packages/gea-ssg/src/head.ts create mode 100644 packages/gea-ssg/tests/head.test.ts create mode 100644 packages/gea/src/lib/head.ts diff --git a/docs/tooling/ssg.md b/docs/tooling/ssg.md index fa17b68..6d99f70 100644 --- a/docs/tooling/ssg.md +++ b/docs/tooling/ssg.md @@ -1,6 +1,6 @@ # Static Site Generation -`@geajs/ssg` pre-renders your Gea application to static HTML at build time. Every route becomes an `index.html` file with zero client JavaScript — instant loads, full SEO, and no runtime overhead. +`@geajs/ssg` pre-renders your Gea application to static HTML at build time. Every route becomes an HTML file with zero client JavaScript — instant loads, full SEO, and no runtime overhead. ## Installation @@ -26,6 +26,8 @@ export default defineConfig({ geaSSG({ contentDir: 'src/content', sitemap: { hostname: 'https://example.com' }, + robots: true, + minify: true, }), ], }) @@ -34,19 +36,21 @@ export default defineConfig({ Your `src/App.tsx` must export a `routes` object and `App` (or a default export): ```tsx -import { Component, RouterView, Link } from '@geajs/core' +import { Component, RouterView, Link, Head } from '@geajs/core' export const routes = { '/': Home, '/about': About, '/blog': Blog, '/blog/:slug': { component: BlogPost, content: 'blog' }, + '*': NotFound, } export default class App extends Component { template() { return (
+
') + assert.ok(!result.includes('comment')) + assert.ok(result.includes('

text

')) + }) + + it('preserves conditional comments', () => { + const result = minifyHtml('

ok

') + assert.ok(result.includes('
  preserved  

more

' + const result = minifyHtml(input) + assert.ok(!result.includes('comment')) + assert.ok(result.includes(' preserved ')) + }) +}) diff --git a/packages/gea/src/index.ts b/packages/gea/src/index.ts index 05f8d9c..19da101 100644 --- a/packages/gea/src/index.ts +++ b/packages/gea/src/index.ts @@ -9,6 +9,7 @@ export { applyListChanges } from './lib/base/list' export type { ListConfig } from './lib/base/list' export { createRouter, Router, router, matchRoute, resolveRoute, Link, Outlet, RouterView } from './lib/router' export { Client } from './lib/client' +export { Head } from './lib/head' export type { RouteMap, RouteEntry, diff --git a/packages/gea/src/lib/head.ts b/packages/gea/src/lib/head.ts new file mode 100644 index 0000000..e13d0eb --- /dev/null +++ b/packages/gea/src/lib/head.ts @@ -0,0 +1,64 @@ +import Component from './base/component' + +export class Head extends Component { + static _current: Record | null = null + + template() { + if (!Head._current) Head._current = {} + const props = this.props || {} + for (const [key, value] of Object.entries(props)) { + if (key === 'id') continue + if (Array.isArray(value) && Array.isArray(Head._current[key])) { + Head._current[key] = [...Head._current[key], ...value] + } else { + Head._current[key] = value + } + } + + if (typeof document !== 'undefined' && !Component._ssgMode) { + this._updateHead() + return `` + } + + return '' + } + + _updateHead() { + const props = this.props || {} + if (props.title) document.title = props.title + + this._setMeta('description', props.description) + this._setMeta('og:title', props.title) + this._setMeta('og:description', props.description) + this._setMeta('og:image', props.image) + this._setMeta('og:url', props.url) + this._setMeta('og:type', props.type || (props.title ? 'website' : undefined)) + this._setMeta('twitter:title', props.title) + this._setMeta('twitter:description', props.description) + this._setMeta('twitter:image', props.image) + if (props.image) this._setMeta('twitter:card', 'summary_large_image') + + if (props.url) { + let el = document.querySelector('link[rel="canonical"]') as HTMLLinkElement + if (!el) { + el = document.createElement('link') + el.rel = 'canonical' + document.head.appendChild(el) + } + el.href = props.url + } + } + + _setMeta(nameOrProperty: string, content?: string) { + if (!content) return + const isOg = nameOrProperty.startsWith('og:') || nameOrProperty.startsWith('twitter:') + const attr = isOg ? 'property' : 'name' + let el = document.querySelector(`meta[${attr}="${nameOrProperty}"]`) as HTMLMetaElement + if (!el) { + el = document.createElement('meta') + el.setAttribute(attr, nameOrProperty) + document.head.appendChild(el) + } + el.content = content + } +} From d5534719d51c8dd33dfd2f9d9238f4db85bd37de Mon Sep 17 00:00:00 2001 From: cemalturkcan Date: Wed, 25 Mar 2026 11:22:26 +0300 Subject: [PATCH 06/26] =?UTF-8?q?fix:=20resolve=20reviewer=20issues=20?= =?UTF-8?q?=E2=80=94=20LiveClock=20separate=20file,=20Head=20browser=20met?= =?UTF-8?q?a/link/jsonld=20support,=20trailingSlash=20showcase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/ssg-basic/src/styles.css | 31 ++++++++++++++++++++ examples/ssg-basic/src/views/Contact.tsx | 6 +++- examples/ssg-basic/src/views/LiveClock.tsx | 20 +++++++++++++ examples/ssg-basic/vite.config.ts | 1 + packages/gea/src/lib/head.ts | 34 ++++++++++++++++++++++ 5 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 examples/ssg-basic/src/views/LiveClock.tsx diff --git a/examples/ssg-basic/src/styles.css b/examples/ssg-basic/src/styles.css index 604762b..64552d8 100644 --- a/examples/ssg-basic/src/styles.css +++ b/examples/ssg-basic/src/styles.css @@ -190,3 +190,34 @@ body { color: var(--text-muted); line-height: 1.7; } + +.live-clock { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 8px 16px; + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: 8px; + font-size: 0.85rem; + color: var(--text-muted); + margin-top: 16px; +} + +.clock-dot { + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--accent); + animation: pulse 2s ease-in-out infinite; +} + +@keyframes pulse { + 0%, + 100% { + opacity: 1; + } + 50% { + opacity: 0.3; + } +} diff --git a/examples/ssg-basic/src/views/Contact.tsx b/examples/ssg-basic/src/views/Contact.tsx index 678cc2a..6a9cbfa 100644 --- a/examples/ssg-basic/src/views/Contact.tsx +++ b/examples/ssg-basic/src/views/Contact.tsx @@ -1,4 +1,5 @@ -import { Component, Head } from '@geajs/core' +import { Component, Head, Client } from '@geajs/core' +import LiveClock from './LiveClock' export default class Contact extends Component { template() { @@ -19,6 +20,9 @@ export default class Contact extends Component {

Email

hello@geajs.dev

+ + +
) } diff --git a/examples/ssg-basic/src/views/LiveClock.tsx b/examples/ssg-basic/src/views/LiveClock.tsx new file mode 100644 index 0000000..3a95cae --- /dev/null +++ b/examples/ssg-basic/src/views/LiveClock.tsx @@ -0,0 +1,20 @@ +import { Component } from '@geajs/core' + +export default class LiveClock extends Component { + time = new Date().toLocaleTimeString() + + created() { + setInterval(() => { + this.time = new Date().toLocaleTimeString() + }, 1000) + } + + template() { + return ( +
+ + Live — {this.time} +
+ ) + } +} diff --git a/examples/ssg-basic/vite.config.ts b/examples/ssg-basic/vite.config.ts index 397e5a6..c3ac8f6 100644 --- a/examples/ssg-basic/vite.config.ts +++ b/examples/ssg-basic/vite.config.ts @@ -13,6 +13,7 @@ export default defineConfig({ }, robots: true, minify: true, + trailingSlash: false, }), ], resolve: { diff --git a/packages/gea/src/lib/head.ts b/packages/gea/src/lib/head.ts index e13d0eb..cb6c3eb 100644 --- a/packages/gea/src/lib/head.ts +++ b/packages/gea/src/lib/head.ts @@ -47,6 +47,40 @@ export class Head extends Component { } el.href = props.url } + + if (props.meta) { + for (const tag of props.meta) { + const key = tag.property || tag.name + if (key) this._setMeta(key, tag.content) + } + } + + if (props.link) { + for (const attrs of props.link) { + const selector = attrs.rel ? `link[rel="${attrs.rel}"]` : null + let el = selector ? (document.querySelector(selector) as HTMLLinkElement) : null + if (!el) { + el = document.createElement('link') + document.head.appendChild(el) + } + for (const [k, v] of Object.entries(attrs)) { + el.setAttribute(k, v as string) + } + } + } + + if (props.jsonld) { + let el = document.querySelector('script[data-head-jsonld]') as HTMLScriptElement + if (!el) { + el = document.createElement('script') + el.type = 'application/ld+json' + el.setAttribute('data-head-jsonld', '') + document.head.appendChild(el) + } + const data = Array.isArray(props.jsonld) ? props.jsonld : [props.jsonld] + const items = data.map((d: any) => ({ '@context': 'https://schema.org', ...d })) + el.textContent = JSON.stringify(items.length === 1 ? items[0] : items) + } } _setMeta(nameOrProperty: string, content?: string) { From 1e364cedb3c8b2f26aa97cc300ec8e83d59b2a0f Mon Sep 17 00:00:00 2001 From: cemalturkcan Date: Wed, 25 Mar 2026 12:14:59 +0300 Subject: [PATCH 07/26] fix: resolve build hang from lingering Vite server handles, update Client/robots docs --- docs/tooling/ssg.md | 4 ++-- packages/gea-ssg/README.md | 4 ++-- packages/gea-ssg/src/vite-plugin.ts | 3 +++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/tooling/ssg.md b/docs/tooling/ssg.md index 6d99f70..f53ed36 100644 --- a/docs/tooling/ssg.md +++ b/docs/tooling/ssg.md @@ -284,7 +284,7 @@ class Dashboard extends Component { } ``` -During SSG the `` section becomes an empty placeholder. At runtime the child components mount normally. This lets you pre-render the page shell (nav, layout, headings) while deferring interactive parts to the client. +During SSG the `` section becomes an empty placeholder. In dev mode (`vite dev`) the child components render normally. This lets you pre-render the page shell while keeping interactive parts visible during development. ## Layouts @@ -350,7 +350,7 @@ geaSSG({ robots: { disallow: ['/admin', '/private'], allow: ['/public'], - sitemap: 'https://example.com/sitemap.xml', + sitemap: false, }, }) ``` diff --git a/packages/gea-ssg/README.md b/packages/gea-ssg/README.md index f96c89f..daa6db5 100644 --- a/packages/gea-ssg/README.md +++ b/packages/gea-ssg/README.md @@ -201,7 +201,7 @@ class Dashboard extends Component { } ``` -During SSG the `` section becomes an empty placeholder. At runtime the child components mount normally. +During SSG the `` section becomes an empty placeholder. In dev mode (`vite dev`) the child components render normally. ### Layouts and Outlets @@ -229,7 +229,7 @@ geaSSG({ robots: { disallow: ['/admin', '/private'], allow: ['/public'], - sitemap: 'https://example.com/sitemap.xml', + sitemap: false, }, }) ``` diff --git a/packages/gea-ssg/src/vite-plugin.ts b/packages/gea-ssg/src/vite-plugin.ts index d197f11..5664cfb 100644 --- a/packages/gea-ssg/src/vite-plugin.ts +++ b/packages/gea-ssg/src/vite-plugin.ts @@ -80,6 +80,9 @@ export function geaSSG(options: SSGPluginOptions = {}): Plugin[] { await generate(ssgOpts) } finally { await viteServer.close() + // Vite middleware-mode server can leave lingering handles. + // All files are already written — schedule clean exit as fallback. + setTimeout(() => process.exit(0), 1500).unref() } } catch (error) { console.error('[gea-ssg] SSG error:', error) From d56ec53e708ba0f47688aa024896a0cbae9ef1a2 Mon Sep 17 00:00:00 2001 From: cemalturkcan Date: Wed, 25 Mar 2026 13:00:44 +0300 Subject: [PATCH 08/26] =?UTF-8?q?fix:=20reviewer=20fixes=20=E2=80=94=20Hea?= =?UTF-8?q?d=20stale=20tag=20cleanup,=20ESM=20preview,=20deterministic=20s?= =?UTF-8?q?itemap,=20SSGRouteConfig=20type,=20build=20hang?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/gea-ssg/src/generate.ts | 7 +++-- packages/gea-ssg/src/vite-plugin.ts | 41 ++++++++++++++++++++++------ packages/gea/src/index.ts | 1 + packages/gea/src/lib/head.ts | 30 ++++++++++++++++++++ packages/gea/src/lib/router/index.ts | 1 + packages/gea/src/lib/router/types.ts | 7 +++++ 6 files changed, 76 insertions(+), 11 deletions(-) diff --git a/packages/gea-ssg/src/generate.ts b/packages/gea-ssg/src/generate.ts index 31bcc28..973ad7c 100644 --- a/packages/gea-ssg/src/generate.ts +++ b/packages/gea-ssg/src/generate.ts @@ -89,7 +89,7 @@ export async function generate(options: SSGOptions): Promise { Link._ssgCurrentPath = null } - let fullHtml = stripScripts(injectIntoShell(shellParts, html)) + let fullHtml = injectIntoShell(shellParts, html) if (Head._current) { const headConfig = { ...Head._current } as HeadConfig @@ -118,6 +118,8 @@ export async function generate(options: SSGOptions): Promise { if (transformed) fullHtml = transformed } + fullHtml = stripScripts(fullHtml) + if (minify) { fullHtml = minifyHtml(fullHtml) } @@ -207,7 +209,8 @@ async function generateSitemap( ): Promise { const { hostname, changefreq = 'weekly', priority = 0.8, exclude = [] } = options - const urls = pages + const urls = [...pages] + .sort((a, b) => a.path.localeCompare(b.path)) .filter((p) => !exclude.includes(p.path) && p.path !== '/404') .map((p) => { const head = headConfigs.get(p.path) diff --git a/packages/gea-ssg/src/vite-plugin.ts b/packages/gea-ssg/src/vite-plugin.ts index 5664cfb..6c0e84c 100644 --- a/packages/gea-ssg/src/vite-plugin.ts +++ b/packages/gea-ssg/src/vite-plugin.ts @@ -1,5 +1,5 @@ import { dirname, join, extname, resolve } from 'node:path' -import { existsSync } from 'node:fs' +import { existsSync, createReadStream } from 'node:fs' import { fileURLToPath } from 'node:url' import type { Plugin, ResolvedConfig } from 'vite' import type { SSGPluginOptions } from './types' @@ -35,13 +35,37 @@ export function geaSSG(options: SSGPluginOptions = {}): Plugin[] { console.log('[gea-ssg] Starting static page generation...') try { - const { createServer } = await import('vite') + const { createServer, loadConfigFromFile } = await import('vite') + + let userPlugins: any[] = [] + let userAlias: Record = {} + + if (config.configFile) { + const loaded = await loadConfigFromFile( + { command: 'serve', mode: config.mode }, + config.configFile, + config.root, + ) + if (loaded?.config) { + userPlugins = ((loaded.config.plugins || []) as any[]) + .flat(Infinity) + .filter((p: any) => p && typeof p === 'object' && 'name' in p && !p.name.startsWith('gea-ssg')) + const alias = loaded.config.resolve?.alias + if (alias && typeof alias === 'object' && !Array.isArray(alias)) { + userAlias = alias as Record + } + } + } + const viteServer = await createServer({ - configFile: config.configFile, - server: { middlewareMode: true }, + configFile: false, + root: config.root, + server: { middlewareMode: true, hmr: false, watch: null }, appType: 'custom', + plugins: userPlugins, + optimizeDeps: { noDiscovery: true, include: [] }, resolve: { - alias: { '@geajs/ssg': SSG_SRC_DIR + '/index.ts' }, + alias: { ...userAlias, '@geajs/ssg': SSG_SRC_DIR + '/index.ts' }, }, }) @@ -80,10 +104,10 @@ export function geaSSG(options: SSGPluginOptions = {}): Plugin[] { await generate(ssgOpts) } finally { await viteServer.close() - // Vite middleware-mode server can leave lingering handles. - // All files are already written — schedule clean exit as fallback. - setTimeout(() => process.exit(0), 1500).unref() } + // Vite's middlewareMode leaks internal handles after close. + // This timer only fires if leaked handles keep the event loop alive. + setTimeout(() => process.exit(0), 0).unref() } catch (error) { console.error('[gea-ssg] SSG error:', error) throw error @@ -173,7 +197,6 @@ export function geaSSG(options: SSGPluginOptions = {}): Plugin[] { const notFoundPath = join(config.build.outDir, '404.html') if (existsSync(notFoundPath)) { res.statusCode = 404 - const { createReadStream } = require('fs') createReadStream(notFoundPath).pipe(res) return } diff --git a/packages/gea/src/index.ts b/packages/gea/src/index.ts index 19da101..cd3dde1 100644 --- a/packages/gea/src/index.ts +++ b/packages/gea/src/index.ts @@ -14,6 +14,7 @@ export type { RouteMap, RouteEntry, RouteGroupConfig, + SSGRouteConfig, ResolvedRoute, RouterOptions, GuardFn, diff --git a/packages/gea/src/lib/head.ts b/packages/gea/src/lib/head.ts index cb6c3eb..6c9022c 100644 --- a/packages/gea/src/lib/head.ts +++ b/packages/gea/src/lib/head.ts @@ -25,6 +25,9 @@ export class Head extends Component { _updateHead() { const props = this.props || {} + + this._removeStale(props) + if (props.title) document.title = props.title this._setMeta('description', props.description) @@ -80,7 +83,34 @@ export class Head extends Component { const data = Array.isArray(props.jsonld) ? props.jsonld : [props.jsonld] const items = data.map((d: any) => ({ '@context': 'https://schema.org', ...d })) el.textContent = JSON.stringify(items.length === 1 ? items[0] : items) + } else { + const el = document.querySelector('script[data-head-jsonld]') + if (el) el.remove() + } + } + + _removeStale(props: Record) { + if (!props.url) { + const el = document.querySelector('link[rel="canonical"]') + if (el) el.remove() + } + if (!props.image) { + this._removeMeta('og:image') + this._removeMeta('twitter:image') + this._removeMeta('twitter:card') } + if (!props.description) { + this._removeMeta('description') + this._removeMeta('og:description') + this._removeMeta('twitter:description') + } + } + + _removeMeta(nameOrProperty: string) { + const isOg = nameOrProperty.startsWith('og:') || nameOrProperty.startsWith('twitter:') + const attr = isOg ? 'property' : 'name' + const el = document.querySelector(`meta[${attr}="${nameOrProperty}"]`) + if (el) el.remove() } _setMeta(nameOrProperty: string, content?: string) { diff --git a/packages/gea/src/lib/router/index.ts b/packages/gea/src/lib/router/index.ts index 1ee997f..464027a 100644 --- a/packages/gea/src/lib/router/index.ts +++ b/packages/gea/src/lib/router/index.ts @@ -37,6 +37,7 @@ export type { RouteMap, RouteEntry, RouteGroupConfig, + SSGRouteConfig, ResolvedRoute, RouterOptions, GuardFn, diff --git a/packages/gea/src/lib/router/types.ts b/packages/gea/src/lib/router/types.ts index 8aff9f0..755303b 100644 --- a/packages/gea/src/lib/router/types.ts +++ b/packages/gea/src/lib/router/types.ts @@ -31,11 +31,18 @@ export interface RouteGroupConfig { children: RouteMap } +export interface SSGRouteConfig { + component: ComponentOrLazy + content?: string + paths?: Array<{ params: Record }> +} + export type RouteEntry = | ComponentOrLazy // direct component or lazy | string // static redirect | RedirectConfig // full redirect control | RouteGroupConfig // nested group with layout/guard/children + | SSGRouteConfig // SSG static generation config // Note: dynamic redirects (functions returning strings) are expressed as RedirectConfig // with redirect as a function, NOT as bare functions. This avoids ambiguity with LazyComponent. From 6c89b1fa0d415025436d2dc9559b4e179632a045 Mon Sep 17 00:00:00 2001 From: cemalturkcan Date: Wed, 25 Mar 2026 14:05:06 +0300 Subject: [PATCH 09/26] fix: preview server root URL serving 404 instead of index.html --- packages/gea-ssg/src/vite-plugin.ts | 30 +++++++++++++---------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/packages/gea-ssg/src/vite-plugin.ts b/packages/gea-ssg/src/vite-plugin.ts index 6c0e84c..37dffd2 100644 --- a/packages/gea-ssg/src/vite-plugin.ts +++ b/packages/gea-ssg/src/vite-plugin.ts @@ -180,27 +180,23 @@ export function geaSSG(options: SSGPluginOptions = {}): Plugin[] { const ts = options.trailingSlash !== false server.middlewares.use((req, res, next) => { - if (req.url && !extname(req.url)) { - const url = req.url.split('?')[0] + if (!req.url || extname(req.url) || req.url === '/') return next() - if (url !== '/') { - const testPath = ts - ? join(config.build.outDir, url, 'index.html') - : join(config.build.outDir, url + '.html') + const url = req.url.split('?')[0] + const testPath = ts ? join(config.build.outDir, url, 'index.html') : join(config.build.outDir, url + '.html') - if (existsSync(testPath)) { - req.url = ts ? (url.endsWith('/') ? url + 'index.html' : url + '/index.html') : url + '.html' - return next() - } - } + if (existsSync(testPath)) { + req.url = ts ? (url.endsWith('/') ? url + 'index.html' : url + '/index.html') : url + '.html' + return next() + } - const notFoundPath = join(config.build.outDir, '404.html') - if (existsSync(notFoundPath)) { - res.statusCode = 404 - createReadStream(notFoundPath).pipe(res) - return - } + const notFoundPath = join(config.build.outDir, '404.html') + if (existsSync(notFoundPath)) { + res.statusCode = 404 + createReadStream(notFoundPath).pipe(res) + return } + next() }) }, From 63a8e9798a845a24f48e9e7dbd24ca1daeecc0fb Mon Sep 17 00:00:00 2001 From: cemalturkcan Date: Wed, 25 Mar 2026 14:39:35 +0300 Subject: [PATCH 10/26] =?UTF-8?q?feat(ssg):=20enable=20client-side=20takeo?= =?UTF-8?q?ver=20=E2=80=94=20keep=20scripts,=20add=20reactive=20Counter=20?= =?UTF-8?q?example?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/tooling/ssg.md | 4 +-- examples/ssg-basic/src/main.ts | 2 ++ examples/ssg-basic/src/styles.css | 31 ++++++++++++++++++++++++ examples/ssg-basic/src/views/Contact.tsx | 6 +++++ examples/ssg-basic/src/views/Counter.tsx | 23 ++++++++++++++++++ packages/gea-ssg/README.md | 4 +-- packages/gea-ssg/src/generate.ts | 9 ++++--- packages/gea-ssg/src/index.ts | 2 +- packages/gea-ssg/tests/generate.test.ts | 6 ++--- 9 files changed, 76 insertions(+), 11 deletions(-) create mode 100644 examples/ssg-basic/src/views/Counter.tsx diff --git a/docs/tooling/ssg.md b/docs/tooling/ssg.md index f53ed36..ef80c2e 100644 --- a/docs/tooling/ssg.md +++ b/docs/tooling/ssg.md @@ -1,6 +1,6 @@ # Static Site Generation -`@geajs/ssg` pre-renders your Gea application to static HTML at build time. Every route becomes an HTML file with zero client JavaScript — instant loads, full SEO, and no runtime overhead. +`@geajs/ssg` pre-renders your Gea application to static HTML at build time. Every route becomes an HTML file — instant first paint, full SEO, and client-side interactivity after JS loads. ## Installation @@ -284,7 +284,7 @@ class Dashboard extends Component { } ``` -During SSG the `` section becomes an empty placeholder. In dev mode (`vite dev`) the child components render normally. This lets you pre-render the page shell while keeping interactive parts visible during development. +During SSG the `` section becomes an empty placeholder in the pre-rendered HTML. Once JavaScript loads, the child components mount and become interactive. This is ideal for heavy libraries (Three.js, chart libraries) or interactive widgets that don't need to be in the initial HTML. ## Layouts diff --git a/examples/ssg-basic/src/main.ts b/examples/ssg-basic/src/main.ts index ad05e69..ae501a0 100644 --- a/examples/ssg-basic/src/main.ts +++ b/examples/ssg-basic/src/main.ts @@ -4,5 +4,7 @@ import './styles.css' const root = document.getElementById('app') if (!root) throw new Error('App root element not found') +root.innerHTML = '' + const app = new App() app.render(root) diff --git a/examples/ssg-basic/src/styles.css b/examples/ssg-basic/src/styles.css index 64552d8..32b7a55 100644 --- a/examples/ssg-basic/src/styles.css +++ b/examples/ssg-basic/src/styles.css @@ -221,3 +221,34 @@ body { opacity: 0.3; } } + +.counter { + display: flex; + align-items: center; + gap: 16px; + margin-top: 12px; +} + +.counter button { + width: 36px; + height: 36px; + border-radius: 8px; + border: 1px solid var(--border); + background: var(--surface); + color: var(--text); + font-size: 1.2rem; + cursor: pointer; + transition: background 0.15s; +} + +.counter button:hover { + background: var(--accent); + color: #fff; +} + +.counter-value { + font-size: 1.5rem; + font-weight: 600; + min-width: 40px; + text-align: center; +} diff --git a/examples/ssg-basic/src/views/Contact.tsx b/examples/ssg-basic/src/views/Contact.tsx index 6a9cbfa..af69070 100644 --- a/examples/ssg-basic/src/views/Contact.tsx +++ b/examples/ssg-basic/src/views/Contact.tsx @@ -1,4 +1,5 @@ import { Component, Head, Client } from '@geajs/core' +import Counter from './Counter' import LiveClock from './LiveClock' export default class Contact extends Component { @@ -20,6 +21,11 @@ export default class Contact extends Component {

Email

hello@geajs.dev

+
+

Reactive Counter

+

This counter works after JS loads — SSG renders the initial state.

+ +
diff --git a/examples/ssg-basic/src/views/Counter.tsx b/examples/ssg-basic/src/views/Counter.tsx new file mode 100644 index 0000000..e97dce6 --- /dev/null +++ b/examples/ssg-basic/src/views/Counter.tsx @@ -0,0 +1,23 @@ +import { Component } from '@geajs/core' + +export default class Counter extends Component { + count = 0 + + increment() { + this.count++ + } + + decrement() { + this.count-- + } + + template() { + return ( +
+ + {this.count} + +
+ ) + } +} diff --git a/packages/gea-ssg/README.md b/packages/gea-ssg/README.md index daa6db5..c8fb249 100644 --- a/packages/gea-ssg/README.md +++ b/packages/gea-ssg/README.md @@ -2,7 +2,7 @@ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/dashersw/gea/blob/master/LICENSE) -Static site generation plugin for [Gea](https://www.npmjs.com/package/@geajs/core). Pre-renders your routes to static HTML at build time — zero client JavaScript, instant page loads, SEO-friendly output. +Static site generation plugin for [Gea](https://www.npmjs.com/package/@geajs/core). Pre-renders your routes to static HTML at build time — instant first paint, full SEO, and client-side interactivity after JS loads. ## Installation @@ -201,7 +201,7 @@ class Dashboard extends Component { } ``` -During SSG the `` section becomes an empty placeholder. In dev mode (`vite dev`) the child components render normally. +During SSG the `` section becomes an empty placeholder in the pre-rendered HTML. Once JavaScript loads, the child components mount and become interactive — ideal for heavy libraries like Three.js or interactive widgets that don't need to be in the initial HTML. ### Layouts and Outlets diff --git a/packages/gea-ssg/src/generate.ts b/packages/gea-ssg/src/generate.ts index 973ad7c..1a33c41 100644 --- a/packages/gea-ssg/src/generate.ts +++ b/packages/gea-ssg/src/generate.ts @@ -4,7 +4,7 @@ import { join, dirname, resolve, relative } from 'node:path' import { RouterView, Link, Head } from '@geajs/core' import { renderToString } from './render' import { crawlRoutes } from './crawl' -import { parseShell, injectIntoShell, stripScripts } from './shell' +import { parseShell, injectIntoShell } from './shell' import { preloadContent, clearContentCache, serializeContentCache } from './content' import { buildHeadTags, replaceTitle, minifyHtml } from './head' import type { HeadConfig } from './head' @@ -91,6 +91,11 @@ export async function generate(options: SSGOptions): Promise { let fullHtml = injectIntoShell(shellParts, html) + if (options.contentDir) { + const contentJson = serializeContentCache().replace(/<\//g, '<\\/') + fullHtml = fullHtml.replace('', `\n`) + } + if (Head._current) { const headConfig = { ...Head._current } as HeadConfig headConfigs.set(route.path, headConfig) @@ -118,8 +123,6 @@ export async function generate(options: SSGOptions): Promise { if (transformed) fullHtml = transformed } - fullHtml = stripScripts(fullHtml) - if (minify) { fullHtml = minifyHtml(fullHtml) } diff --git a/packages/gea-ssg/src/index.ts b/packages/gea-ssg/src/index.ts index 930e95b..3393746 100644 --- a/packages/gea-ssg/src/index.ts +++ b/packages/gea-ssg/src/index.ts @@ -5,7 +5,7 @@ export { crawlRoutes } from './crawl' export { generate } from './generate' -export { parseShell, injectIntoShell, stripScripts } from './shell' +export { parseShell, injectIntoShell } from './shell' export type { ShellParts } from './shell' export { ssg, preloadContent, clearContentCache, serializeContentCache, getContentSlugs } from './content' diff --git a/packages/gea-ssg/tests/generate.test.ts b/packages/gea-ssg/tests/generate.test.ts index 7f456c8..67e5774 100644 --- a/packages/gea-ssg/tests/generate.test.ts +++ b/packages/gea-ssg/tests/generate.test.ts @@ -313,7 +313,7 @@ describe('generate', () => { assert.ok(html.includes('
SSG
')) }) - it('strips module scripts from output', async () => { + it('keeps scripts in output for client-side takeover', async () => { await generate({ routes: { '/': HomePage } as any, app: MockApp as any, @@ -322,7 +322,7 @@ describe('generate', () => { }) const html = await readFile(join(tempDir, 'index.html'), 'utf-8') - assert.ok(!html.includes('main.js')) + assert.ok(html.includes('main.js')) }) it('preserves non-JS scripts like JSON-LD', async () => { @@ -341,7 +341,7 @@ describe('generate', () => { const html = await readFile(join(tempDir, 'index.html'), 'utf-8') assert.ok(html.includes('application/ld+json')) - assert.ok(!html.includes('main.js')) + assert.ok(html.includes('main.js')) }) it('generates sitemap when enabled', async () => { From de7120ddc77d598cffd87d744cdd41559f95d5b8 Mon Sep 17 00:00:00 2001 From: cemalturkcan Date: Wed, 25 Mar 2026 14:51:59 +0300 Subject: [PATCH 11/26] fix: Client component renders children in browser mode --- packages/gea/src/lib/client.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/gea/src/lib/client.ts b/packages/gea/src/lib/client.ts index 4480268..84311fc 100644 --- a/packages/gea/src/lib/client.ts +++ b/packages/gea/src/lib/client.ts @@ -2,6 +2,9 @@ import Component from './base/component' export class Client extends Component { template() { - return `
` + if (Component._ssgMode) { + return `
` + } + return `
${this.props?.children || ''}
` } } From 262fc624848f04f171abf8866cfc5e9832d107c7 Mon Sep 17 00:00:00 2001 From: cemalturkcan Date: Wed, 25 Mar 2026 15:09:19 +0300 Subject: [PATCH 12/26] =?UTF-8?q?refactor:=20remove=20Client=20component?= =?UTF-8?q?=20=E2=80=94=20SSG=20renders=20full=20HTML,=20JS=20adds=20react?= =?UTF-8?q?ivity=20after=20load?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/tooling/ssg.md | 24 ------------------------ examples/ssg-basic/src/views/Contact.tsx | 6 ++---- packages/gea-ssg/README.md | 24 ------------------------ packages/gea/src/index.ts | 1 - packages/gea/src/lib/client.ts | 10 ---------- 5 files changed, 2 insertions(+), 63 deletions(-) delete mode 100644 packages/gea/src/lib/client.ts diff --git a/docs/tooling/ssg.md b/docs/tooling/ssg.md index ef80c2e..70421b9 100644 --- a/docs/tooling/ssg.md +++ b/docs/tooling/ssg.md @@ -262,30 +262,6 @@ class NotFound extends Component { The preview server automatically serves `404.html` for unmatched routes. -## Client-Only Content - -Wrap parts of a component's template with `` to exclude them from static output. The wrapped content renders only in the browser: - -```tsx -import { Component, Client } from '@geajs/core' - -class Dashboard extends Component { - template() { - return ( -
-

Dashboard

- - - - -
- ) - } -} -``` - -During SSG the `` section becomes an empty placeholder in the pre-rendered HTML. Once JavaScript loads, the child components mount and become interactive. This is ideal for heavy libraries (Three.js, chart libraries) or interactive widgets that don't need to be in the initial HTML. - ## Layouts Route groups with `layout` components work automatically. The SSG renders layouts wrapping page content through `Outlet`, just like client-side rendering: diff --git a/examples/ssg-basic/src/views/Contact.tsx b/examples/ssg-basic/src/views/Contact.tsx index af69070..6d65ec2 100644 --- a/examples/ssg-basic/src/views/Contact.tsx +++ b/examples/ssg-basic/src/views/Contact.tsx @@ -1,4 +1,4 @@ -import { Component, Head, Client } from '@geajs/core' +import { Component, Head } from '@geajs/core' import Counter from './Counter' import LiveClock from './LiveClock' @@ -26,9 +26,7 @@ export default class Contact extends Component {

This counter works after JS loads — SSG renders the initial state.

- - - + ) } diff --git a/packages/gea-ssg/README.md b/packages/gea-ssg/README.md index c8fb249..f670832 100644 --- a/packages/gea-ssg/README.md +++ b/packages/gea-ssg/README.md @@ -179,30 +179,6 @@ class NotFound extends Component { The preview server automatically serves `404.html` for unmatched routes. -### Client-Only Content - -Wrap parts of a template with the `` tag to exclude them from static output. The wrapped content only renders in the browser: - -```tsx -import { Component, Client } from '@geajs/core' - -class Dashboard extends Component { - template() { - return ( -
-

Dashboard

- - - - -
- ) - } -} -``` - -During SSG the `` section becomes an empty placeholder in the pre-rendered HTML. Once JavaScript loads, the child components mount and become interactive — ideal for heavy libraries like Three.js or interactive widgets that don't need to be in the initial HTML. - ### Layouts and Outlets Route groups with `layout` components are rendered with proper nesting — the layout wraps the page content through `Outlet`. diff --git a/packages/gea/src/index.ts b/packages/gea/src/index.ts index cd3dde1..8504484 100644 --- a/packages/gea/src/index.ts +++ b/packages/gea/src/index.ts @@ -8,7 +8,6 @@ export { resetUidCounter } from './lib/base/uid' export { applyListChanges } from './lib/base/list' export type { ListConfig } from './lib/base/list' export { createRouter, Router, router, matchRoute, resolveRoute, Link, Outlet, RouterView } from './lib/router' -export { Client } from './lib/client' export { Head } from './lib/head' export type { RouteMap, diff --git a/packages/gea/src/lib/client.ts b/packages/gea/src/lib/client.ts deleted file mode 100644 index 84311fc..0000000 --- a/packages/gea/src/lib/client.ts +++ /dev/null @@ -1,10 +0,0 @@ -import Component from './base/component' - -export class Client extends Component { - template() { - if (Component._ssgMode) { - return `
` - } - return `
${this.props?.children || ''}
` - } -} From 19355f4979b55fec5e5753e23182a3b63ccf9d58 Mon Sep 17 00:00:00 2001 From: cemalturkcan Date: Wed, 25 Mar 2026 15:24:05 +0300 Subject: [PATCH 13/26] fix: resolve @geajs/ssg via alias in production build instead of marking external --- packages/gea-ssg/src/vite-plugin.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/gea-ssg/src/vite-plugin.ts b/packages/gea-ssg/src/vite-plugin.ts index 37dffd2..a9b24e9 100644 --- a/packages/gea-ssg/src/vite-plugin.ts +++ b/packages/gea-ssg/src/vite-plugin.ts @@ -19,10 +19,8 @@ export function geaSSG(options: SSGPluginOptions = {}): Plugin[] { config() { return { - build: { - rollupOptions: { - external: ['@geajs/ssg'], - }, + resolve: { + alias: { '@geajs/ssg': SSG_SRC_DIR + '/client.ts' }, }, } }, From 334704921a1afb33bdafa312e9e1d08c421edfb5 Mon Sep 17 00:00:00 2001 From: cemalturkcan Date: Wed, 25 Mar 2026 15:48:45 +0300 Subject: [PATCH 14/26] refactor: extract __SSG_CONTENT__ to separate _ssg/content.js file, strip raw markdown from client payload --- packages/gea-ssg/src/client.ts | 3 ++- packages/gea-ssg/src/content.ts | 9 +++++++++ packages/gea-ssg/src/generate.ts | 13 ++++++++++--- packages/gea-ssg/src/index.ts | 9 ++++++++- packages/gea-ssg/src/types.ts | 2 ++ packages/gea-ssg/src/vite-plugin.ts | 3 ++- 6 files changed, 33 insertions(+), 6 deletions(-) diff --git a/packages/gea-ssg/src/client.ts b/packages/gea-ssg/src/client.ts index c97a312..2b55171 100644 --- a/packages/gea-ssg/src/client.ts +++ b/packages/gea-ssg/src/client.ts @@ -1,7 +1,8 @@ export interface ContentFile> { slug: string frontmatter: T - content: string + /** Raw markdown — available during SSR, omitted in client bundle */ + content?: string html: string } diff --git a/packages/gea-ssg/src/content.ts b/packages/gea-ssg/src/content.ts index 1d25e8d..63dc1c1 100644 --- a/packages/gea-ssg/src/content.ts +++ b/packages/gea-ssg/src/content.ts @@ -59,6 +59,15 @@ export function serializeContentCache(): string { return JSON.stringify(obj) } +/** Serialize for client bundle — strips raw markdown `content` field to reduce payload */ +export function serializeContentCacheForClient(): string { + const obj: Record[]> = {} + for (const [key, value] of cache) { + obj[key] = value.map(({ content: _content, ...rest }) => rest) + } + return JSON.stringify(obj) +} + export function getContentSlugs(subdir: string): string[] { return (cache.get(subdir) || []).map((f) => f.slug) } diff --git a/packages/gea-ssg/src/generate.ts b/packages/gea-ssg/src/generate.ts index 1a33c41..0ad3608 100644 --- a/packages/gea-ssg/src/generate.ts +++ b/packages/gea-ssg/src/generate.ts @@ -5,7 +5,7 @@ import { RouterView, Link, Head } from '@geajs/core' import { renderToString } from './render' import { crawlRoutes } from './crawl' import { parseShell, injectIntoShell } from './shell' -import { preloadContent, clearContentCache, serializeContentCache } from './content' +import { preloadContent, clearContentCache, serializeContentCache, serializeContentCacheForClient } from './content' import { buildHeadTags, replaceTitle, minifyHtml } from './head' import type { HeadConfig } from './head' import type { SSGOptions, GenerateResult, GeneratedPage, StaticRoute, RobotsOptions } from './types' @@ -92,8 +92,8 @@ export async function generate(options: SSGOptions): Promise { let fullHtml = injectIntoShell(shellParts, html) if (options.contentDir) { - const contentJson = serializeContentCache().replace(/<\//g, '<\\/') - fullHtml = fullHtml.replace('', `\n`) + const base = options.base || '/' + fullHtml = fullHtml.replace('', `\n`) } if (Head._current) { @@ -149,6 +149,13 @@ export async function generate(options: SSGOptions): Promise { await runWithConcurrency(staticRoutes, renderRoute, concurrency) + if (options.contentDir) { + const ssgDir = join(outDir, '_ssg') + await mkdir(ssgDir, { recursive: true }) + const clientJson = serializeContentCacheForClient().replace(/<\//g, '<\\/') + await writeFile(join(ssgDir, 'content.js'), `window.__SSG_CONTENT__=${clientJson}`, 'utf-8') + } + if (sitemap) { const sitemapOpts = typeof sitemap === 'boolean' ? { hostname: 'https://example.com' } : sitemap await generateSitemap(pages, sitemapOpts, outDir, headConfigs, trailingSlash) diff --git a/packages/gea-ssg/src/index.ts b/packages/gea-ssg/src/index.ts index 3393746..1d35c88 100644 --- a/packages/gea-ssg/src/index.ts +++ b/packages/gea-ssg/src/index.ts @@ -8,7 +8,14 @@ export { generate } from './generate' export { parseShell, injectIntoShell } from './shell' export type { ShellParts } from './shell' -export { ssg, preloadContent, clearContentCache, serializeContentCache, getContentSlugs } from './content' +export { + ssg, + preloadContent, + clearContentCache, + serializeContentCache, + serializeContentCacheForClient, + getContentSlugs, +} from './content' export type { ContentFile } from './content' export { buildHeadTags, replaceTitle, minifyHtml } from './head' diff --git a/packages/gea-ssg/src/types.ts b/packages/gea-ssg/src/types.ts index 6bdd726..d7eb56c 100644 --- a/packages/gea-ssg/src/types.ts +++ b/packages/gea-ssg/src/types.ts @@ -5,6 +5,8 @@ export interface SSGOptions { outDir?: string appElementId?: string contentDir?: string + /** Base path for assets (default: '/') */ + base?: string sitemap?: SitemapOptions | boolean robots?: boolean | RobotsOptions minify?: boolean diff --git a/packages/gea-ssg/src/vite-plugin.ts b/packages/gea-ssg/src/vite-plugin.ts index a9b24e9..81ba98d 100644 --- a/packages/gea-ssg/src/vite-plugin.ts +++ b/packages/gea-ssg/src/vite-plugin.ts @@ -73,6 +73,7 @@ export function geaSSG(options: SSGPluginOptions = {}): Plugin[] { const ssgOpts: Record = { shell: `${config.build.outDir}/index.html`, outDir: config.build.outDir, + base: config.base || '/', appElementId: options.appElementId || 'app', contentDir: options.contentDir ? resolve(config.root, options.contentDir) : undefined, sitemap: options.sitemap, @@ -135,7 +136,7 @@ export function geaSSG(options: SSGPluginOptions = {}): Plugin[] { if (!contentLoaded) { const mod = await ctx.server.ssrLoadModule(`${SSG_SRC_DIR}/content.ts`) await mod.preloadContent(resolve(config.root, options.contentDir)) - cachedContentJson = mod.serializeContentCache() + cachedContentJson = mod.serializeContentCacheForClient() contentLoaded = true } From 153815a40eda6dfd12022315b320d9f6f17ed6cd Mon Sep 17 00:00:00 2001 From: cemalturkcan Date: Wed, 25 Mar 2026 16:23:14 +0300 Subject: [PATCH 15/26] fix: add defer to content.js, unify ContentFile type, remove dead code, fix onAfterRender empty string --- packages/gea-ssg/src/client.ts | 14 +++++++------- packages/gea-ssg/src/content.ts | 10 +++------- packages/gea-ssg/src/generate.ts | 6 +++--- packages/gea-ssg/src/index.ts | 2 +- packages/gea-ssg/src/shell.ts | 20 ++------------------ packages/gea-ssg/src/types.ts | 8 ++++++++ packages/gea-ssg/tests/shell.test.ts | 1 - 7 files changed, 24 insertions(+), 37 deletions(-) diff --git a/packages/gea-ssg/src/client.ts b/packages/gea-ssg/src/client.ts index 2b55171..12a53f1 100644 --- a/packages/gea-ssg/src/client.ts +++ b/packages/gea-ssg/src/client.ts @@ -1,10 +1,10 @@ -export interface ContentFile> { - slug: string - frontmatter: T - /** Raw markdown — available during SSR, omitted in client bundle */ - content?: string - html: string -} +/** + * Lightweight browser-only module. + * vite-plugin aliases `@geajs/ssg` to this file for client builds. + * Reads content from `window.__SSG_CONTENT__` injected by the SSG build. + */ +import type { ContentFile } from './types' +export type { ContentFile } from './types' function getData(): Record { const g = globalThis as any diff --git a/packages/gea-ssg/src/content.ts b/packages/gea-ssg/src/content.ts index 63dc1c1..1bb45e7 100644 --- a/packages/gea-ssg/src/content.ts +++ b/packages/gea-ssg/src/content.ts @@ -1,11 +1,7 @@ -const cache = new Map() +import type { ContentFile } from './types' +export type { ContentFile } from './types' -export interface ContentFile> { - slug: string - frontmatter: T - content: string - html: string -} +const cache = new Map() export async function preloadContent(rootDir: string): Promise { const { readdir, readFile } = await import('node:fs/promises') diff --git a/packages/gea-ssg/src/generate.ts b/packages/gea-ssg/src/generate.ts index 0ad3608..0db27e0 100644 --- a/packages/gea-ssg/src/generate.ts +++ b/packages/gea-ssg/src/generate.ts @@ -92,8 +92,8 @@ export async function generate(options: SSGOptions): Promise { let fullHtml = injectIntoShell(shellParts, html) if (options.contentDir) { - const base = options.base || '/' - fullHtml = fullHtml.replace('', `\n`) + const base = (options.base || '/').replace(/\/?$/, '/') + fullHtml = fullHtml.replace(/(]*>)/i, `$1\n`) } if (Head._current) { @@ -120,7 +120,7 @@ export async function generate(options: SSGOptions): Promise { }, fullHtml, ) - if (transformed) fullHtml = transformed + if (transformed !== undefined) fullHtml = transformed } if (minify) { diff --git a/packages/gea-ssg/src/index.ts b/packages/gea-ssg/src/index.ts index 1d35c88..8f642b8 100644 --- a/packages/gea-ssg/src/index.ts +++ b/packages/gea-ssg/src/index.ts @@ -16,7 +16,7 @@ export { serializeContentCacheForClient, getContentSlugs, } from './content' -export type { ContentFile } from './content' +export type { ContentFile } from './types' export { buildHeadTags, replaceTitle, minifyHtml } from './head' export type { HeadConfig } from './head' diff --git a/packages/gea-ssg/src/shell.ts b/packages/gea-ssg/src/shell.ts index 960eda9..655994c 100644 --- a/packages/gea-ssg/src/shell.ts +++ b/packages/gea-ssg/src/shell.ts @@ -1,7 +1,6 @@ export interface ShellParts { before: string after: string - headEnd: number } export function parseShell(html: string, appElementId: string = 'app'): ShellParts { @@ -22,15 +21,13 @@ export function parseShell(html: string, appElementId: string = 'app'): ShellPar const before = html.slice(0, openTagEnd) const after = html.slice(closeIndex) - const headEnd = html.toLowerCase().indexOf('') - - return { before, after, headEnd } + return { before, after } } export function injectIntoShell(shell: ShellParts, renderedHtml: string, headTags?: string): string { let result = shell.before + renderedHtml + shell.after - if (headTags && shell.headEnd !== -1) { + if (headTags) { const headInsertPos = result.toLowerCase().indexOf('') if (headInsertPos !== -1) { result = result.slice(0, headInsertPos) + headTags + result.slice(headInsertPos) @@ -39,16 +36,3 @@ export function injectIntoShell(shell: ShellParts, renderedHtml: string, headTag return result } - -export function stripScripts(html: string): string { - return html.replace(/]*)>[\s\S]*?<\/script>/gi, (_match, attrs: string) => { - const typeMatch = attrs.match(/type\s*=\s*["']([^"']+)["']/i) - if (typeMatch) { - const type = typeMatch[1].toLowerCase() - if (type !== 'module' && type !== 'text/javascript' && type !== 'application/javascript') { - return _match - } - } - return '' - }) -} diff --git a/packages/gea-ssg/src/types.ts b/packages/gea-ssg/src/types.ts index d7eb56c..5181ef7 100644 --- a/packages/gea-ssg/src/types.ts +++ b/packages/gea-ssg/src/types.ts @@ -1,3 +1,11 @@ +export interface ContentFile> { + slug: string + frontmatter: T + /** Raw markdown — available during build, omitted in client payload */ + content?: string + html: string +} + export interface SSGOptions { routes: Record app: new (props?: any) => any diff --git a/packages/gea-ssg/tests/shell.test.ts b/packages/gea-ssg/tests/shell.test.ts index 2a2fd5d..e75cd6f 100644 --- a/packages/gea-ssg/tests/shell.test.ts +++ b/packages/gea-ssg/tests/shell.test.ts @@ -18,7 +18,6 @@ describe('parseShell', () => { const parts = parseShell(BASIC_SHELL) assert.ok(parts.before.endsWith('
')) assert.ok(parts.after.startsWith('
')) - assert.ok(parts.headEnd > 0) }) it('throws when app element is not found', () => { From 2135739fb0e62bdc8e49bf4f6169886c932a7500 Mon Sep 17 00:00:00 2001 From: cemalturkcan Date: Wed, 25 Mar 2026 18:08:10 +0300 Subject: [PATCH 16/26] =?UTF-8?q?feat:=20MPA=20hydration=20architecture=20?= =?UTF-8?q?=E2=80=94=20zero=20JS=20on=20static=20pages,=20selective=20comp?= =?UTF-8?q?onent=20hydration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace full SPA re-render with per-component hydration via data-gea attributes and UID matching. Static pages get zero JavaScript. Interactive pages load only the shared runtime + needed components. - render.ts: inject data-gea attributes on hydrate-listed components during SSG - client.ts: add hydrate() that attaches components to existing SSG DOM - generate.ts: strip `) } @@ -123,6 +123,11 @@ export async function generate(options: SSGOptions): Promise { if (transformed !== undefined) fullHtml = transformed } + if (options.hydrate && !fullHtml.includes('data-gea=')) { + fullHtml = fullHtml.replace(/`) @@ -154,6 +158,7 @@ export async function generate(options: SSGOptions): Promise { await runWithConcurrency(staticRoutes, renderRoute, concurrency) + // In MPA/hydrate mode content.js is intentionally skipped — see note above. if (options.contentDir && !options.hydrate) { const ssgDir = join(outDir, '_ssg') await mkdir(ssgDir, { recursive: true }) @@ -163,6 +168,11 @@ export async function generate(options: SSGOptions): Promise { if (sitemap) { const sitemapOpts = typeof sitemap === 'boolean' ? { hostname: 'https://example.com' } : sitemap + if (typeof sitemap === 'boolean') { + console.warn( + '[gea-ssg] sitemap: true uses placeholder hostname "https://example.com". Pass { hostname: "https://your-site.com" } for production.', + ) + } await generateSitemap(pages, sitemapOpts, outDir, headConfigs, trailingSlash) } diff --git a/packages/gea-ssg/src/head.ts b/packages/gea-ssg/src/head.ts index 7d2dbc6..b4a75d4 100644 --- a/packages/gea-ssg/src/head.ts +++ b/packages/gea-ssg/src/head.ts @@ -10,6 +10,7 @@ export interface HeadConfig { link?: Array> } +/** Build ``, ``, and JSON-LD `