From beabfac8c13031ea1b9e7dd0b5cc9d16e7709119 Mon Sep 17 00:00:00 2001 From: Aperrix Date: Fri, 13 Mar 2026 09:16:12 +0100 Subject: [PATCH 01/10] feat(astro): add @json-render/astro SSR HTML renderer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New package that transforms json-render specs into HTML strings on the server. Zero framework dependencies — works in Astro, Cloudflare Workers, Node.js, Deno, Bun. Includes schema, catalog types, renderToHtml(), escapeHtml(), and full test suite. --- packages/astro/README.md | 187 +++++++++++++ packages/astro/package.json | 69 +++++ packages/astro/src/catalog-types.ts | 52 ++++ packages/astro/src/index.ts | 18 ++ packages/astro/src/render.test.ts | 407 ++++++++++++++++++++++++++++ packages/astro/src/render.ts | 183 +++++++++++++ packages/astro/src/schema.ts | 56 ++++ packages/astro/src/server.ts | 15 + packages/astro/tsconfig.json | 9 + packages/astro/tsup.config.ts | 10 + pnpm-lock.yaml | 19 ++ 11 files changed, 1025 insertions(+) create mode 100644 packages/astro/README.md create mode 100644 packages/astro/package.json create mode 100644 packages/astro/src/catalog-types.ts create mode 100644 packages/astro/src/index.ts create mode 100644 packages/astro/src/render.test.ts create mode 100644 packages/astro/src/render.ts create mode 100644 packages/astro/src/schema.ts create mode 100644 packages/astro/src/server.ts create mode 100644 packages/astro/tsconfig.json create mode 100644 packages/astro/tsup.config.ts diff --git a/packages/astro/README.md b/packages/astro/README.md new file mode 100644 index 00000000..c084b659 --- /dev/null +++ b/packages/astro/README.md @@ -0,0 +1,187 @@ +# @json-render/astro + +SSR renderer for `@json-render/core`. JSON becomes HTML on the server. Zero framework dependencies -- works in Astro, Cloudflare Workers, Node.js, Deno, Bun, or any server environment. + +## Install + +```bash +npm install @json-render/core @json-render/astro +``` + +## Quick Start + +### Define a catalog and registry + +```typescript +import { defineCatalog } from "@json-render/core"; +import { schema, renderToHtml, escapeHtml } from "@json-render/astro"; +import { z } from "zod"; + +const catalog = defineCatalog(schema, { + components: { + Section: { + props: z.object({ + id: z.string().nullable(), + }), + description: "A content section", + }, + Heading: { + props: z.object({ + text: z.string(), + level: z.enum(["h1", "h2", "h3"]).nullable(), + }), + description: "Heading text", + }, + Text: { + props: z.object({ + content: z.string(), + }), + description: "Body text paragraph", + }, + }, +}); + +// Registry: pure functions that return HTML strings +const registry = { + Section: ({ props, children }) => + `${children}`, + Heading: ({ props }) => + `<${props.level || "h2"}>${escapeHtml(props.text)}`, + Text: ({ props }) => + `

${escapeHtml(props.content)}

`, +}; +``` + +### Render a spec to HTML + +```typescript +import type { Spec } from "@json-render/core"; + +const spec: Spec = { + root: "section-1", + elements: { + "section-1": { + type: "Section", + props: { id: "hero" }, + children: ["heading-1", "text-1"], + }, + "heading-1": { + type: "Heading", + props: { text: "Welcome", level: "h1" }, + children: [], + }, + "text-1": { + type: "Text", + props: { content: "Hello from the server." }, + children: [], + }, + }, +}; + +const html = renderToHtml(spec, { registry }); +// =>

Welcome

Hello from the server.

+``` + +## Usage with Astro + +In an Astro page or component, use `set:html` to inject the rendered HTML: + +```astro +--- +// src/pages/index.astro +import { renderToHtml } from "@json-render/astro"; + +const html = renderToHtml(spec, { registry, state: { showBanner: true } }); +--- + + + +
+ + +``` + +## Usage with Cloudflare Workers + +```typescript +import { renderToHtml, escapeHtml } from "@json-render/astro/render"; + +export default { + async fetch(request: Request): Promise { + const spec = await getSpecFromAI(request); + + const html = renderToHtml(spec, { + registry: { + Card: ({ props, children }) => + `

${escapeHtml(props.title)}

${children}
`, + Text: ({ props }) => + `

${escapeHtml(props.content)}

`, + }, + state: { theme: "dark" }, + }); + + return new Response(`${html}`, { + headers: { "Content-Type": "text/html" }, + }); + }, +}; +``` + +## API Reference + +### `renderToHtml(spec, options)` + +Render a json-render spec to an HTML string. Pure, synchronous, no framework dependencies. + +**Parameters:** + +- `spec` (`Spec`) -- the json-render spec to render +- `options.registry` (`ComponentRegistry`) -- component render functions +- `options.state` (`Record`, optional) -- state for `$state`/`$cond` resolution + +**Returns:** `string` -- the rendered HTML + +### `escapeHtml(str)` + +Escape HTML special characters to prevent XSS. Use in component render functions for any user-provided content. + +### `schema` + +The SSR element schema. Use with `defineCatalog` from core. + +## Server-Safe Import + +Import schema and catalog definitions without the renderer: + +```typescript +import { schema, defineCatalog } from "@json-render/astro/server"; +``` + +## Sub-path Exports + +| Export | Description | +|--------|-------------| +| `@json-render/astro` | Full package: schema, renderer, types | +| `@json-render/astro/server` | Schema and catalog definitions only (no renderer) | +| `@json-render/astro/render` | Render functions and types only | + +## Types + +| Export | Description | +|--------|-------------| +| `AstroSchema` | Schema type for SSR specs | +| `AstroSpec` | Spec type for SSR output | +| `RenderOptions` | Options for `renderToHtml()` | +| `ComponentRenderProps` | Props passed to component render functions | +| `ComponentRenderer` | Component render function type | +| `ComponentRegistry` | Map of component names to render functions | +| `Components` | Typed registry for a specific catalog | +| `ComponentFn` | Typed render function for a specific component | + +## Documentation + +Full API reference: [json-render.dev/docs/api/astro](https://json-render.dev/docs/api/astro). + +## License + +Apache-2.0 diff --git a/packages/astro/package.json b/packages/astro/package.json new file mode 100644 index 00000000..5a406ee2 --- /dev/null +++ b/packages/astro/package.json @@ -0,0 +1,69 @@ +{ + "name": "@json-render/astro", + "version": "0.13.0", + "license": "Apache-2.0", + "description": "Astro SSR renderer for @json-render/core. JSON becomes HTML on the server.", + "keywords": [ + "json", + "astro", + "ssr", + "html", + "ai", + "generative-ui", + "llm", + "renderer", + "cloudflare-workers", + "edge" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/vercel-labs/json-render.git", + "directory": "packages/astro" + }, + "homepage": "https://json-render.dev", + "bugs": { + "url": "https://github.com/vercel-labs/json-render/issues" + }, + "publishConfig": { + "access": "public" + }, + "main": "./dist/index.js", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.mjs", + "require": "./dist/index.js" + }, + "./server": { + "types": "./dist/server.d.ts", + "import": "./dist/server.mjs", + "require": "./dist/server.js" + }, + "./render": { + "types": "./dist/render.d.ts", + "import": "./dist/render.mjs", + "require": "./dist/render.js" + } + }, + "files": ["dist"], + "scripts": { + "build": "tsup", + "dev": "tsup --watch", + "check-types": "tsc --noEmit", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@json-render/core": "workspace:*" + }, + "devDependencies": { + "@internal/typescript-config": "workspace:*", + "tsup": "^8.0.2", + "typescript": "^5.4.5", + "zod": "^4.0.0" + }, + "peerDependencies": { + "zod": "^4.0.0" + } +} diff --git a/packages/astro/src/catalog-types.ts b/packages/astro/src/catalog-types.ts new file mode 100644 index 00000000..ee645da8 --- /dev/null +++ b/packages/astro/src/catalog-types.ts @@ -0,0 +1,52 @@ +import type { + Catalog, + InferCatalogComponents, + InferComponentProps, +} from "@json-render/core"; + +/** + * Props passed to SSR component render functions. + * + * Unlike React/Vue renderers, Astro SSR components receive pre-rendered + * children as an HTML string and return an HTML string. + */ +export interface ComponentRenderProps

> { + /** Resolved props (all $state/$cond expressions already evaluated) */ + props: P; + /** Pre-rendered children as HTML string (already resolved and concatenated) */ + children: string; +} + +/** + * An SSR component render function. + * Takes resolved props + pre-rendered children HTML, returns an HTML string. + * + * @example + * ```ts + * const Card: ComponentRenderer<{ title: string }> = ({ props, children }) => + * `

${escapeHtml(props.title)}

${children}
`; + * ``` + */ +export type ComponentRenderer

> = ( + ctx: ComponentRenderProps

, +) => string; + +/** + * Registry mapping component type names to SSR render functions. + */ +export type ComponentRegistry = Record>; + +/** + * Typed component render function for a specific catalog component. + */ +export type ComponentFn< + C extends Catalog, + K extends keyof InferCatalogComponents, +> = ComponentRenderer>; + +/** + * Typed registry of all component render functions for a catalog. + */ +export type Components = { + [K in keyof InferCatalogComponents]: ComponentFn; +}; diff --git a/packages/astro/src/index.ts b/packages/astro/src/index.ts new file mode 100644 index 00000000..c2c92456 --- /dev/null +++ b/packages/astro/src/index.ts @@ -0,0 +1,18 @@ +// Schema +export { schema, type AstroSchema, type AstroSpec } from "./schema"; + +// Core types (re-exported for convenience) +export type { Spec } from "@json-render/core"; +export { defineCatalog } from "@json-render/core"; + +// Catalog-aware types +export type { + ComponentFn, + Components, + ComponentRenderProps, + ComponentRenderer, + ComponentRegistry, +} from "./catalog-types"; + +// SSR renderer +export { renderToHtml, escapeHtml, type RenderOptions } from "./render"; diff --git a/packages/astro/src/render.test.ts b/packages/astro/src/render.test.ts new file mode 100644 index 00000000..0f370ccb --- /dev/null +++ b/packages/astro/src/render.test.ts @@ -0,0 +1,407 @@ +import { describe, it, expect } from "vitest"; +import type { Spec } from "@json-render/core"; +import { renderToHtml, escapeHtml } from "./render"; +import type { ComponentRegistry } from "./catalog-types"; + +// ============================================================================= +// Test registry — minimal HTML components +// ============================================================================= + +const testRegistry: ComponentRegistry = { + Container: ({ props, children }) => + `

${children}
`, + Heading: ({ props }) => + `<${props.level || "h2"}>${escapeHtml(props.text)}`, + Text: ({ props }) => `

${escapeHtml(props.content)}

`, + Image: ({ props }) => + `${escapeHtml(props.alt)}`, + Card: ({ props, children }) => + `

${escapeHtml(props.title)}

${children}
`, + Link: ({ props, children }) => + `${children || escapeHtml(props.text)}`, + Section: ({ props, children }) => + `${children}`, + List: ({ children }) => `
    ${children}
`, + ListItem: ({ props }) => `
  • ${escapeHtml(props.text)}
  • `, +}; + +// ============================================================================= +// Helpers +// ============================================================================= + +function simpleSpec(elements: Spec["elements"], root = "root"): Spec { + return { root, elements }; +} + +// ============================================================================= +// renderToHtml +// ============================================================================= + +describe("renderToHtml", () => { + it("renders a single element", () => { + const spec = simpleSpec({ + root: { type: "Text", props: { content: "Hello World" }, children: [] }, + }); + const html = renderToHtml(spec, { registry: testRegistry }); + expect(html).toBe("

    Hello World

    "); + }); + + it("renders nested elements", () => { + const spec = simpleSpec({ + root: { + type: "Container", + props: {}, + children: ["heading", "text"], + }, + heading: { + type: "Heading", + props: { text: "Title", level: "h1" }, + children: [], + }, + text: { type: "Text", props: { content: "Body text" }, children: [] }, + }); + const html = renderToHtml(spec, { registry: testRegistry }); + expect(html).toContain("

    Title

    "); + expect(html).toContain("

    Body text

    "); + expect(html).toContain('
    '); + }); + + it("renders deeply nested elements", () => { + const spec = simpleSpec({ + root: { + type: "Container", + props: {}, + children: ["card"], + }, + card: { + type: "Card", + props: { title: "My Card" }, + children: ["inner-text"], + }, + "inner-text": { + type: "Text", + props: { content: "Nested content" }, + children: [], + }, + }); + const html = renderToHtml(spec, { registry: testRegistry }); + expect(html).toContain("My Card"); + expect(html).toContain("Nested content"); + expect(html).toContain('
    '); + expect(html).toContain('
    '); + }); + + it("returns empty string for null/missing spec", () => { + expect(renderToHtml(null as any, { registry: testRegistry })).toBe(""); + expect( + renderToHtml( + { root: "missing", elements: {} }, + { registry: testRegistry }, + ), + ).toBe(""); + }); + + it("skips unknown component types gracefully", () => { + const spec = simpleSpec({ + root: { type: "Unknown", props: {}, children: [] }, + }); + const html = renderToHtml(spec, { registry: testRegistry }); + expect(html).toBe(""); + }); + + it("skips missing child elements gracefully", () => { + const spec = simpleSpec({ + root: { + type: "Container", + props: {}, + children: ["exists", "does-not-exist"], + }, + exists: { type: "Text", props: { content: "I exist" }, children: [] }, + }); + const html = renderToHtml(spec, { registry: testRegistry }); + expect(html).toContain("I exist"); + }); + + it("escapes HTML in props via registry components", () => { + const spec = simpleSpec({ + root: { + type: "Text", + props: { content: '' }, + children: [], + }, + }); + const html = renderToHtml(spec, { registry: testRegistry }); + expect(html).not.toContain("'); +// => <script>alert("xss")</script> +``` + +## Component Registry + +Unlike React/Vue renderers, the Astro SSR registry uses plain functions that return HTML strings. + +```typescript +import type { ComponentRegistry } from '@json-render/astro'; + +const registry: ComponentRegistry = { + Section: ({ props, children }) => + `
    ${children}
    `, + Heading: ({ props }) => + `<${props.level || 'h2'}>${escapeHtml(props.text)}`, + Text: ({ props }) => + `

    ${escapeHtml(props.content)}

    `, +}; +``` + +Each function receives: + + + + + + + + + + + + + + + + + + + + + +
    PropTypeDescription
    propsPResolved props (all $state/$cond expressions already evaluated)
    childrenstringPre-rendered children as HTML string
    + +## Usage with Astro + +```astro +--- +import { renderToHtml } from '@json-render/astro'; + +const html = renderToHtml(spec, { registry }); +--- + +
    +``` + +## Usage with Cloudflare Workers + +```typescript +import { renderToHtml } from '@json-render/astro/render'; + +export default { + async fetch(request) { + const spec = await getSpec(request); + const html = renderToHtml(spec, { registry }); + return new Response(html, { + headers: { 'Content-Type': 'text/html' }, + }); + }, +}; +``` + +## Server-Safe Import + +Import schema and catalog definitions without the renderer: + +```typescript +import { schema, defineCatalog } from '@json-render/astro/server'; +``` + +## Sub-path Exports + + + + + + + + + + + + + + + + + + + + + + +
    ExportDescription
    @json-render/astroFull package: schema, renderer, types
    @json-render/astro/serverSchema and catalog definitions only (no renderer)
    @json-render/astro/renderRender functions and types only
    + +## Types + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ExportDescription
    AstroSchemaSchema type for SSR specs
    AstroSpecSpec type for SSR output
    RenderOptionsOptions for renderToHtml()
    ComponentRenderPropsProps passed to component render functions
    ComponentRendererComponent render function type
    ComponentRegistryMap of component names to render functions
    {"Components"}Typed registry for a specific catalog
    {"ComponentFn"}Typed render function for a specific component
    diff --git a/apps/web/app/api/docs-chat/route.ts b/apps/web/app/api/docs-chat/route.ts index ae4641c3..ea97ec09 100644 --- a/apps/web/app/api/docs-chat/route.ts +++ b/apps/web/app/api/docs-chat/route.ts @@ -16,8 +16,8 @@ const SYSTEM_PROMPT = `You are a helpful documentation assistant for json-render GitHub repository: https://github.com/vercel-labs/json-render Documentation: https://json-render.dev/docs -npm packages: @json-render/core, @json-render/react, @json-render/vue, @json-render/svelte, @json-render/solid, @json-render/shadcn, @json-render/react-three-fiber, @json-render/react-native, @json-render/react-email, @json-render/react-pdf, @json-render/image, @json-render/remotion, @json-render/codegen, @json-render/mcp, @json-render/redux, @json-render/zustand, @json-render/jotai, @json-render/xstate, @json-render/yaml -Skills: json-render ships AI agent skills that teach coding agents how to use each package. Install with "npx skills add vercel-labs/json-render --skill ". Available skills: core, react, react-pdf, react-email, react-native, shadcn, react-three-fiber, image, remotion, vue, svelte, solid, codegen, mcp, redux, zustand, jotai, xstate, yaml. See /docs/skills for details. +npm packages: @json-render/core, @json-render/react, @json-render/vue, @json-render/svelte, @json-render/solid, @json-render/shadcn, @json-render/react-three-fiber, @json-render/react-native, @json-render/react-email, @json-render/react-pdf, @json-render/image, @json-render/remotion, @json-render/codegen, @json-render/mcp, @json-render/redux, @json-render/zustand, @json-render/jotai, @json-render/xstate, @json-render/yaml, @json-render/astro +Skills: json-render ships AI agent skills that teach coding agents how to use each package. Install with "npx skills add vercel-labs/json-render --skill ". Available skills: core, react, react-pdf, react-email, react-native, shadcn, react-three-fiber, image, remotion, vue, svelte, solid, codegen, mcp, redux, zustand, jotai, xstate, yaml, astro. See /docs/skills for details. You have access to the full json-render documentation via the bash and readFile tools. The docs are available as markdown files in the /workspace/docs/ directory. diff --git a/apps/web/lib/docs-navigation.ts b/apps/web/lib/docs-navigation.ts index 172d579c..6c365bec 100644 --- a/apps/web/lib/docs-navigation.ts +++ b/apps/web/lib/docs-navigation.ts @@ -145,6 +145,7 @@ export const docsNavigation: NavSection[] = [ { title: "@json-render/jotai", href: "/docs/api/jotai" }, { title: "@json-render/xstate", href: "/docs/api/xstate" }, { title: "@json-render/yaml", href: "/docs/api/yaml" }, + { title: "@json-render/astro", href: "/docs/api/astro" }, ], }, ]; diff --git a/apps/web/lib/page-titles.ts b/apps/web/lib/page-titles.ts index 679408c7..c7c54ebe 100644 --- a/apps/web/lib/page-titles.ts +++ b/apps/web/lib/page-titles.ts @@ -59,6 +59,7 @@ export const PAGE_TITLES: Record = { "docs/api/react-three-fiber": "@json-render/react-three-fiber API", "docs/api/xstate": "@json-render/xstate API", "docs/api/yaml": "@json-render/yaml API", + "docs/api/astro": "@json-render/astro API", }; /** diff --git a/skills/astro/SKILL.md b/skills/astro/SKILL.md new file mode 100644 index 00000000..f2c49512 --- /dev/null +++ b/skills/astro/SKILL.md @@ -0,0 +1,134 @@ +--- +name: astro +description: SSR HTML renderer for json-render that turns JSON specs into HTML strings on the server. Use when working with @json-render/astro, building server-rendered HTML from JSON, rendering specs in Astro SSR, Cloudflare Workers, Deno, Bun, or any server environment, or when the user mentions SSR HTML rendering, edge rendering, or server-side JSON-to-HTML. +metadata: + tags: astro, ssr, html, json-render, cloudflare-workers, edge, server-rendering +--- + +# @json-render/astro + +SSR renderer that converts JSON specs into HTML strings on the server. Zero framework dependencies. + +## Quick Start + +```typescript +import { renderToHtml, escapeHtml } from "@json-render/astro"; +import { defineCatalog } from "@json-render/core"; +import { schema } from "@json-render/astro"; +import { z } from "zod"; + +const catalog = defineCatalog(schema, { + components: { + Card: { + props: z.object({ title: z.string() }), + description: "A card container", + }, + Text: { + props: z.object({ content: z.string() }), + description: "Body text paragraph", + }, + }, +}); + +const registry = { + Card: ({ props, children }) => + `

    ${escapeHtml(props.title)}

    ${children}
    `, + Text: ({ props }) => + `

    ${escapeHtml(props.content)}

    `, +}; + +const html = renderToHtml(spec, { registry, state: { theme: "dark" } }); +``` + +## Spec Structure (Element Tree) + +Same flat element tree as other json-render renderers: `root` key plus `elements` map. Each element has `type`, `props`, `children`, and optional `visible` and `repeat`. + +## Creating a Registry + +The registry is a plain object mapping component type names to render functions. Each function receives `{ props, children }` and returns an HTML string. + +```typescript +import type { ComponentRegistry } from "@json-render/astro"; + +const registry: ComponentRegistry = { + Section: ({ props, children }) => + `
    ${children}
    `, + Heading: ({ props }) => + `<${props.level || "h2"}>${escapeHtml(props.text)}`, +}; +``` + +Always use `escapeHtml()` for user-provided content to prevent XSS. + +## Server-Side Render API + +| Function | Purpose | +|----------|---------| +| `renderToHtml(spec, options)` | Render spec to HTML string (synchronous) | +| `escapeHtml(str)` | Escape HTML special characters | + +`RenderOptions`: `registry` (required), `state` (optional, for `$state` / `$cond`). + +## Visibility and State + +Supports `visible` conditions, `$state`, `$cond`, `$item`, `$index`, `$template`, and `repeat` (same expression syntax as other renderers). Pass `state` in `RenderOptions` so expressions resolve at render time. + +## Usage with Astro + +```astro +--- +import { renderToHtml } from "@json-render/astro"; +const html = renderToHtml(spec, { registry }); +--- +
    +``` + +## Usage with Cloudflare Workers + +```typescript +import { renderToHtml } from "@json-render/astro/render"; + +export default { + async fetch(request) { + const spec = await getSpec(request); + const html = renderToHtml(spec, { registry }); + return new Response(html, { + headers: { "Content-Type": "text/html" }, + }); + }, +}; +``` + +## Server-Safe Import + +Import schema and catalog without the renderer: + +```typescript +import { schema, defineCatalog } from "@json-render/astro/server"; +``` + +## Key Exports + +| Export | Purpose | +|--------|---------| +| `renderToHtml` | Spec to HTML string (synchronous) | +| `escapeHtml` | Escape HTML special characters | +| `schema` | SSR element schema | +| `defineCatalog` | Re-export from core | + +## Sub-path Exports + +| Path | Purpose | +|------|---------| +| `@json-render/astro` | Full package | +| `@json-render/astro/server` | Schema and catalog only (no renderer) | +| `@json-render/astro/render` | Render functions only | + +## Key Differences from Other Renderers + +- **No framework dependency**: produces raw HTML strings, not React elements or Vue VNodes +- **Synchronous**: `renderToHtml()` is synchronous (no `await` needed), unlike `@json-render/react-email` +- **No actions/state mutations**: SSR-only, no interactive event handlers +- **Registry pattern**: functions return strings, not JSX/components +- **XSS prevention**: use `escapeHtml()` explicitly in render functions From fab576c43c9955da6dfe6bd93bc9643253b51ec0 Mon Sep 17 00:00:00 2001 From: Aperrix Date: Fri, 13 Mar 2026 09:21:25 +0100 Subject: [PATCH 03/10] feat(astro): add Astro SSR example project Minimal Astro app demonstrating renderToHtml() with set:html, including visibility conditions, repeat, $cond expressions, and a registry of pure HTML component render functions. --- README.md | 1 + examples/astro/.astro/content.d.ts | 187 ++++ examples/astro/.astro/types.d.ts | 2 + examples/astro/astro.config.mjs | 3 + examples/astro/package.json | 22 + examples/astro/src/lib/catalog.ts | 61 ++ examples/astro/src/lib/registry.ts | 46 + examples/astro/src/lib/spec.ts | 125 +++ examples/astro/src/pages/index.astro | 42 + examples/astro/tsconfig.json | 6 + pnpm-lock.yaml | 1262 ++++++++++++++++++++++++-- 11 files changed, 1673 insertions(+), 84 deletions(-) create mode 100644 examples/astro/.astro/content.d.ts create mode 100644 examples/astro/.astro/types.d.ts create mode 100644 examples/astro/astro.config.mjs create mode 100644 examples/astro/package.json create mode 100644 examples/astro/src/lib/catalog.ts create mode 100644 examples/astro/src/lib/registry.ts create mode 100644 examples/astro/src/lib/spec.ts create mode 100644 examples/astro/src/pages/index.astro create mode 100644 examples/astro/tsconfig.json diff --git a/README.md b/README.md index 861021be..ea7f5200 100644 --- a/README.md +++ b/README.md @@ -628,6 +628,7 @@ pnpm dev - Vue Example: run `pnpm dev` in `examples/vue` - Vite Renderers (React + Vue + Svelte + Solid): run `pnpm dev` in `examples/vite-renderers` - React Native example: run `npx expo start` in `examples/react-native` +- Astro SSR Example: run `pnpm dev` in `examples/astro` ## How It Works diff --git a/examples/astro/.astro/content.d.ts b/examples/astro/.astro/content.d.ts new file mode 100644 index 00000000..f2f5acf0 --- /dev/null +++ b/examples/astro/.astro/content.d.ts @@ -0,0 +1,187 @@ +declare module "astro:content" { + export interface RenderResult { + Content: import("astro/runtime/server/index.js").AstroComponentFactory; + headings: import("astro").MarkdownHeading[]; + remarkPluginFrontmatter: Record; + } + interface Render { + ".md": Promise; + } + + export interface RenderedContent { + html: string; + metadata?: { + imagePaths: Array; + [key: string]: unknown; + }; + } + + type Flatten = T extends { [K: string]: infer U } ? U : never; + + export type CollectionKey = keyof DataEntryMap; + export type CollectionEntry = Flatten< + DataEntryMap[C] + >; + + type AllValuesOf = T extends any ? T[keyof T] : never; + + export type ReferenceDataEntry< + C extends CollectionKey, + E extends keyof DataEntryMap[C] = string, + > = { + collection: C; + id: E; + }; + + export type ReferenceLiveEntry< + C extends keyof LiveContentConfig["collections"], + > = { + collection: C; + id: string; + }; + + export function getCollection< + C extends keyof DataEntryMap, + E extends CollectionEntry, + >( + collection: C, + filter?: (entry: CollectionEntry) => entry is E, + ): Promise; + export function getCollection( + collection: C, + filter?: (entry: CollectionEntry) => unknown, + ): Promise[]>; + + export function getLiveCollection< + C extends keyof LiveContentConfig["collections"], + >( + collection: C, + filter?: LiveLoaderCollectionFilterType, + ): Promise< + import("astro").LiveDataCollectionResult< + LiveLoaderDataType, + LiveLoaderErrorType + > + >; + + export function getEntry< + C extends keyof DataEntryMap, + E extends keyof DataEntryMap[C] | (string & {}), + >( + entry: ReferenceDataEntry, + ): E extends keyof DataEntryMap[C] + ? Promise + : Promise | undefined>; + export function getEntry< + C extends keyof DataEntryMap, + E extends keyof DataEntryMap[C] | (string & {}), + >( + collection: C, + id: E, + ): E extends keyof DataEntryMap[C] + ? string extends keyof DataEntryMap[C] + ? Promise | undefined + : Promise + : Promise | undefined>; + export function getLiveEntry< + C extends keyof LiveContentConfig["collections"], + >( + collection: C, + filter: string | LiveLoaderEntryFilterType, + ): Promise< + import("astro").LiveDataEntryResult< + LiveLoaderDataType, + LiveLoaderErrorType + > + >; + + /** Resolve an array of entry references from the same collection */ + export function getEntries( + entries: ReferenceDataEntry[], + ): Promise[]>; + + export function render( + entry: DataEntryMap[C][string], + ): Promise; + + export function reference< + C extends + | keyof DataEntryMap + // Allow generic `string` to avoid excessive type errors in the config + // if `dev` is not running to update as you edit. + // Invalid collection names will be caught at build time. + | (string & {}), + >( + collection: C, + ): import("astro/zod").ZodPipe< + import("astro/zod").ZodString, + import("astro/zod").ZodTransform< + C extends keyof DataEntryMap + ? { + collection: C; + id: string; + } + : never, + string + > + >; + + type ReturnTypeOrOriginal = T extends (...args: any[]) => infer R ? R : T; + type InferEntrySchema = + import("astro/zod").infer< + ReturnTypeOrOriginal["schema"]> + >; + type InferLoaderSchema< + C extends keyof DataEntryMap, + L = Required["loader"], + > = L extends { schema: import("astro/zod").ZodSchema } + ? import("astro/zod").infer< + Required["loader"]["schema"] + > + : any; + + type DataEntryMap = {}; + + type ExtractLoaderTypes = T extends import("astro/loaders").LiveLoader< + infer TData, + infer TEntryFilter, + infer TCollectionFilter, + infer TError + > + ? { + data: TData; + entryFilter: TEntryFilter; + collectionFilter: TCollectionFilter; + error: TError; + } + : { + data: never; + entryFilter: never; + collectionFilter: never; + error: never; + }; + type ExtractEntryFilterType = ExtractLoaderTypes["entryFilter"]; + type ExtractCollectionFilterType = + ExtractLoaderTypes["collectionFilter"]; + type ExtractErrorType = ExtractLoaderTypes["error"]; + + type LiveLoaderDataType = + LiveContentConfig["collections"][C]["schema"] extends undefined + ? ExtractDataType + : import("astro/zod").infer< + Exclude + >; + type LiveLoaderEntryFilterType< + C extends keyof LiveContentConfig["collections"], + > = ExtractEntryFilterType; + type LiveLoaderCollectionFilterType< + C extends keyof LiveContentConfig["collections"], + > = ExtractCollectionFilterType< + LiveContentConfig["collections"][C]["loader"] + >; + type LiveLoaderErrorType = + ExtractErrorType; + + export type ContentConfig = never; + export type LiveContentConfig = never; +} diff --git a/examples/astro/.astro/types.d.ts b/examples/astro/.astro/types.d.ts new file mode 100644 index 00000000..306a68bf --- /dev/null +++ b/examples/astro/.astro/types.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/examples/astro/astro.config.mjs b/examples/astro/astro.config.mjs new file mode 100644 index 00000000..ef0fcdd5 --- /dev/null +++ b/examples/astro/astro.config.mjs @@ -0,0 +1,3 @@ +import { defineConfig } from "astro/config"; + +export default defineConfig({}); diff --git a/examples/astro/package.json b/examples/astro/package.json new file mode 100644 index 00000000..fcc75b6b --- /dev/null +++ b/examples/astro/package.json @@ -0,0 +1,22 @@ +{ + "name": "example-astro", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "predev": "command -v portless >/dev/null 2>&1 || (echo '\\nportless is required but not installed. Run: npm i -g portless\\nSee: https://github.com/vercel-labs/portless\\n' && exit 1)", + "dev": "portless astro-demo.json-render astro dev", + "build": "astro build", + "preview": "astro preview", + "check-types": "astro check" + }, + "dependencies": { + "@json-render/core": "workspace:*", + "@json-render/astro": "workspace:*", + "astro": "^6.0.4", + "zod": "^4.3.6" + }, + "devDependencies": { + "typescript": "^5.9.3" + } +} diff --git a/examples/astro/src/lib/catalog.ts b/examples/astro/src/lib/catalog.ts new file mode 100644 index 00000000..2977c98c --- /dev/null +++ b/examples/astro/src/lib/catalog.ts @@ -0,0 +1,61 @@ +import { defineCatalog } from "@json-render/core"; +import { schema } from "@json-render/astro"; +import { z } from "zod"; + +export const catalog = defineCatalog(schema, { + components: { + Section: { + props: z.object({ + id: z.string().nullable(), + className: z.string().nullable(), + }), + description: "A semantic section wrapper", + }, + Card: { + props: z.object({ + title: z.string(), + subtitle: z.string().nullable(), + }), + description: "A card container with title and optional subtitle", + }, + Heading: { + props: z.object({ + text: z.string(), + level: z.enum(["h1", "h2", "h3", "h4"]).nullable(), + }), + description: "Heading text at various levels", + }, + Text: { + props: z.object({ + content: z.string(), + }), + description: "Body text paragraph", + }, + Badge: { + props: z.object({ + label: z.string(), + variant: z.enum(["default", "success", "warning"]).nullable(), + }), + description: "A small status badge", + }, + List: { + props: z.object({}), + description: "An unordered list container", + }, + ListItem: { + props: z.object({ + text: z.string(), + }), + description: "A single list item", + }, + Link: { + props: z.object({ + href: z.string(), + text: z.string(), + }), + description: "A hyperlink", + }, + }, +}); + +export type AppCatalog = typeof catalog; diff --git a/examples/astro/src/lib/registry.ts b/examples/astro/src/lib/registry.ts new file mode 100644 index 00000000..50300ad0 --- /dev/null +++ b/examples/astro/src/lib/registry.ts @@ -0,0 +1,46 @@ +import { escapeHtml } from "@json-render/astro"; +import type { ComponentRegistry } from "@json-render/astro"; + +export const registry: ComponentRegistry = { + Section: ({ props, children }) => { + const attrs = [ + props.id ? ` id="${escapeHtml(props.id)}"` : "", + props.className ? ` class="${escapeHtml(props.className)}"` : "", + ].join(""); + return `${children}`; + }, + + Card: ({ props, children }) => + `
    +

    ${escapeHtml(props.title)}

    + ${props.subtitle ? `

    ${escapeHtml(props.subtitle)}

    ` : ""} + ${children} +
    `, + + Heading: ({ props }) => { + const tag = props.level || "h2"; + return `<${tag}>${escapeHtml(props.text)}`; + }, + + Text: ({ props }) => + `

    ${escapeHtml(props.content)}

    `, + + Badge: ({ props }) => { + const colors: Record = { + default: { bg: "#e0f2fe", fg: "#0369a1", border: "#bae6fd" }, + success: { bg: "#dcfce7", fg: "#15803d", border: "#bbf7d0" }, + warning: { bg: "#fef9c3", fg: "#a16207", border: "#fde68a" }, + }; + const c = colors[props.variant ?? "default"] ?? colors.default!; + return `${escapeHtml(props.label)}`; + }, + + List: ({ children }) => + `
      ${children}
    `, + + ListItem: ({ props }) => + `
  • ${escapeHtml(props.text)}
  • `, + + Link: ({ props }) => + `${escapeHtml(props.text)}`, +}; diff --git a/examples/astro/src/lib/spec.ts b/examples/astro/src/lib/spec.ts new file mode 100644 index 00000000..50dadbd7 --- /dev/null +++ b/examples/astro/src/lib/spec.ts @@ -0,0 +1,125 @@ +import type { Spec } from "@json-render/core"; + +export const demoSpec: Spec = { + root: "root", + state: { + showBanner: true, + userRole: "admin", + features: [ + { + id: "1", + name: "SSR rendering", + description: "Pure HTML output on the server", + }, + { + id: "2", + name: "Zero dependencies", + description: "No React, Vue, or Svelte required", + }, + { + id: "3", + name: "Edge-ready", + description: "Works in Cloudflare Workers, Deno, Bun", + }, + ], + }, + elements: { + root: { + type: "Section", + props: { id: "app", className: null }, + children: [ + "header", + "banner", + "features-card", + "admin-card", + "links-card", + ], + }, + + // Header + header: { + type: "Heading", + props: { text: "@json-render/astro demo", level: "h1" }, + children: [], + }, + + // Conditional banner (visible when showBanner is true) + banner: { + type: "Badge", + props: { label: "SSR-rendered at build time", variant: "success" }, + children: [], + visible: { $state: "/showBanner" }, + }, + + // Features card with repeat + "features-card": { + type: "Card", + props: { + title: "Features", + subtitle: "What makes this renderer special", + }, + children: ["features-list"], + }, + "features-list": { + type: "List", + props: {}, + children: ["feature-item"], + repeat: { statePath: "/features", key: "id" }, + }, + "feature-item": { + type: "ListItem", + props: { + text: { $item: "name" }, + }, + children: [], + }, + + // Admin-only card (visible when role is admin) + "admin-card": { + type: "Card", + props: { + title: "Admin Panel", + subtitle: null, + }, + children: ["admin-text"], + visible: { $state: "/userRole", eq: "admin" }, + }, + "admin-text": { + type: "Text", + props: { + content: { + $cond: { $state: "/userRole", eq: "admin" }, + $then: "You have full admin access.", + $else: "Access restricted.", + }, + }, + children: [], + }, + + // Links + "links-card": { + type: "Card", + props: { + title: "Resources", + subtitle: null, + }, + children: ["link-docs", "link-github"], + }, + "link-docs": { + type: "Link", + props: { + href: "https://json-render.dev/docs/api/astro", + text: "Documentation", + }, + children: [], + }, + "link-github": { + type: "Link", + props: { + href: "https://github.com/vercel-labs/json-render/tree/main/examples/astro", + text: "Source code", + }, + children: [], + }, + }, +}; diff --git a/examples/astro/src/pages/index.astro b/examples/astro/src/pages/index.astro new file mode 100644 index 00000000..41e84f71 --- /dev/null +++ b/examples/astro/src/pages/index.astro @@ -0,0 +1,42 @@ +--- +import { renderToHtml } from "@json-render/astro"; +import { registry } from "../lib/registry"; +import { demoSpec } from "../lib/spec"; + +const html = renderToHtml(demoSpec, { + registry, + state: { showBanner: true, userRole: "admin" }, +}); +--- + + + + + + @json-render/astro demo + + + +
    + + diff --git a/examples/astro/tsconfig.json b/examples/astro/tsconfig.json new file mode 100644 index 00000000..0fc51d71 --- /dev/null +++ b/examples/astro/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "astro/tsconfigs/strict", + "compilerOptions": { + "strictNullChecks": true + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 80a65b98..fb88abe7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -83,9 +83,6 @@ importers: '@json-render/react': specifier: workspace:* version: link:../../packages/react - '@json-render/yaml': - specifier: workspace:* - version: link:../../packages/yaml '@mdx-js/loader': specifier: ^3.1.1 version: 3.1.1(webpack@5.96.1) @@ -134,15 +131,15 @@ importers: clsx: specifier: ^2.1.1 version: 2.1.1 - diff: - specifier: ^8.0.3 - version: 8.0.3 embla-carousel-react: specifier: ^8.6.0 version: 8.6.0(react@19.2.3) geist: specifier: 1.7.0 version: 1.7.0(next@16.1.1(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)) + just-bash: + specifier: 2.9.6 + version: 2.9.6 lucide-react: specifier: ^0.562.0 version: 0.562.0(react@19.2.3) @@ -185,9 +182,6 @@ importers: vaul: specifier: ^1.1.2 version: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.3))(@types/react@19.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - yaml: - specifier: ^2.8.2 - version: 2.8.2 zod: specifier: ^4.3.6 version: 4.3.6 @@ -229,6 +223,25 @@ importers: specifier: 5.9.2 version: 5.9.2 + examples/astro: + dependencies: + '@json-render/astro': + specifier: workspace:* + version: link:../../packages/astro + '@json-render/core': + specifier: workspace:* + version: link:../../packages/core + astro: + specifier: ^6.0.4 + version: 6.0.4(@types/node@22.19.6)(@upstash/redis@1.36.1)(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.55.1)(terser@5.46.0)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) + zod: + specifier: ^4.3.6 + version: 4.3.6 + devDependencies: + typescript: + specifier: ^5.9.3 + version: 5.9.3 + examples/chat: dependencies: '@ai-sdk/gateway': @@ -1776,7 +1789,7 @@ importers: version: link:../typescript-config esbuild-plugin-solid: specifier: ^0.6.0 - version: 0.6.0(esbuild@0.27.2)(solid-js@1.9.11) + version: 0.6.0(esbuild@0.27.4)(solid-js@1.9.11) solid-js: specifier: ^1.9.0 version: 1.9.11 @@ -1895,34 +1908,6 @@ importers: specifier: ^5.4.5 version: 5.9.3 - packages/yaml: - dependencies: - '@json-render/core': - specifier: workspace:* - version: link:../core - diff: - specifier: ^8.0.3 - version: 8.0.3 - yaml: - specifier: ^2.8.2 - version: 2.8.2 - devDependencies: - '@internal/typescript-config': - specifier: workspace:* - version: link:../typescript-config - tsup: - specifier: ^8.0.2 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) - typescript: - specifier: ^5.4.5 - version: 5.9.3 - vitest: - specifier: ^4.0.17 - version: 4.0.17(@opentelemetry/api@1.9.0)(@types/node@22.19.6)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.31.1)(msw@2.12.10(@types/node@22.19.6)(typescript@5.9.3))(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) - zod: - specifier: ^4.3.6 - version: 4.3.6 - packages/zustand: dependencies: '@json-render/core': @@ -2077,6 +2062,23 @@ packages: '@asamuzakjp/nwsapi@2.3.9': resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} + '@astrojs/compiler@3.0.0': + resolution: {integrity: sha512-MwAbDE5mawZ1SS+D8qWiHdprdME5Tlj2e0YjxnEICvcOpbSukNS7Sa7hA5PK+6RrmUr/t6Gi5YgrdZKjbO/WPQ==} + + '@astrojs/internal-helpers@0.8.0': + resolution: {integrity: sha512-J56GrhEiV+4dmrGLPNOl2pZjpHXAndWVyiVDYGDuw6MWKpBSEMLdFxHzeM/6sqaknw9M+HFfHZAcvi3OfT3D/w==} + + '@astrojs/markdown-remark@7.0.0': + resolution: {integrity: sha512-jTAXHPy45L7o1ljH4jYV+ShtOHtyQUa1mGp3a5fJp1soX8lInuTJQ6ihmldHzVM4Q7QptU4SzIDIcKbBJO7sXQ==} + + '@astrojs/prism@4.0.0': + resolution: {integrity: sha512-NndtNPpxaGinRpRytljGBvYHpTOwHycSZ/c+lQi5cHvkqqrHKWdkPEhImlODBNmbuB+vyQUNUDXyjzt66CihJg==} + engines: {node: ^20.19.1 || >=22.12.0} + + '@astrojs/telemetry@3.3.0': + resolution: {integrity: sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==} + engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0} + '@babel/code-frame@7.10.4': resolution: {integrity: sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==} @@ -2620,6 +2622,10 @@ packages: '@borewit/text-codec@0.2.1': resolution: {integrity: sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw==} + '@capsizecss/unpack@4.0.0': + resolution: {integrity: sha512-VERIM64vtTP1C4mxQ5thVT9fK0apjPFobqybMtA1UdUujWka24ERHbRHFGmpbbhp73MhV+KSsHQH9C6uOTdEQA==} + engines: {node: '>=18'} + '@changesets/apply-release-plan@7.0.14': resolution: {integrity: sha512-ddBvf9PHdy2YY0OUiEl3TV78mH9sckndJR14QAt87KLEbIov81XO0q0QAmvooBxXlqRRP8I9B7XOzZwQG7JkWA==} @@ -2675,6 +2681,12 @@ packages: '@changesets/write@0.4.0': resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} + '@clack/core@1.1.0': + resolution: {integrity: sha512-SVcm4Dqm2ukn64/8Gub2wnlA5nS2iWJyCkdNHcvNHPIeBTGojpdJ+9cZKwLfmqy7irD4N5qLteSilJlE0WLAtA==} + + '@clack/prompts@1.1.0': + resolution: {integrity: sha512-pkqbPGtohJAvm4Dphs2M8xE29ggupihHdy1x84HNojZuMtFsHiUlRvqD24tM2+XmI+61LlfNceM3Wr7U5QES5g==} + '@csstools/color-helpers@5.1.0': resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} engines: {node: '>=18'} @@ -2774,6 +2786,12 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.27.4': + resolution: {integrity: sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.18.20': resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} engines: {node: '>=12'} @@ -2798,6 +2816,12 @@ packages: cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.27.4': + resolution: {integrity: sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.18.20': resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} engines: {node: '>=12'} @@ -2822,6 +2846,12 @@ packages: cpu: [arm] os: [android] + '@esbuild/android-arm@0.27.4': + resolution: {integrity: sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.18.20': resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} engines: {node: '>=12'} @@ -2846,6 +2876,12 @@ packages: cpu: [x64] os: [android] + '@esbuild/android-x64@0.27.4': + resolution: {integrity: sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.18.20': resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} engines: {node: '>=12'} @@ -2870,6 +2906,12 @@ packages: cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.27.4': + resolution: {integrity: sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.18.20': resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} engines: {node: '>=12'} @@ -2894,6 +2936,12 @@ packages: cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.27.4': + resolution: {integrity: sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.18.20': resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} engines: {node: '>=12'} @@ -2918,6 +2966,12 @@ packages: cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.27.4': + resolution: {integrity: sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.18.20': resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} engines: {node: '>=12'} @@ -2942,6 +2996,12 @@ packages: cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.27.4': + resolution: {integrity: sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.18.20': resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} engines: {node: '>=12'} @@ -2966,6 +3026,12 @@ packages: cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.27.4': + resolution: {integrity: sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.18.20': resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} engines: {node: '>=12'} @@ -2990,6 +3056,12 @@ packages: cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.27.4': + resolution: {integrity: sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.18.20': resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} engines: {node: '>=12'} @@ -3014,6 +3086,12 @@ packages: cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.27.4': + resolution: {integrity: sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.18.20': resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} engines: {node: '>=12'} @@ -3038,6 +3116,12 @@ packages: cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.27.4': + resolution: {integrity: sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.18.20': resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} engines: {node: '>=12'} @@ -3062,6 +3146,12 @@ packages: cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.27.4': + resolution: {integrity: sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.18.20': resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} engines: {node: '>=12'} @@ -3086,6 +3176,12 @@ packages: cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.27.4': + resolution: {integrity: sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.18.20': resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} engines: {node: '>=12'} @@ -3110,6 +3206,12 @@ packages: cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.27.4': + resolution: {integrity: sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.18.20': resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} engines: {node: '>=12'} @@ -3134,6 +3236,12 @@ packages: cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.27.4': + resolution: {integrity: sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.18.20': resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} engines: {node: '>=12'} @@ -3158,6 +3266,12 @@ packages: cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.27.4': + resolution: {integrity: sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-arm64@0.25.0': resolution: {integrity: sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==} engines: {node: '>=18'} @@ -3176,6 +3290,12 @@ packages: cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-arm64@0.27.4': + resolution: {integrity: sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-x64@0.18.20': resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} engines: {node: '>=12'} @@ -3200,6 +3320,12 @@ packages: cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.27.4': + resolution: {integrity: sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/openbsd-arm64@0.25.0': resolution: {integrity: sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==} engines: {node: '>=18'} @@ -3218,6 +3344,12 @@ packages: cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-arm64@0.27.4': + resolution: {integrity: sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.18.20': resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} engines: {node: '>=12'} @@ -3242,6 +3374,12 @@ packages: cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.27.4': + resolution: {integrity: sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openharmony-arm64@0.25.12': resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} engines: {node: '>=18'} @@ -3254,6 +3392,12 @@ packages: cpu: [arm64] os: [openharmony] + '@esbuild/openharmony-arm64@0.27.4': + resolution: {integrity: sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/sunos-x64@0.18.20': resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} engines: {node: '>=12'} @@ -3278,6 +3422,12 @@ packages: cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.27.4': + resolution: {integrity: sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.18.20': resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} engines: {node: '>=12'} @@ -3302,6 +3452,12 @@ packages: cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.27.4': + resolution: {integrity: sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.18.20': resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} engines: {node: '>=12'} @@ -3326,6 +3482,12 @@ packages: cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.27.4': + resolution: {integrity: sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.18.20': resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} engines: {node: '>=12'} @@ -3350,6 +3512,12 @@ packages: cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.27.4': + resolution: {integrity: sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.9.1': resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -4152,6 +4320,9 @@ packages: resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} engines: {node: '>=8.0.0'} + '@oslojs/encoding@1.1.0': + resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -5510,6 +5681,15 @@ packages: '@rolldown/pluginutils@1.0.0-rc.3': resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==} + '@rollup/pluginutils@5.3.0': + resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + '@rollup/rollup-android-arm-eabi@4.55.1': resolution: {integrity: sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==} cpu: [arm] @@ -5657,21 +5837,49 @@ packages: '@shikijs/core@3.21.0': resolution: {integrity: sha512-AXSQu/2n1UIQekY8euBJlvFYZIw0PHY63jUzGbrOma4wPxzznJXTXkri+QcHeBNaFxiiOljKxxJkVSoB3PjbyA==} + '@shikijs/core@4.0.2': + resolution: {integrity: sha512-hxT0YF4ExEqB8G/qFdtJvpmHXBYJ2lWW7qTHDarVkIudPFE6iCIrqdgWxGn5s+ppkGXI0aEGlibI0PAyzP3zlw==} + engines: {node: '>=20'} + '@shikijs/engine-javascript@3.21.0': resolution: {integrity: sha512-ATwv86xlbmfD9n9gKRiwuPpWgPENAWCLwYCGz9ugTJlsO2kOzhOkvoyV/UD+tJ0uT7YRyD530x6ugNSffmvIiQ==} + '@shikijs/engine-javascript@4.0.2': + resolution: {integrity: sha512-7PW0Nm49DcoUIQEXlJhNNBHyoGMjalRETTCcjMqEaMoJRLljy1Bi/EGV3/qLBgLKQejdspiiYuHGQW6dX94Nag==} + engines: {node: '>=20'} + '@shikijs/engine-oniguruma@3.21.0': resolution: {integrity: sha512-OYknTCct6qiwpQDqDdf3iedRdzj6hFlOPv5hMvI+hkWfCKs5mlJ4TXziBG9nyabLwGulrUjHiCq3xCspSzErYQ==} + '@shikijs/engine-oniguruma@4.0.2': + resolution: {integrity: sha512-UpCB9Y2sUKlS9z8juFSKz7ZtysmeXCgnRF0dlhXBkmQnek7lAToPte8DkxmEYGNTMii72zU/lyXiCB6StuZeJg==} + engines: {node: '>=20'} + '@shikijs/langs@3.21.0': resolution: {integrity: sha512-g6mn5m+Y6GBJ4wxmBYqalK9Sp0CFkUqfNzUy2pJglUginz6ZpWbaWjDB4fbQ/8SHzFjYbtU6Ddlp1pc+PPNDVA==} + '@shikijs/langs@4.0.2': + resolution: {integrity: sha512-KaXby5dvoeuZzN0rYQiPMjFoUrz4hgwIE+D6Du9owcHcl6/g16/yT5BQxSW5cGt2MZBz6Hl0YuRqf12omRfUUg==} + engines: {node: '>=20'} + + '@shikijs/primitive@4.0.2': + resolution: {integrity: sha512-M6UMPrSa3fN5ayeJwFVl9qWofl273wtK1VG8ySDZ1mQBfhCpdd8nEx7nPZ/tk7k+TYcpqBZzj/AnwxT9lO+HJw==} + engines: {node: '>=20'} + '@shikijs/themes@3.21.0': resolution: {integrity: sha512-BAE4cr9EDiZyYzwIHEk7JTBJ9CzlPuM4PchfcA5ao1dWXb25nv6hYsoDiBq2aZK9E3dlt3WB78uI96UESD+8Mw==} + '@shikijs/themes@4.0.2': + resolution: {integrity: sha512-mjCafwt8lJJaVSsQvNVrJumbnnj1RI8jbUKrPKgE6E3OvQKxnuRoBaYC51H4IGHePsGN/QtALglWBU7DoKDFnA==} + engines: {node: '>=20'} + '@shikijs/types@3.21.0': resolution: {integrity: sha512-zGrWOxZ0/+0ovPY7PvBU2gIS9tmhSUUt30jAcNV0Bq0gb2S98gwfjIs1vxlmH5zM7/4YxLamT6ChlqqAJmPPjA==} + '@shikijs/types@4.0.2': + resolution: {integrity: sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg==} + engines: {node: '>=20'} + '@shikijs/vscode-textmate@10.0.2': resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} @@ -6133,6 +6341,9 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + '@types/nlcst@2.0.3': + resolution: {integrity: sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==} + '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} @@ -6781,6 +6992,10 @@ packages: resolution: {integrity: sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==} engines: {node: '>= 0.4'} + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + array-buffer-byte-length@1.0.2: resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} engines: {node: '>= 0.4'} @@ -6789,6 +7004,9 @@ packages: resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} engines: {node: '>= 0.4'} + array-iterate@2.0.1: + resolution: {integrity: sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==} + array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} @@ -6828,6 +7046,11 @@ packages: resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} hasBin: true + astro@6.0.4: + resolution: {integrity: sha512-1piLJCPTL/x7AMO2cjVFSTFyRqKuC3W8sSEySCt1aJio+p/wGs5H3K+Xr/rE9ftKtknLUtjxCqCE7/0NsXfGpQ==} + engines: {node: ^20.19.1 || >=22.12.0, npm: '>=9.6.5', pnpm: '>=7.1.0'} + hasBin: true + async-function@1.0.0: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} engines: {node: '>= 0.4'} @@ -7005,6 +7228,9 @@ packages: resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} engines: {node: '>=18'} + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + bplist-creator@0.1.0: resolution: {integrity: sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg==} @@ -7185,6 +7411,10 @@ packages: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} + ci-info@4.4.0: + resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} + engines: {node: '>=8'} + cjs-module-lexer@1.4.3: resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} @@ -7307,6 +7537,10 @@ packages: resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} engines: {node: '>= 10'} + common-ancestor-path@2.0.0: + resolution: {integrity: sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng==} + engines: {node: '>= 18'} + compressible@2.0.18: resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} engines: {node: '>= 0.6'} @@ -7350,6 +7584,9 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie-es@1.2.2: + resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==} + cookie-signature@1.2.2: resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} engines: {node: '>=6.6.0'} @@ -7391,6 +7628,9 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + crossws@0.3.5: + resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==} + crypto-js@4.2.0: resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} @@ -7418,18 +7658,33 @@ packages: peerDependencies: webpack: ^4.27.0 || ^5.0.0 + css-select@5.2.2: + resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} + css-to-react-native@3.2.0: resolution: {integrity: sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==} + css-tree@2.2.1: + resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + css-tree@3.1.0: resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + css-what@6.2.2: + resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} + engines: {node: '>= 6'} + cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} hasBin: true + csso@5.0.5: + resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + cssom@0.3.8: resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==} @@ -7609,6 +7864,9 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -7621,6 +7879,9 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} + destr@2.0.5: + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + destroy@1.2.0: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} @@ -7672,6 +7933,9 @@ packages: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} + dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} @@ -7819,6 +8083,10 @@ packages: sqlite3: optional: true + dset@3.1.4: + resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==} + engines: {node: '>=4'} + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -7946,6 +8214,9 @@ packages: es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-module-lexer@2.0.0: + resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} + es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} @@ -7999,6 +8270,11 @@ packages: engines: {node: '>=18'} hasBin: true + esbuild@0.27.4: + resolution: {integrity: sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -8479,15 +8755,26 @@ packages: flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + flattie@1.1.1: + resolution: {integrity: sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==} + engines: {node: '>=8'} + flow-enums-runtime@0.0.6: resolution: {integrity: sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==} + fontace@0.4.1: + resolution: {integrity: sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw==} + fontfaceobserver@2.3.0: resolution: {integrity: sha512-6FPvD/IVyT4ZlNe7Wcn5Fb/4ChigpucKYSvD6a+0iMoLn2inpo711eyIcKjmDtE5XNcgAkSH9uN/nfAeZzHEfg==} fontkit@2.0.4: resolution: {integrity: sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==} + fontkitten@1.0.3: + resolution: {integrity: sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw==} + engines: {node: '>=20'} + for-each@0.3.5: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} @@ -8629,6 +8916,9 @@ packages: github-from-package@0.0.0: resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + github-slugger@2.0.0: + resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -8701,6 +8991,9 @@ packages: resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} engines: {node: '>=6.0'} + h3@1.15.6: + resolution: {integrity: sha512-oi15ESLW5LRthZ+qPCi5GNasY/gvynSKUQxgiovrY63bPAtG59wtM+LSrlcwvOHAXzGrXVLnI97brbkdPF9WoQ==} + has-bigints@1.1.0: resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} engines: {node: '>= 0.4'} @@ -8732,9 +9025,15 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + hast-util-from-html@2.0.3: + resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} + hast-util-from-parse5@8.0.3: resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} + hast-util-is-element@3.0.0: + resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} + hast-util-parse-selector@4.0.0: resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} @@ -8756,6 +9055,9 @@ packages: hast-util-to-parse5@8.0.1: resolution: {integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==} + hast-util-to-text@4.0.2: + resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==} + hast-util-whitespace@3.0.0: resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} @@ -8815,6 +9117,9 @@ packages: html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + html-escaper@3.0.3: + resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==} + html-to-text@9.0.5: resolution: {integrity: sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==} engines: {node: '>=14'} @@ -8828,6 +9133,9 @@ packages: htmlparser2@8.0.2: resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} + http-cache-semantics@4.2.0: + resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} + http-errors@2.0.1: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} @@ -8953,6 +9261,9 @@ packages: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} + iron-webcrypto@1.2.1: + resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} + is-alphabetical@2.0.1: resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} @@ -9879,6 +10190,9 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + magicast@0.5.2: + resolution: {integrity: sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==} + make-dir@4.0.0: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} @@ -9913,6 +10227,9 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + mdast-util-definitions@6.0.0: + resolution: {integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==} + mdast-util-find-and-replace@3.0.2: resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} @@ -9961,6 +10278,9 @@ packages: mdast-util-to-string@4.0.0: resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + mdn-data@2.0.28: + resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} + mdn-data@2.12.2: resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} @@ -10325,6 +10645,10 @@ packages: neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + neotraverse@0.6.18: + resolution: {integrity: sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==} + engines: {node: '>= 10'} + nested-error-stacks@2.0.1: resolution: {integrity: sha512-SrQrok4CATudVzBS7coSz26QRSmlK9TzzoFbeKfcPBUFPjcQM9Rqvr/DlJkOrwI/0KcgvMub1n1g5Jt9EgRn4A==} @@ -10376,6 +10700,9 @@ packages: sass: optional: true + nlcst-to-string@4.0.0: + resolution: {integrity: sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==} + node-abi@3.87.0: resolution: {integrity: sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ==} engines: {node: '>=10'} @@ -10389,6 +10716,9 @@ packages: engines: {node: '>=10.5.0'} deprecated: Use your platform's native DOMException instead + node-fetch-native@1.6.7: + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + node-fetch@3.3.2: resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -10409,6 +10739,9 @@ packages: engines: {node: '>=16.0.0'} hasBin: true + node-mock-http@1.0.4: + resolution: {integrity: sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==} + node-releases@2.0.27: resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} @@ -10436,6 +10769,9 @@ packages: resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} engines: {node: '>=18'} + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + nullthrows@1.1.1: resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} @@ -10481,6 +10817,12 @@ packages: obug@2.1.1: resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + ofetch@1.5.1: + resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} + + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + on-finished@2.3.0: resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} engines: {node: '>= 0.8'} @@ -10560,6 +10902,10 @@ packages: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} + p-limit@7.3.0: + resolution: {integrity: sha512-7cIXg/Z0M5WZRblrsOla88S4wAK+zOQQWeBYfV3qJuJXMr+LnbYjaadrFaS0JILfEDPVqHyKnZ1Z/1d6J9VVUw==} + engines: {node: '>=20'} + p-locate@4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} @@ -10572,6 +10918,14 @@ packages: resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} engines: {node: '>=6'} + p-queue@9.1.0: + resolution: {integrity: sha512-O/ZPaXuQV29uSLbxWBGGZO1mCQXV2BLIwUr59JUU9SoH76mnYvtms7aafH/isNSNGwuEfP6W/4xD0/TJXxrizw==} + engines: {node: '>=20'} + + p-timeout@7.0.1: + resolution: {integrity: sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg==} + engines: {node: '>=20'} + p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} @@ -10608,6 +10962,9 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} + parse-latin@7.0.0: + resolution: {integrity: sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==} + parse-ms@4.0.0: resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} engines: {node: '>=18'} @@ -10684,6 +11041,9 @@ packages: pend@1.2.0: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + piccolore@0.1.3: + resolution: {integrity: sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -10942,6 +11302,9 @@ packages: '@types/react-dom': optional: true + radix3@1.1.2: + resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} + randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} @@ -11244,6 +11607,9 @@ packages: rehype-harden@1.1.7: resolution: {integrity: sha512-j5DY0YSK2YavvNGV+qBHma15J9m0WZmRe8posT5AtKDS6TNWtMVTo6RiqF8SidfcASYz8f3k2J/1RWmq5zTXUw==} + rehype-parse@9.0.1: + resolution: {integrity: sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==} + rehype-raw@7.0.0: resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==} @@ -11253,6 +11619,12 @@ packages: rehype-sanitize@6.0.0: resolution: {integrity: sha512-CsnhKNsyI8Tub6L4sm5ZFsme4puGfc6pYylvXo1AeqaGbjOYyzNv3qZPwvs0oMJ39eryyeOdmxwUIo94IpEhqg==} + rehype-stringify@10.0.1: + resolution: {integrity: sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==} + + rehype@13.0.2: + resolution: {integrity: sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==} + remark-gfm@4.0.1: resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} @@ -11265,6 +11637,10 @@ packages: remark-rehype@11.1.2: resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + remark-smartypants@3.0.2: + resolution: {integrity: sha512-ILTWeOriIluwEvPjv67v7Blgrcx+LZOkAUVtKI3putuhlZm84FnqDORNXPPm+HY3NdZOMhyDwZ1E+eZB/Df5dA==} + engines: {node: '>=16.0.0'} + remark-stringify@11.0.0: resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} @@ -11351,6 +11727,18 @@ packages: restructure@3.0.2: resolution: {integrity: sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==} + retext-latin@4.0.0: + resolution: {integrity: sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==} + + retext-smartypants@6.2.0: + resolution: {integrity: sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==} + + retext-stringify@4.0.0: + resolution: {integrity: sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==} + + retext@9.0.0: + resolution: {integrity: sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==} + rettime@0.10.1: resolution: {integrity: sha512-uyDrIlUEH37cinabq0AX4QbgV4HbFZ/gqoiunWQ1UqBtRvTTytwhNYjE++pO/MjPTZL5KQCf2bEoJ/BJNVQ5Kw==} @@ -11421,6 +11809,10 @@ packages: resolution: {integrity: sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==} engines: {node: '>=11.0.0'} + sax@1.5.0: + resolution: {integrity: sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==} + engines: {node: '>=11.0.0'} + saxes@5.0.1: resolution: {integrity: sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==} engines: {node: '>=10'} @@ -11478,6 +11870,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + engines: {node: '>=10'} + hasBin: true + send@0.19.2: resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==} engines: {node: '>= 0.8.0'} @@ -11562,6 +11959,10 @@ packages: shiki@3.21.0: resolution: {integrity: sha512-N65B/3bqL/TI2crrXr+4UivctrAGEjmsib5rPMMPpFp1xAx/w03v8WZ9RDDFYteXoEgY7qZ4HGgl5KBIu1153w==} + shiki@4.0.2: + resolution: {integrity: sha512-eAVKTMedR5ckPo4xne/PjYQYrU3qx78gtJZ+sHlXEg5IHhhoQhMfZVzetTYuaJS0L2Ef3AcCRzCHV8T0WI6nIQ==} + engines: {node: '>=20'} + side-channel-list@1.0.0: resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} engines: {node: '>= 0.4'} @@ -11939,6 +12340,11 @@ packages: svg-arc-to-cubic-bezier@3.2.0: resolution: {integrity: sha512-djbJ/vZKZO+gPoSDThGNpKDO+o+bAeA4XQKovvkNCqnIS2t+S4qnLAGQhyyrulhCFRl1WWzAp0wUDV8PpTVU3g==} + svgo@4.0.1: + resolution: {integrity: sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==} + engines: {node: '>=16'} + hasBin: true + swr@2.4.0: resolution: {integrity: sha512-sUlC20T8EOt1pHmDiqueUWMmRRX03W7w5YxovWX7VR2KHEPCTMly85x05vpkP5i6Bu4h44ePSMD9Tc+G2MItFw==} peerDependencies: @@ -12071,6 +12477,10 @@ packages: tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + tinyclip@0.1.12: + resolution: {integrity: sha512-Ae3OVUqifDw0wBriIBS7yVaW44Dp6eSHQcyq4Igc7eN2TJH/2YsicswaW+J/OuMvhpDPOKEgpAZCjkb4hpoyeA==} + engines: {node: ^16.14.0 || >= 17.3.0} + tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} @@ -12187,10 +12597,20 @@ packages: ts-morph@26.0.0: resolution: {integrity: sha512-ztMO++owQnz8c/gIENcM9XfCEzgoGphTv+nKpYNM1bgsdOVC/jRZuEBf6N+mLLDNg68Kl+GgUZfOySaRiG1/Ug==} - tsconfig-paths@4.2.0: - resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} - engines: {node: '>=6'} - + tsconfck@3.1.6: + resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==} + engines: {node: ^18 || >=20} + hasBin: true + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + tsconfig-paths@4.2.0: + resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} + engines: {node: '>=6'} + tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} @@ -12350,10 +12770,16 @@ packages: ufo@1.6.2: resolution: {integrity: sha512-heMioaxBcG9+Znsda5Q8sQbWnLJSl98AFDXTO80wELWEzX3hordXsTdxrIfMQoO9IY1MEnoGoPjpoKpMj+Yx0Q==} + ufo@1.6.3: + resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} + uint8array-extras@1.5.0: resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} engines: {node: '>=18'} + ultrahtml@1.6.0: + resolution: {integrity: sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==} + unbox-primitive@1.1.0: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} @@ -12397,22 +12823,37 @@ packages: unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + unifont@0.7.4: + resolution: {integrity: sha512-oHeis4/xl42HUIeHuNZRGEvxj5AaIKR+bHPNegRq5LV1gdc3jundpONbjglKpihmJf+dswygdMJn3eftGIMemg==} + unique-string@2.0.0: resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==} engines: {node: '>=8'} + unist-util-find-after@5.0.0: + resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==} + unist-util-is@6.0.1: resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + unist-util-modify-children@4.0.0: + resolution: {integrity: sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==} + unist-util-position-from-estree@2.0.0: resolution: {integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==} unist-util-position@5.0.0: resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + unist-util-remove-position@5.0.0: + resolution: {integrity: sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==} + unist-util-stringify-position@4.0.0: resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + unist-util-visit-children@3.0.0: + resolution: {integrity: sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==} + unist-util-visit-parents@6.0.2: resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} @@ -12435,6 +12876,68 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} + unstorage@1.17.4: + resolution: {integrity: sha512-fHK0yNg38tBiJKp/Vgsq4j0JEsCmgqH58HAn707S7zGkArbZsVr/CwINoi+nh3h98BRCwKvx1K3Xg9u3VV83sw==} + peerDependencies: + '@azure/app-configuration': ^1.8.0 + '@azure/cosmos': ^4.2.0 + '@azure/data-tables': ^13.3.0 + '@azure/identity': ^4.6.0 + '@azure/keyvault-secrets': ^4.9.0 + '@azure/storage-blob': ^12.26.0 + '@capacitor/preferences': ^6 || ^7 || ^8 + '@deno/kv': '>=0.9.0' + '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0 + '@planetscale/database': ^1.19.0 + '@upstash/redis': ^1.34.3 + '@vercel/blob': '>=0.27.1' + '@vercel/functions': ^2.2.12 || ^3.0.0 + '@vercel/kv': ^1 || ^2 || ^3 + aws4fetch: ^1.0.20 + db0: '>=0.2.1' + idb-keyval: ^6.2.1 + ioredis: ^5.4.2 + uploadthing: ^7.4.4 + peerDependenciesMeta: + '@azure/app-configuration': + optional: true + '@azure/cosmos': + optional: true + '@azure/data-tables': + optional: true + '@azure/identity': + optional: true + '@azure/keyvault-secrets': + optional: true + '@azure/storage-blob': + optional: true + '@capacitor/preferences': + optional: true + '@deno/kv': + optional: true + '@netlify/blobs': + optional: true + '@planetscale/database': + optional: true + '@upstash/redis': + optional: true + '@vercel/blob': + optional: true + '@vercel/functions': + optional: true + '@vercel/kv': + optional: true + aws4fetch: + optional: true + db0: + optional: true + idb-keyval: + optional: true + ioredis: + optional: true + uploadthing: + optional: true + until-async@3.0.2: resolution: {integrity: sha512-IiSk4HlzAMqTUseHHe3VhIGyuFmN90zMTpD3Z3y8jeQbzLIq500MVM7Jq2vUAnTKAFPJrqwkzr6PoTcPhGcOiw==} @@ -12803,6 +13306,10 @@ packages: resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} engines: {node: '>= 0.4'} + which-pm-runs@1.1.0: + resolution: {integrity: sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==} + engines: {node: '>=4'} + which-typed-array@1.1.19: resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} engines: {node: '>= 0.4'} @@ -12932,6 +13439,9 @@ packages: xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + xxhash-wasm@1.1.0: + resolution: {integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -12959,6 +13469,10 @@ packages: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + yargs-parser@22.0.0: + resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + yargs@16.2.0: resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} engines: {node: '>=10'} @@ -12974,6 +13488,10 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + yocto-queue@1.2.2: + resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} + engines: {node: '>=12.20'} + yoctocolors-cjs@2.1.3: resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} engines: {node: '>=18'} @@ -13154,6 +13672,53 @@ snapshots: '@asamuzakjp/nwsapi@2.3.9': {} + '@astrojs/compiler@3.0.0': {} + + '@astrojs/internal-helpers@0.8.0': + dependencies: + picomatch: 4.0.3 + + '@astrojs/markdown-remark@7.0.0': + dependencies: + '@astrojs/internal-helpers': 0.8.0 + '@astrojs/prism': 4.0.0 + github-slugger: 2.0.0 + hast-util-from-html: 2.0.3 + hast-util-to-text: 4.0.2 + js-yaml: 4.1.1 + mdast-util-definitions: 6.0.0 + rehype-raw: 7.0.0 + rehype-stringify: 10.0.1 + remark-gfm: 4.0.1 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + remark-smartypants: 3.0.2 + shiki: 4.0.2 + smol-toml: 1.6.0 + unified: 11.0.5 + unist-util-remove-position: 5.0.0 + unist-util-visit: 5.1.0 + unist-util-visit-parents: 6.0.2 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@astrojs/prism@4.0.0': + dependencies: + prismjs: 1.30.0 + + '@astrojs/telemetry@3.3.0': + dependencies: + ci-info: 4.4.0 + debug: 4.4.3 + dlv: 1.1.3 + dset: 3.1.4 + is-docker: 3.0.0 + is-wsl: 3.1.1 + which-pm-runs: 1.1.0 + transitivePeerDependencies: + - supports-color + '@babel/code-frame@7.10.4': dependencies: '@babel/highlight': 7.25.9 @@ -13820,8 +14385,11 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} - '@borewit/text-codec@0.2.1': - optional: true + '@borewit/text-codec@0.2.1': {} + + '@capsizecss/unpack@4.0.0': + dependencies: + fontkitten: 1.0.3 '@changesets/apply-release-plan@7.0.14': dependencies: @@ -13967,6 +14535,15 @@ snapshots: human-id: 4.1.3 prettier: 2.8.8 + '@clack/core@1.1.0': + dependencies: + sisteransi: 1.0.5 + + '@clack/prompts@1.1.0': + dependencies: + '@clack/core': 1.1.0 + sisteransi: 1.0.5 + '@csstools/color-helpers@5.1.0': {} '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': @@ -14058,6 +14635,9 @@ snapshots: '@esbuild/aix-ppc64@0.27.2': optional: true + '@esbuild/aix-ppc64@0.27.4': + optional: true + '@esbuild/android-arm64@0.18.20': optional: true @@ -14070,6 +14650,9 @@ snapshots: '@esbuild/android-arm64@0.27.2': optional: true + '@esbuild/android-arm64@0.27.4': + optional: true + '@esbuild/android-arm@0.18.20': optional: true @@ -14082,6 +14665,9 @@ snapshots: '@esbuild/android-arm@0.27.2': optional: true + '@esbuild/android-arm@0.27.4': + optional: true + '@esbuild/android-x64@0.18.20': optional: true @@ -14094,6 +14680,9 @@ snapshots: '@esbuild/android-x64@0.27.2': optional: true + '@esbuild/android-x64@0.27.4': + optional: true + '@esbuild/darwin-arm64@0.18.20': optional: true @@ -14106,6 +14695,9 @@ snapshots: '@esbuild/darwin-arm64@0.27.2': optional: true + '@esbuild/darwin-arm64@0.27.4': + optional: true + '@esbuild/darwin-x64@0.18.20': optional: true @@ -14118,6 +14710,9 @@ snapshots: '@esbuild/darwin-x64@0.27.2': optional: true + '@esbuild/darwin-x64@0.27.4': + optional: true + '@esbuild/freebsd-arm64@0.18.20': optional: true @@ -14130,6 +14725,9 @@ snapshots: '@esbuild/freebsd-arm64@0.27.2': optional: true + '@esbuild/freebsd-arm64@0.27.4': + optional: true + '@esbuild/freebsd-x64@0.18.20': optional: true @@ -14142,6 +14740,9 @@ snapshots: '@esbuild/freebsd-x64@0.27.2': optional: true + '@esbuild/freebsd-x64@0.27.4': + optional: true + '@esbuild/linux-arm64@0.18.20': optional: true @@ -14154,6 +14755,9 @@ snapshots: '@esbuild/linux-arm64@0.27.2': optional: true + '@esbuild/linux-arm64@0.27.4': + optional: true + '@esbuild/linux-arm@0.18.20': optional: true @@ -14166,6 +14770,9 @@ snapshots: '@esbuild/linux-arm@0.27.2': optional: true + '@esbuild/linux-arm@0.27.4': + optional: true + '@esbuild/linux-ia32@0.18.20': optional: true @@ -14178,6 +14785,9 @@ snapshots: '@esbuild/linux-ia32@0.27.2': optional: true + '@esbuild/linux-ia32@0.27.4': + optional: true + '@esbuild/linux-loong64@0.18.20': optional: true @@ -14190,6 +14800,9 @@ snapshots: '@esbuild/linux-loong64@0.27.2': optional: true + '@esbuild/linux-loong64@0.27.4': + optional: true + '@esbuild/linux-mips64el@0.18.20': optional: true @@ -14202,6 +14815,9 @@ snapshots: '@esbuild/linux-mips64el@0.27.2': optional: true + '@esbuild/linux-mips64el@0.27.4': + optional: true + '@esbuild/linux-ppc64@0.18.20': optional: true @@ -14214,6 +14830,9 @@ snapshots: '@esbuild/linux-ppc64@0.27.2': optional: true + '@esbuild/linux-ppc64@0.27.4': + optional: true + '@esbuild/linux-riscv64@0.18.20': optional: true @@ -14226,6 +14845,9 @@ snapshots: '@esbuild/linux-riscv64@0.27.2': optional: true + '@esbuild/linux-riscv64@0.27.4': + optional: true + '@esbuild/linux-s390x@0.18.20': optional: true @@ -14238,6 +14860,9 @@ snapshots: '@esbuild/linux-s390x@0.27.2': optional: true + '@esbuild/linux-s390x@0.27.4': + optional: true + '@esbuild/linux-x64@0.18.20': optional: true @@ -14250,6 +14875,9 @@ snapshots: '@esbuild/linux-x64@0.27.2': optional: true + '@esbuild/linux-x64@0.27.4': + optional: true + '@esbuild/netbsd-arm64@0.25.0': optional: true @@ -14259,6 +14887,9 @@ snapshots: '@esbuild/netbsd-arm64@0.27.2': optional: true + '@esbuild/netbsd-arm64@0.27.4': + optional: true + '@esbuild/netbsd-x64@0.18.20': optional: true @@ -14271,6 +14902,9 @@ snapshots: '@esbuild/netbsd-x64@0.27.2': optional: true + '@esbuild/netbsd-x64@0.27.4': + optional: true + '@esbuild/openbsd-arm64@0.25.0': optional: true @@ -14280,6 +14914,9 @@ snapshots: '@esbuild/openbsd-arm64@0.27.2': optional: true + '@esbuild/openbsd-arm64@0.27.4': + optional: true + '@esbuild/openbsd-x64@0.18.20': optional: true @@ -14292,12 +14929,18 @@ snapshots: '@esbuild/openbsd-x64@0.27.2': optional: true + '@esbuild/openbsd-x64@0.27.4': + optional: true + '@esbuild/openharmony-arm64@0.25.12': optional: true '@esbuild/openharmony-arm64@0.27.2': optional: true + '@esbuild/openharmony-arm64@0.27.4': + optional: true + '@esbuild/sunos-x64@0.18.20': optional: true @@ -14310,6 +14953,9 @@ snapshots: '@esbuild/sunos-x64@0.27.2': optional: true + '@esbuild/sunos-x64@0.27.4': + optional: true + '@esbuild/win32-arm64@0.18.20': optional: true @@ -14322,6 +14968,9 @@ snapshots: '@esbuild/win32-arm64@0.27.2': optional: true + '@esbuild/win32-arm64@0.27.4': + optional: true + '@esbuild/win32-ia32@0.18.20': optional: true @@ -14334,6 +14983,9 @@ snapshots: '@esbuild/win32-ia32@0.27.2': optional: true + '@esbuild/win32-ia32@0.27.4': + optional: true + '@esbuild/win32-x64@0.18.20': optional: true @@ -14346,6 +14998,9 @@ snapshots: '@esbuild/win32-x64@0.27.2': optional: true + '@esbuild/win32-x64@0.27.4': + optional: true + '@eslint-community/eslint-utils@4.9.1(eslint@8.57.1)': dependencies: eslint: 8.57.1 @@ -15347,8 +16002,7 @@ snapshots: '@mediapipe/tasks-vision@0.10.17': {} - '@mixmark-io/domino@2.2.0': - optional: true + '@mixmark-io/domino@2.2.0': {} '@modelcontextprotocol/ext-apps@1.2.0(@modelcontextprotocol/sdk@1.27.1(zod@4.3.6))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(zod@4.3.6)': dependencies: @@ -15523,6 +16177,8 @@ snapshots: '@opentelemetry/api@1.9.0': {} + '@oslojs/encoding@1.1.0': {} + '@pkgjs/parseargs@0.11.0': optional: true @@ -18159,6 +18815,14 @@ snapshots: '@rolldown/pluginutils@1.0.0-rc.3': {} + '@rollup/pluginutils@5.3.0(rollup@4.55.1)': + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.3 + optionalDependencies: + rollup: 4.55.1 + '@rollup/rollup-android-arm-eabi@4.55.1': optional: true @@ -18248,30 +18912,68 @@ snapshots: '@types/hast': 3.0.4 hast-util-to-html: 9.0.5 + '@shikijs/core@4.0.2': + dependencies: + '@shikijs/primitive': 4.0.2 + '@shikijs/types': 4.0.2 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + '@shikijs/engine-javascript@3.21.0': dependencies: '@shikijs/types': 3.21.0 '@shikijs/vscode-textmate': 10.0.2 oniguruma-to-es: 4.3.4 + '@shikijs/engine-javascript@4.0.2': + dependencies: + '@shikijs/types': 4.0.2 + '@shikijs/vscode-textmate': 10.0.2 + oniguruma-to-es: 4.3.4 + '@shikijs/engine-oniguruma@3.21.0': dependencies: '@shikijs/types': 3.21.0 '@shikijs/vscode-textmate': 10.0.2 + '@shikijs/engine-oniguruma@4.0.2': + dependencies: + '@shikijs/types': 4.0.2 + '@shikijs/vscode-textmate': 10.0.2 + '@shikijs/langs@3.21.0': dependencies: '@shikijs/types': 3.21.0 + '@shikijs/langs@4.0.2': + dependencies: + '@shikijs/types': 4.0.2 + + '@shikijs/primitive@4.0.2': + dependencies: + '@shikijs/types': 4.0.2 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + '@shikijs/themes@3.21.0': dependencies: '@shikijs/types': 3.21.0 + '@shikijs/themes@4.0.2': + dependencies: + '@shikijs/types': 4.0.2 + '@shikijs/types@3.21.0': dependencies: '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 + '@shikijs/types@4.0.2': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + '@shikijs/vscode-textmate@10.0.2': {} '@shuding/opentype.js@1.4.0-beta.0': @@ -18342,7 +19044,7 @@ snapshots: '@stripe/ui-extension-tools@0.0.1(@babel/core@7.29.0)(babel-jest@27.5.1(@babel/core@7.29.0))': dependencies: '@types/jest': 28.1.8 - '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint@8.57.1)(typescript@4.9.5) + '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0(eslint@9.39.2(jiti@2.6.1))(typescript@4.9.5))(eslint@8.57.1)(typescript@4.9.5) '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@4.9.5) eslint: 8.57.1 eslint-plugin-react: 7.37.5(eslint@8.57.1) @@ -18639,10 +19341,8 @@ snapshots: token-types: 6.1.2 transitivePeerDependencies: - supports-color - optional: true - '@tokenizer/token@0.3.0': - optional: true + '@tokenizer/token@0.3.0': {} '@tootallnate/once@1.1.2': {} @@ -18771,6 +19471,10 @@ snapshots: '@types/ms@2.1.0': {} + '@types/nlcst@2.0.3': + dependencies: + '@types/unist': 3.0.3 + '@types/node@12.20.55': {} '@types/node@22.19.6': @@ -18880,7 +19584,7 @@ snapshots: '@types/node': 22.19.6 optional: true - '@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint@8.57.1)(typescript@4.9.5)': + '@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@9.39.2(jiti@2.6.1))(typescript@4.9.5))(eslint@8.57.1)(typescript@4.9.5)': dependencies: '@eslint-community/regexpp': 4.12.2 '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@4.9.5) @@ -19486,8 +20190,7 @@ snapshots: alien-signals@3.1.2: {} - amdefine@1.0.1: - optional: true + amdefine@1.0.1: {} anser@1.4.10: {} @@ -19546,6 +20249,8 @@ snapshots: aria-query@5.3.1: {} + aria-query@5.3.2: {} + array-buffer-byte-length@1.0.2: dependencies: call-bound: 1.0.4 @@ -19562,6 +20267,8 @@ snapshots: is-string: 1.1.1 math-intrinsics: 1.1.0 + array-iterate@2.0.1: {} + array-union@2.1.0: {} array.prototype.findlast@1.2.5: @@ -19615,6 +20322,100 @@ snapshots: astring@1.9.0: {} + astro@6.0.4(@types/node@22.19.6)(@upstash/redis@1.36.1)(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.55.1)(terser@5.46.0)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2): + dependencies: + '@astrojs/compiler': 3.0.0 + '@astrojs/internal-helpers': 0.8.0 + '@astrojs/markdown-remark': 7.0.0 + '@astrojs/telemetry': 3.3.0 + '@capsizecss/unpack': 4.0.0 + '@clack/prompts': 1.1.0 + '@oslojs/encoding': 1.1.0 + '@rollup/pluginutils': 5.3.0(rollup@4.55.1) + aria-query: 5.3.2 + axobject-query: 4.1.0 + ci-info: 4.4.0 + clsx: 2.1.1 + common-ancestor-path: 2.0.0 + cookie: 1.1.1 + devalue: 5.6.3 + diff: 8.0.3 + dlv: 1.1.3 + dset: 3.1.4 + es-module-lexer: 2.0.0 + esbuild: 0.27.4 + flattie: 1.1.1 + fontace: 0.4.1 + github-slugger: 2.0.0 + html-escaper: 3.0.3 + http-cache-semantics: 4.2.0 + js-yaml: 4.1.1 + magic-string: 0.30.21 + magicast: 0.5.2 + mrmime: 2.0.1 + neotraverse: 0.6.18 + obug: 2.1.1 + p-limit: 7.3.0 + p-queue: 9.1.0 + package-manager-detector: 1.6.0 + piccolore: 0.1.3 + picomatch: 4.0.3 + rehype: 13.0.2 + semver: 7.7.4 + shiki: 4.0.2 + smol-toml: 1.6.0 + svgo: 4.0.1 + tinyclip: 0.1.12 + tinyexec: 1.0.2 + tinyglobby: 0.2.15 + tsconfck: 3.1.6(typescript@5.9.3) + ultrahtml: 1.6.0 + unifont: 0.7.4 + unist-util-visit: 5.1.0 + unstorage: 1.17.4(@upstash/redis@1.36.1) + vfile: 6.0.3 + vite: 7.3.1(@types/node@22.19.6)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vitefu: 1.1.2(vite@7.3.1(@types/node@22.19.6)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + xxhash-wasm: 1.1.0 + yargs-parser: 22.0.0 + zod: 4.3.6 + optionalDependencies: + sharp: 0.34.5 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@types/node' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - db0 + - idb-keyval + - ioredis + - jiti + - less + - lightningcss + - rollup + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - typescript + - uploadthing + - yaml + async-function@1.0.0: {} async-limiter@1.0.1: {} @@ -19870,6 +20671,8 @@ snapshots: transitivePeerDependencies: - supports-color + boolbase@1.0.0: {} + bplist-creator@0.1.0: dependencies: stream-buffers: 2.2.0 @@ -20051,6 +20854,8 @@ snapshots: ci-info@3.9.0: {} + ci-info@4.4.0: {} + cjs-module-lexer@1.4.3: {} class-variance-authority@0.7.1: @@ -20145,12 +20950,13 @@ snapshots: commander@2.8.1: dependencies: graceful-readlink: 1.0.1 - optional: true commander@4.1.1: {} commander@7.2.0: {} + common-ancestor-path@2.0.0: {} + compressible@2.0.18: dependencies: mime-db: 1.54.0 @@ -20171,7 +20977,6 @@ snapshots: dependencies: amdefine: 1.0.1 commander: 2.8.1 - optional: true concat-map@0.0.1: {} @@ -20201,6 +21006,8 @@ snapshots: convert-source-map@2.0.0: {} + cookie-es@1.2.2: {} + cookie-signature@1.2.2: {} cookie@0.6.0: {} @@ -20237,6 +21044,10 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + crossws@0.3.5: + dependencies: + uncrypto: 0.1.3 + crypto-js@4.2.0: {} crypto-random-string@2.0.0: {} @@ -20263,19 +21074,38 @@ snapshots: semver: 7.7.3 webpack: 5.96.1(esbuild@0.25.0) + css-select@5.2.2: + dependencies: + boolbase: 1.0.0 + css-what: 6.2.2 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + css-to-react-native@3.2.0: dependencies: camelize: 1.0.1 css-color-keywords: 1.0.0 postcss-value-parser: 4.2.0 + css-tree@2.2.1: + dependencies: + mdn-data: 2.0.28 + source-map-js: 1.2.1 + css-tree@3.1.0: dependencies: mdn-data: 2.12.2 source-map-js: 1.2.1 + css-what@6.2.2: {} + cssesc@3.0.0: {} + csso@5.0.5: + dependencies: + css-tree: 2.2.1 + cssom@0.3.8: {} cssom@0.4.4: {} @@ -20428,12 +21258,16 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + defu@6.1.4: {} + delayed-stream@1.0.0: {} depd@2.0.0: {} dequal@2.0.3: {} + destr@2.0.5: {} + destroy@1.2.0: {} detect-gpu@5.0.70: @@ -20468,6 +21302,8 @@ snapshots: dependencies: path-type: 4.0.0 + dlv@1.1.3: {} + doctrine@2.1.0: dependencies: esutils: 2.0.3 @@ -20533,6 +21369,8 @@ snapshots: postgres: 3.4.8 sql.js: 1.13.0 + dset@3.1.4: {} + dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 @@ -20711,6 +21549,8 @@ snapshots: es-module-lexer@1.7.0: {} + es-module-lexer@2.0.0: {} + es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 @@ -20746,12 +21586,12 @@ snapshots: esast-util-from-estree: 2.0.0 vfile-message: 4.0.3 - esbuild-plugin-solid@0.6.0(esbuild@0.27.2)(solid-js@1.9.11): + esbuild-plugin-solid@0.6.0(esbuild@0.27.4)(solid-js@1.9.11): dependencies: '@babel/core': 7.29.0 '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) babel-preset-solid: 1.9.10(@babel/core@7.29.0)(solid-js@1.9.11) - esbuild: 0.27.2 + esbuild: 0.27.4 solid-js: 1.9.11 transitivePeerDependencies: - supports-color @@ -20874,6 +21714,35 @@ snapshots: '@esbuild/win32-ia32': 0.27.2 '@esbuild/win32-x64': 0.27.2 + esbuild@0.27.4: + 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 + escalade@3.2.0: {} escape-html@1.0.3: {} @@ -21565,7 +22434,6 @@ snapshots: fast-xml-parser@5.3.5: dependencies: strnum: 2.1.2 - optional: true fastq@1.20.1: dependencies: @@ -21616,7 +22484,6 @@ snapshots: uint8array-extras: 1.5.0 transitivePeerDependencies: - supports-color - optional: true fill-range@7.1.1: dependencies: @@ -21676,8 +22543,14 @@ snapshots: flatted@3.3.3: {} + flattie@1.1.1: {} + flow-enums-runtime@0.0.6: {} + fontace@0.4.1: + dependencies: + fontkitten: 1.0.3 + fontfaceobserver@2.3.0: {} fontkit@2.0.4: @@ -21692,6 +22565,10 @@ snapshots: unicode-properties: 1.4.1 unicode-trie: 2.0.0 + fontkitten@1.0.3: + dependencies: + tiny-inflate: 1.0.3 + for-each@0.3.5: dependencies: is-callable: 1.2.7 @@ -21832,6 +22709,8 @@ snapshots: github-from-package@0.0.0: optional: true + github-slugger@2.0.0: {} + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -21898,8 +22777,7 @@ snapshots: graceful-fs@4.2.11: {} - graceful-readlink@1.0.1: - optional: true + graceful-readlink@1.0.1: {} graphemer@1.4.0: {} @@ -21912,6 +22790,18 @@ snapshots: section-matter: 1.0.0 strip-bom-string: 1.0.0 + h3@1.15.6: + dependencies: + cookie-es: 1.2.2 + crossws: 0.3.5 + defu: 6.1.4 + destr: 2.0.5 + iron-webcrypto: 1.2.1 + node-mock-http: 1.0.4 + radix3: 1.1.2 + ufo: 1.6.3 + uncrypto: 0.1.3 + has-bigints@1.1.0: {} has-flag@3.0.0: {} @@ -21936,6 +22826,15 @@ snapshots: dependencies: function-bind: 1.1.2 + hast-util-from-html@2.0.3: + dependencies: + '@types/hast': 3.0.4 + devlop: 1.1.0 + hast-util-from-parse5: 8.0.3 + parse5: 7.3.0 + vfile: 6.0.3 + vfile-message: 4.0.3 + hast-util-from-parse5@8.0.3: dependencies: '@types/hast': 3.0.4 @@ -21947,6 +22846,10 @@ snapshots: vfile-location: 5.0.3 web-namespaces: 2.0.1 + hast-util-is-element@3.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-parse-selector@4.0.0: dependencies: '@types/hast': 3.0.4 @@ -22038,6 +22941,13 @@ snapshots: web-namespaces: 2.0.1 zwitch: 2.0.4 + hast-util-to-text@4.0.2: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + hast-util-is-element: 3.0.0 + unist-util-find-after: 5.0.0 + hast-util-whitespace@3.0.0: dependencies: '@types/hast': 3.0.4 @@ -22096,6 +23006,8 @@ snapshots: html-escaper@2.0.2: {} + html-escaper@3.0.3: {} + html-to-text@9.0.5: dependencies: '@selderee/plugin-htmlparser2': 0.11.0 @@ -22115,6 +23027,8 @@ snapshots: domutils: 3.2.2 entities: 4.5.0 + http-cache-semantics@4.2.0: {} + http-errors@2.0.1: dependencies: depd: 2.0.0 @@ -22209,8 +23123,7 @@ snapshots: ini@1.3.8: {} - ini@6.0.0: - optional: true + ini@6.0.0: {} inline-style-parser@0.2.7: {} @@ -22230,6 +23143,8 @@ snapshots: ipaddr.js@1.9.1: {} + iron-webcrypto@1.2.1: {} + is-alphabetical@2.0.1: {} is-alphanumerical@2.0.1: @@ -23129,7 +24044,6 @@ snapshots: - bufferutil - supports-color - utf-8-validate - optional: true keyv@4.5.4: dependencies: @@ -23399,6 +24313,12 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + magicast@0.5.2: + dependencies: + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + source-map-js: 1.2.1 + make-dir@4.0.0: dependencies: semver: 7.7.3 @@ -23421,6 +24341,12 @@ snapshots: math-intrinsics@1.1.0: {} + mdast-util-definitions@6.0.0: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + unist-util-visit: 5.1.0 + mdast-util-find-and-replace@3.0.2: dependencies: '@types/mdast': 4.0.4 @@ -23584,6 +24510,8 @@ snapshots: dependencies: '@types/mdast': 4.0.4 + mdn-data@2.0.28: {} + mdn-data@2.12.2: {} media-engine@1.0.3: {} @@ -24126,8 +25054,7 @@ snapshots: pkg-types: 1.3.1 ufo: 1.6.2 - modern-tar@0.7.3: - optional: true + modern-tar@0.7.3: {} mri@1.2.0: {} @@ -24222,6 +25149,8 @@ snapshots: neo-async@2.6.2: {} + neotraverse@0.6.18: {} + nested-error-stacks@2.0.1: {} next-themes@0.4.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3): @@ -24286,6 +25215,10 @@ snapshots: - '@babel/core' - babel-plugin-macros + nlcst-to-string@4.0.0: + dependencies: + '@types/nlcst': 2.0.3 + node-abi@3.87.0: dependencies: semver: 7.7.3 @@ -24296,6 +25229,8 @@ snapshots: node-domexception@1.0.0: {} + node-fetch-native@1.6.7: {} + node-fetch@3.3.2: dependencies: data-uri-to-buffer: 4.0.1 @@ -24315,6 +25250,8 @@ snapshots: node-gyp-build: 4.8.4 optional: true + node-mock-http@1.0.4: {} + node-releases@2.0.27: {} nopt@7.2.1: @@ -24343,6 +25280,10 @@ snapshots: path-key: 4.0.0 unicorn-magic: 0.3.0 + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + nullthrows@1.1.1: {} nwsapi@2.2.23: {} @@ -24391,6 +25332,14 @@ snapshots: obug@2.1.1: {} + ofetch@1.5.1: + dependencies: + destr: 2.0.5 + node-fetch-native: 1.6.7 + ufo: 1.6.2 + + ohash@2.0.11: {} + on-finished@2.3.0: dependencies: ee-first: 1.1.1 @@ -24497,6 +25446,10 @@ snapshots: dependencies: yocto-queue: 0.1.0 + p-limit@7.3.0: + dependencies: + yocto-queue: 1.2.2 + p-locate@4.1.0: dependencies: p-limit: 2.3.0 @@ -24507,6 +25460,13 @@ snapshots: p-map@2.1.0: {} + p-queue@9.1.0: + dependencies: + eventemitter3: 5.0.1 + p-timeout: 7.0.1 + + p-timeout@7.0.1: {} + p-try@2.2.0: {} package-json-from-dist@1.0.1: {} @@ -24521,8 +25481,7 @@ snapshots: pako@1.0.11: {} - papaparse@5.5.3: - optional: true + papaparse@5.5.3: {} parent-module@1.0.1: dependencies: @@ -24550,6 +25509,15 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + parse-latin@7.0.0: + dependencies: + '@types/nlcst': 2.0.3 + '@types/unist': 3.0.3 + nlcst-to-string: 4.0.0 + unist-util-modify-children: 4.0.0 + unist-util-visit-children: 3.0.0 + vfile: 6.0.3 + parse-ms@4.0.0: {} parse-png@2.1.0: @@ -24609,6 +25577,8 @@ snapshots: pend@1.2.0: {} + piccolore@0.1.3: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -24816,7 +25786,6 @@ snapshots: transitivePeerDependencies: - bufferutil - utf-8-validate - optional: true qrcode-terminal@0.11.0: {} @@ -24967,6 +25936,8 @@ snapshots: '@types/react': 19.2.3 '@types/react-dom': 19.2.3(@types/react@19.2.3) + radix3@1.1.2: {} + randombytes@2.1.0: dependencies: safe-buffer: 5.2.1 @@ -24987,8 +25958,7 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - re2js@1.2.1: - optional: true + re2js@1.2.1: {} react-confetti-explosion@3.0.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: @@ -25535,6 +26505,12 @@ snapshots: dependencies: unist-util-visit: 5.1.0 + rehype-parse@9.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-from-html: 2.0.3 + unified: 11.0.5 + rehype-raw@7.0.0: dependencies: '@types/hast': 3.0.4 @@ -25554,6 +26530,19 @@ snapshots: '@types/hast': 3.0.4 hast-util-sanitize: 5.0.2 + rehype-stringify@10.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + unified: 11.0.5 + + rehype@13.0.2: + dependencies: + '@types/hast': 3.0.4 + rehype-parse: 9.0.1 + rehype-stringify: 10.0.1 + unified: 11.0.5 + remark-gfm@4.0.1: dependencies: '@types/mdast': 4.0.4 @@ -25589,6 +26578,13 @@ snapshots: unified: 11.0.5 vfile: 6.0.3 + remark-smartypants@3.0.2: + dependencies: + retext: 9.0.0 + retext-smartypants: 6.2.0 + unified: 11.0.5 + unist-util-visit: 5.1.0 + remark-stringify@11.0.0: dependencies: '@types/mdast': 4.0.4 @@ -25671,6 +26667,31 @@ snapshots: restructure@3.0.2: {} + retext-latin@4.0.0: + dependencies: + '@types/nlcst': 2.0.3 + parse-latin: 7.0.0 + unified: 11.0.5 + + retext-smartypants@6.2.0: + dependencies: + '@types/nlcst': 2.0.3 + nlcst-to-string: 4.0.0 + unist-util-visit: 5.1.0 + + retext-stringify@4.0.0: + dependencies: + '@types/nlcst': 2.0.3 + nlcst-to-string: 4.0.0 + unified: 11.0.5 + + retext@9.0.0: + dependencies: + '@types/nlcst': 2.0.3 + retext-latin: 4.0.0 + retext-stringify: 4.0.0 + unified: 11.0.5 + rettime@0.10.1: {} reusify@1.1.0: {} @@ -25780,6 +26801,8 @@ snapshots: sax@1.4.4: {} + sax@1.5.0: {} + saxes@5.0.1: dependencies: xmlchars: 2.2.0 @@ -25832,6 +26855,8 @@ snapshots: semver@7.7.3: {} + semver@7.7.4: {} + send@0.19.2: dependencies: debug: 2.6.9 @@ -26023,6 +27048,17 @@ snapshots: '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 + shiki@4.0.2: + dependencies: + '@shikijs/core': 4.0.2 + '@shikijs/engine-javascript': 4.0.2 + '@shikijs/engine-oniguruma': 4.0.2 + '@shikijs/langs': 4.0.2 + '@shikijs/themes': 4.0.2 + '@shikijs/types': 4.0.2 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + side-channel-list@1.0.0: dependencies: es-errors: 1.3.0 @@ -26094,8 +27130,7 @@ snapshots: slugify@1.6.6: {} - smol-toml@1.6.0: - optional: true + smol-toml@1.6.0: {} solid-js@1.9.11: dependencies: @@ -26152,11 +27187,9 @@ snapshots: sprintf-js@1.0.3: {} - sprintf-js@1.1.3: - optional: true + sprintf-js@1.1.3: {} - sql.js@1.13.0: - optional: true + sql.js@1.13.0: {} stack-utils@2.0.6: dependencies: @@ -26364,13 +27397,11 @@ snapshots: '@types/node': 22.19.6 qs: 6.14.1 - strnum@2.1.2: - optional: true + strnum@2.1.2: {} strtok3@10.3.4: dependencies: '@tokenizer/token': 0.3.0 - optional: true structured-headers@0.4.1: {} @@ -26482,6 +27513,16 @@ snapshots: svg-arc-to-cubic-bezier@3.2.0: {} + svgo@4.0.1: + dependencies: + commander: 11.1.0 + css-select: 5.2.2 + css-tree: 3.1.0 + css-what: 6.2.2 + csso: 5.0.5 + picocolors: 1.1.1 + sax: 1.5.0 + swr@2.4.0(react@19.2.3): dependencies: dequal: 2.0.3 @@ -26636,6 +27677,8 @@ snapshots: tinybench@2.9.0: {} + tinyclip@0.1.12: {} + tinyexec@0.3.2: {} tinyexec@1.0.2: {} @@ -26666,7 +27709,6 @@ snapshots: '@borewit/text-codec': 0.2.1 '@tokenizer/token': 0.3.0 ieee754: 1.2.1 - optional: true totalist@3.0.1: {} @@ -26753,6 +27795,10 @@ snapshots: '@ts-morph/common': 0.27.0 code-block-writer: 13.0.3 + tsconfck@3.1.6(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 + tsconfig-paths@4.2.0: dependencies: json5: 2.2.3 @@ -26846,7 +27892,6 @@ snapshots: turndown@7.2.2: dependencies: '@mixmark-io/domino': 2.2.0 - optional: true tw-animate-css@1.4.0: {} @@ -26930,8 +27975,11 @@ snapshots: ufo@1.6.2: {} - uint8array-extras@1.5.0: - optional: true + ufo@1.6.3: {} + + uint8array-extras@1.5.0: {} + + ultrahtml@1.6.0: {} unbox-primitive@1.1.0: dependencies: @@ -26979,14 +28027,30 @@ snapshots: trough: 2.2.0 vfile: 6.0.3 + unifont@0.7.4: + dependencies: + css-tree: 3.1.0 + ofetch: 1.5.1 + ohash: 2.0.11 + unique-string@2.0.0: dependencies: crypto-random-string: 2.0.0 + unist-util-find-after@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-is@6.0.1: dependencies: '@types/unist': 3.0.3 + unist-util-modify-children@4.0.0: + dependencies: + '@types/unist': 3.0.3 + array-iterate: 2.0.1 + unist-util-position-from-estree@2.0.0: dependencies: '@types/unist': 3.0.3 @@ -26995,10 +28059,19 @@ snapshots: dependencies: '@types/unist': 3.0.3 + unist-util-remove-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-visit: 5.1.0 + unist-util-stringify-position@4.0.0: dependencies: '@types/unist': 3.0.3 + unist-util-visit-children@3.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-visit-parents@6.0.2: dependencies: '@types/unist': 3.0.3 @@ -27018,6 +28091,19 @@ snapshots: unpipe@1.0.0: {} + unstorage@1.17.4(@upstash/redis@1.36.1): + dependencies: + anymatch: 3.1.3 + chokidar: 5.0.0 + destr: 2.0.5 + h3: 1.15.6 + lru-cache: 11.2.4 + node-fetch-native: 1.6.7 + ofetch: 1.5.1 + ufo: 1.6.3 + optionalDependencies: + '@upstash/redis': 1.36.1 + until-async@3.0.2: {} update-browserslist-db@1.2.3(browserslist@4.28.1): @@ -27524,6 +28610,8 @@ snapshots: is-weakmap: 2.0.2 is-weakset: 2.0.4 + which-pm-runs@1.1.0: {} + which-typed-array@1.1.19: dependencies: available-typed-arrays: 1.0.7 @@ -27624,6 +28712,8 @@ snapshots: xmlchars@2.2.0: {} + xxhash-wasm@1.1.0: {} + y18n@5.0.8: {} yallist@3.1.1: {} @@ -27638,6 +28728,8 @@ snapshots: yargs-parser@21.1.1: {} + yargs-parser@22.0.0: {} + yargs@16.2.0: dependencies: cliui: 7.0.4 @@ -27665,6 +28757,8 @@ snapshots: yocto-queue@0.1.0: {} + yocto-queue@1.2.2: {} + yoctocolors-cjs@2.1.3: {} yoctocolors@2.1.2: {} From ae1c5dff458403a37a9c7c3d9a3056989901a184 Mon Sep 17 00:00:00 2001 From: Aperrix Date: Fri, 13 Mar 2026 09:29:10 +0100 Subject: [PATCH 04/10] test(astro): add SSR-specific tests and enhance example with request-time state Add 8 new tests covering SSR safety: - No DOM globals dependency - Synchronous output (no promises) - No script tags or event handlers in output - XSS escaping in HTML attributes (href, src, alt) - Unicode content handling - Request-time state resolution (per-request rendering) - No caching leak between renders - Repeat with $index for position-aware rendering Example now demonstrates server-side state injection with timestamp. --- examples/astro/src/lib/spec.ts | 19 +++ examples/astro/src/pages/index.astro | 16 +- packages/astro/src/render.test.ts | 221 +++++++++++++++++++++++++++ 3 files changed, 255 insertions(+), 1 deletion(-) diff --git a/examples/astro/src/lib/spec.ts b/examples/astro/src/lib/spec.ts index 50dadbd7..8603a3c8 100644 --- a/examples/astro/src/lib/spec.ts +++ b/examples/astro/src/lib/spec.ts @@ -32,6 +32,7 @@ export const demoSpec: Spec = { "banner", "features-card", "admin-card", + "timestamp-card", "links-card", ], }, @@ -96,6 +97,24 @@ export const demoSpec: Spec = { children: [], }, + // Server timestamp (resolved from request-time state) + "timestamp-card": { + type: "Card", + props: { + title: "Server Info", + subtitle: null, + }, + children: ["timestamp-text"], + }, + "timestamp-text": { + type: "Text", + props: { + content: { $state: "/serverTimestamp" }, + }, + children: [], + visible: { $state: "/serverTimestamp" }, + }, + // Links "links-card": { type: "Card", diff --git a/examples/astro/src/pages/index.astro b/examples/astro/src/pages/index.astro index 41e84f71..4a1e80bf 100644 --- a/examples/astro/src/pages/index.astro +++ b/examples/astro/src/pages/index.astro @@ -3,9 +3,20 @@ import { renderToHtml } from "@json-render/astro"; import { registry } from "../lib/registry"; import { demoSpec } from "../lib/spec"; +// Simulate request-time state (e.g. from a database, auth middleware, or API) +// In a real Astro SSR app, this would come from Astro.cookies, fetch(), etc. +const requestState = { + showBanner: true, + userRole: "admin", + // Override spec defaults with server-side data + serverTimestamp: new Date().toISOString(), +}; + +// renderToHtml is synchronous — no await needed. +// State from options overrides spec.state, enabling per-request rendering. const html = renderToHtml(demoSpec, { registry, - state: { showBanner: true, userRole: "admin" }, + state: requestState, }); --- @@ -38,5 +49,8 @@ const html = renderToHtml(demoSpec, {
    +
    + Rendered at {requestState.serverTimestamp} +
    diff --git a/packages/astro/src/render.test.ts b/packages/astro/src/render.test.ts index 0f370ccb..a8101099 100644 --- a/packages/astro/src/render.test.ts +++ b/packages/astro/src/render.test.ts @@ -383,6 +383,227 @@ describe("renderToHtml", () => { }); }); +// ============================================================================= +// SSR-specific concerns +// ============================================================================= + +describe("SSR safety", () => { + it("works without DOM globals (no window, document, navigator)", () => { + // The renderer is pure string concatenation — verify it never + // touches browser globals by running in a plain Node/Vitest context + const spec = simpleSpec({ + root: { + type: "Container", + props: {}, + children: ["heading", "text"], + }, + heading: { + type: "Heading", + props: { text: "SSR", level: "h1" }, + children: [], + }, + text: { + type: "Text", + props: { content: "Server-rendered" }, + children: [], + }, + }); + // If this throws, the renderer depends on browser APIs + const html = renderToHtml(spec, { registry: testRegistry }); + expect(html).toContain("

    SSR

    "); + expect(html).toContain("

    Server-rendered

    "); + }); + + it("is synchronous (no promises, no async)", () => { + const spec = simpleSpec({ + root: { type: "Text", props: { content: "sync" }, children: [] }, + }); + const result = renderToHtml(spec, { registry: testRegistry }); + // Result is a plain string, not a Promise + expect(typeof result).toBe("string"); + expect(result).not.toBeInstanceOf(Promise); + }); + + it("produces no script tags or event handlers in output", () => { + const spec = simpleSpec({ + root: { + type: "Container", + props: {}, + children: ["card", "link"], + }, + card: { + type: "Card", + props: { title: "Test" }, + children: ["text"], + }, + text: { + type: "Text", + props: { content: "Content" }, + children: [], + }, + link: { + type: "Link", + props: { href: "https://example.com", text: "Click" }, + children: [], + }, + }); + const html = renderToHtml(spec, { registry: testRegistry }); + expect(html).not.toMatch(/]/i); + expect(html).not.toMatch(/\bon\w+\s*=/i); // no onclick, onload, etc. + }); + + it("escapes XSS attempts in HTML attributes (href, src, alt)", () => { + const spec = simpleSpec({ + root: { + type: "Container", + props: {}, + children: ["evil-link", "evil-image"], + }, + "evil-link": { + type: "Link", + props: { + href: 'javascript:alert("xss")', + text: "Click me", + }, + children: [], + }, + "evil-image": { + type: "Image", + props: { + src: '" onerror="alert(1)', + alt: '">', + }, + children: [], + }, + }); + const html = renderToHtml(spec, { registry: testRegistry }); + // href should be escaped (quotes neutralized) + expect(html).not.toContain('onerror="alert'); + expect(html).not.toContain("'); -// => <script>alert("xss")</script> -``` +{'// Comparisons'} +{'{ "$state": "/status", "eq": "active" }'} +{'{ "$state": "/count", "gt": 10 }'} + +{'// Negation'} +{'{ "$state": "/maintenance", "not": true }'} -## Component Registry +{'// Multiple conditions (implicit AND)'} +{'[{ "$state": "/feature/enabled" }, { "$state": "/maintenance", "not": true }]'} -Unlike React/Vue renderers, the Astro SSR registry uses plain functions that return HTML strings. +{'// Always / never'} +true // always visible +false // never visible +``` + +TypeScript helpers from `@json-render/core`: ```typescript -import type { ComponentRegistry } from '@json-render/astro'; - -const registry: ComponentRegistry = { - Section: ({ props, children }) => - `
    ${children}
    `, - Heading: ({ props }) => - `<${props.level || 'h2'}>${escapeHtml(props.text)}`, - Text: ({ props }) => - `

    ${escapeHtml(props.content)}

    `, -}; +import { visibility } from "@json-render/core"; + +visibility.when("/path") // { $state: "/path" } +visibility.unless("/path") // { $state: "/path", not: true } +visibility.eq("/path", val) // { $state: "/path", eq: val } +visibility.and(cond1, cond2) // { $and: [cond1, cond2] } ``` -Each function receives: +## Dynamic Prop Expressions + +Any prop value can use data-driven expressions that resolve at render time. The renderer resolves these transparently before passing props to components. + +```json +{ + "type": "Badge", + "props": { + "label": { "$state": "/user/role" }, + "color": { + "$cond": { "$state": "/user/role", "eq": "admin" }, + "$then": "red", + "$else": "gray" + } + } +} +``` - - + - - - + + + + + + - - - + + + + + + + + + +
    PropTypeExpression Description
    propsPResolved props (all $state/$cond expressions already evaluated){'{ "$state": "/path" }'}Read a value from state
    {'{ "$cond": ..., "$then": ..., "$else": ... }'}Conditional value based on a visibility condition
    childrenstringPre-rendered children as HTML string{'{ "$template": "Hello, ${/name}!" }'}Interpolate state values into strings
    {'{ "$item": "field" }'}Read from current repeat item
    {'{ "$index": true }'}Current repeat index
    -## Usage with Astro +No two-way binding (`$bindState`, `$bindItem`) since Astro is static HTML. For interactive form components, use an Astro island. -```astro ---- -import { renderToHtml } from '@json-render/astro'; +## SSG vs SSR -const html = renderToHtml(spec, { registry }); ---- - -
    -``` +The package works in both modes without modification: -## Usage with Cloudflare Workers +- **SSG** (default, no adapter) -- state is resolved at build time +- **SSR** (with adapter) -- state is resolved at each request -```typescript -import { renderToHtml } from '@json-render/astro/render'; - -export default { - async fetch(request) { - const spec = await getSpec(request); - const html = renderToHtml(spec, { registry }); - return new Response(html, { - headers: { 'Content-Type': 'text/html' }, - }); - }, -}; -``` +The choice is a project-level Astro decision, not a package concern. ## Astro Islands -Use `@json-render/astro` for static content and framework-specific renderers for interactive islands. This is the recommended pattern for Astro apps. +Use `@json-render/astro` for static content and framework-specific renderers for interactive islands. -```astro +{`\`\`\`astro --- -import { renderToHtml } from '@json-render/astro'; +import Renderer from '@json-render/astro/Renderer.astro'; import Counter from '../components/Counter'; // React, Vue, Svelte, or Solid -const staticHtml = renderToHtml(spec, { registry }); --- -{''} -
    + + -{''} + -``` +\`\`\``} @@ -217,13 +282,49 @@ Each island uses its own `@json-render/*` renderer internally (`defineRegistry` See the [islands example](https://github.com/vercel-labs/json-render/tree/main/examples/astro/src/pages/islands.astro) for a working implementation with React. -## Server-Safe Import - -Import schema and catalog definitions without the renderer: +## Differences from Other Renderers -```typescript -import { schema, defineCatalog } from '@json-render/astro/server'; -``` +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AspectReact / Vue / Svelte / SolidAstro
    OutputClient-side interactive UIStatic HTML (zero JS)
    ComponentsFramework components / render functions.astro files with {""}
    Actionsemit(), on(), built-in state actionsNone (use islands for interactivity)
    State mutations$bindState, setState actionRead-only ($state, $cond)
    ProvidersStateProvider, ActionProvider, etc.None (state passed as prop)
    Hooks / ComposablesuseStateStore, useActions, etc.None (static rendering)
    ## Sub-path Exports @@ -237,15 +338,19 @@ import { schema, defineCatalog } from '@json-render/astro/server'; @json-render/astro - Full package: schema, renderer, types + Full package: schema, defineRegistry, types - @json-render/astro/server - Schema and catalog definitions only (no renderer) + @json-render/astro/schema + Schema only - @json-render/astro/render - Render functions and types only + @json-render/astro/Renderer.astro + Entry point Astro component + + + @json-render/astro/ElementRenderer.astro + Recursive element renderer @@ -262,35 +367,27 @@ import { schema, defineCatalog } from '@json-render/astro/server'; AstroSchema - Schema type for SSR specs - - - AstroSpec - Spec type for SSR output - - - RenderOptions - Options for renderToHtml() - - - ComponentRenderProps - Props passed to component render functions + Schema type - ComponentRenderer - Component render function type + {"AstroSpec"} + Infer the spec type from a catalog - ComponentRegistry - Map of component names to render functions + AstroComponentRegistry + Registry mapping component names to Astro components {"Components"} Typed registry for a specific catalog - {"ComponentFn"} - Typed render function for a specific component + DefineRegistryResult + Return type of defineRegistry() + + + StateModel + State model type (re-export from core) diff --git a/apps/web/lib/docs-navigation.ts b/apps/web/lib/docs-navigation.ts index f935c7b5..67e510d6 100644 --- a/apps/web/lib/docs-navigation.ts +++ b/apps/web/lib/docs-navigation.ts @@ -102,7 +102,7 @@ export const docsNavigation: NavSection[] = [ external: true, }, { - title: "Astro SSR + Islands", + title: "Astro (SSG + Islands)", href: "https://github.com/vercel-labs/json-render/tree/main/examples/astro", external: true, }, diff --git a/examples/astro/.astro/content.d.ts b/examples/astro/.astro/content.d.ts deleted file mode 100644 index f2f5acf0..00000000 --- a/examples/astro/.astro/content.d.ts +++ /dev/null @@ -1,187 +0,0 @@ -declare module "astro:content" { - export interface RenderResult { - Content: import("astro/runtime/server/index.js").AstroComponentFactory; - headings: import("astro").MarkdownHeading[]; - remarkPluginFrontmatter: Record; - } - interface Render { - ".md": Promise; - } - - export interface RenderedContent { - html: string; - metadata?: { - imagePaths: Array; - [key: string]: unknown; - }; - } - - type Flatten = T extends { [K: string]: infer U } ? U : never; - - export type CollectionKey = keyof DataEntryMap; - export type CollectionEntry = Flatten< - DataEntryMap[C] - >; - - type AllValuesOf = T extends any ? T[keyof T] : never; - - export type ReferenceDataEntry< - C extends CollectionKey, - E extends keyof DataEntryMap[C] = string, - > = { - collection: C; - id: E; - }; - - export type ReferenceLiveEntry< - C extends keyof LiveContentConfig["collections"], - > = { - collection: C; - id: string; - }; - - export function getCollection< - C extends keyof DataEntryMap, - E extends CollectionEntry, - >( - collection: C, - filter?: (entry: CollectionEntry) => entry is E, - ): Promise; - export function getCollection( - collection: C, - filter?: (entry: CollectionEntry) => unknown, - ): Promise[]>; - - export function getLiveCollection< - C extends keyof LiveContentConfig["collections"], - >( - collection: C, - filter?: LiveLoaderCollectionFilterType, - ): Promise< - import("astro").LiveDataCollectionResult< - LiveLoaderDataType, - LiveLoaderErrorType - > - >; - - export function getEntry< - C extends keyof DataEntryMap, - E extends keyof DataEntryMap[C] | (string & {}), - >( - entry: ReferenceDataEntry, - ): E extends keyof DataEntryMap[C] - ? Promise - : Promise | undefined>; - export function getEntry< - C extends keyof DataEntryMap, - E extends keyof DataEntryMap[C] | (string & {}), - >( - collection: C, - id: E, - ): E extends keyof DataEntryMap[C] - ? string extends keyof DataEntryMap[C] - ? Promise | undefined - : Promise - : Promise | undefined>; - export function getLiveEntry< - C extends keyof LiveContentConfig["collections"], - >( - collection: C, - filter: string | LiveLoaderEntryFilterType, - ): Promise< - import("astro").LiveDataEntryResult< - LiveLoaderDataType, - LiveLoaderErrorType - > - >; - - /** Resolve an array of entry references from the same collection */ - export function getEntries( - entries: ReferenceDataEntry[], - ): Promise[]>; - - export function render( - entry: DataEntryMap[C][string], - ): Promise; - - export function reference< - C extends - | keyof DataEntryMap - // Allow generic `string` to avoid excessive type errors in the config - // if `dev` is not running to update as you edit. - // Invalid collection names will be caught at build time. - | (string & {}), - >( - collection: C, - ): import("astro/zod").ZodPipe< - import("astro/zod").ZodString, - import("astro/zod").ZodTransform< - C extends keyof DataEntryMap - ? { - collection: C; - id: string; - } - : never, - string - > - >; - - type ReturnTypeOrOriginal = T extends (...args: any[]) => infer R ? R : T; - type InferEntrySchema = - import("astro/zod").infer< - ReturnTypeOrOriginal["schema"]> - >; - type InferLoaderSchema< - C extends keyof DataEntryMap, - L = Required["loader"], - > = L extends { schema: import("astro/zod").ZodSchema } - ? import("astro/zod").infer< - Required["loader"]["schema"] - > - : any; - - type DataEntryMap = {}; - - type ExtractLoaderTypes = T extends import("astro/loaders").LiveLoader< - infer TData, - infer TEntryFilter, - infer TCollectionFilter, - infer TError - > - ? { - data: TData; - entryFilter: TEntryFilter; - collectionFilter: TCollectionFilter; - error: TError; - } - : { - data: never; - entryFilter: never; - collectionFilter: never; - error: never; - }; - type ExtractEntryFilterType = ExtractLoaderTypes["entryFilter"]; - type ExtractCollectionFilterType = - ExtractLoaderTypes["collectionFilter"]; - type ExtractErrorType = ExtractLoaderTypes["error"]; - - type LiveLoaderDataType = - LiveContentConfig["collections"][C]["schema"] extends undefined - ? ExtractDataType - : import("astro/zod").infer< - Exclude - >; - type LiveLoaderEntryFilterType< - C extends keyof LiveContentConfig["collections"], - > = ExtractEntryFilterType; - type LiveLoaderCollectionFilterType< - C extends keyof LiveContentConfig["collections"], - > = ExtractCollectionFilterType< - LiveContentConfig["collections"][C]["loader"] - >; - type LiveLoaderErrorType = - ExtractErrorType; - - export type ContentConfig = never; - export type LiveContentConfig = never; -} diff --git a/examples/astro/.astro/types.d.ts b/examples/astro/.astro/types.d.ts deleted file mode 100644 index 306a68bf..00000000 --- a/examples/astro/.astro/types.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/examples/astro/src/components/AstroLink.astro b/examples/astro/src/components/AstroLink.astro new file mode 100644 index 00000000..2d3dd0ba --- /dev/null +++ b/examples/astro/src/components/AstroLink.astro @@ -0,0 +1,10 @@ +--- +interface Props { + href: string; + text: string; +} + +const { href, text } = Astro.props; +--- + +{text} diff --git a/examples/astro/src/components/AstroText.astro b/examples/astro/src/components/AstroText.astro new file mode 100644 index 00000000..c4a7cbb1 --- /dev/null +++ b/examples/astro/src/components/AstroText.astro @@ -0,0 +1,9 @@ +--- +interface Props { + content: string; +} + +const { content } = Astro.props; +--- + +

    {content}

    diff --git a/examples/astro/src/components/Badge.astro b/examples/astro/src/components/Badge.astro new file mode 100644 index 00000000..a33bad04 --- /dev/null +++ b/examples/astro/src/components/Badge.astro @@ -0,0 +1,19 @@ +--- +interface Props { + label: string; + variant?: string | null; +} + +const { label, variant } = Astro.props; + +const colors: Record = { + default: { bg: "#e0f2fe", fg: "#0369a1", border: "#bae6fd" }, + success: { bg: "#dcfce7", fg: "#15803d", border: "#bbf7d0" }, + warning: { bg: "#fef9c3", fg: "#a16207", border: "#fde68a" }, +}; +const c = colors[variant ?? "default"] ?? colors.default!; +--- + + + {label} + diff --git a/examples/astro/src/components/Card.astro b/examples/astro/src/components/Card.astro new file mode 100644 index 00000000..3d071b4d --- /dev/null +++ b/examples/astro/src/components/Card.astro @@ -0,0 +1,14 @@ +--- +interface Props { + title: string; + subtitle?: string | null; +} + +const { title, subtitle } = Astro.props; +--- + +
    +

    {title}

    + {subtitle &&

    {subtitle}

    } + +
    diff --git a/examples/astro/src/components/Heading.astro b/examples/astro/src/components/Heading.astro new file mode 100644 index 00000000..3b14afb9 --- /dev/null +++ b/examples/astro/src/components/Heading.astro @@ -0,0 +1,11 @@ +--- +interface Props { + text: string; + level?: string | null; +} + +const { text, level } = Astro.props; +const Tag = (level || "h2") as any; +--- + +{text} diff --git a/examples/astro/src/components/List.astro b/examples/astro/src/components/List.astro new file mode 100644 index 00000000..baaed490 --- /dev/null +++ b/examples/astro/src/components/List.astro @@ -0,0 +1,6 @@ +--- +--- + +
      + +
    diff --git a/examples/astro/src/components/ListItem.astro b/examples/astro/src/components/ListItem.astro new file mode 100644 index 00000000..c1793dff --- /dev/null +++ b/examples/astro/src/components/ListItem.astro @@ -0,0 +1,9 @@ +--- +interface Props { + text: string; +} + +const { text } = Astro.props; +--- + +
  • {text}
  • diff --git a/examples/astro/src/components/Section.astro b/examples/astro/src/components/Section.astro new file mode 100644 index 00000000..557a237f --- /dev/null +++ b/examples/astro/src/components/Section.astro @@ -0,0 +1,12 @@ +--- +interface Props { + id?: string | null; + className?: string | null; +} + +const { id, className } = Astro.props; +--- + +
    + +
    diff --git a/examples/astro/src/lib/catalog.ts b/examples/astro/src/lib/catalog.ts index 2977c98c..8d679970 100644 --- a/examples/astro/src/lib/catalog.ts +++ b/examples/astro/src/lib/catalog.ts @@ -57,5 +57,3 @@ export const catalog = defineCatalog(schema, { }, }, }); - -export type AppCatalog = typeof catalog; diff --git a/examples/astro/src/lib/registry.ts b/examples/astro/src/lib/registry.ts deleted file mode 100644 index 50300ad0..00000000 --- a/examples/astro/src/lib/registry.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { escapeHtml } from "@json-render/astro"; -import type { ComponentRegistry } from "@json-render/astro"; - -export const registry: ComponentRegistry = { - Section: ({ props, children }) => { - const attrs = [ - props.id ? ` id="${escapeHtml(props.id)}"` : "", - props.className ? ` class="${escapeHtml(props.className)}"` : "", - ].join(""); - return `${children}`; - }, - - Card: ({ props, children }) => - `
    -

    ${escapeHtml(props.title)}

    - ${props.subtitle ? `

    ${escapeHtml(props.subtitle)}

    ` : ""} - ${children} -
    `, - - Heading: ({ props }) => { - const tag = props.level || "h2"; - return `<${tag}>${escapeHtml(props.text)}`; - }, - - Text: ({ props }) => - `

    ${escapeHtml(props.content)}

    `, - - Badge: ({ props }) => { - const colors: Record = { - default: { bg: "#e0f2fe", fg: "#0369a1", border: "#bae6fd" }, - success: { bg: "#dcfce7", fg: "#15803d", border: "#bbf7d0" }, - warning: { bg: "#fef9c3", fg: "#a16207", border: "#fde68a" }, - }; - const c = colors[props.variant ?? "default"] ?? colors.default!; - return `${escapeHtml(props.label)}`; - }, - - List: ({ children }) => - `
      ${children}
    `, - - ListItem: ({ props }) => - `
  • ${escapeHtml(props.text)}
  • `, - - Link: ({ props }) => - `${escapeHtml(props.text)}`, -}; diff --git a/examples/astro/src/lib/spec.ts b/examples/astro/src/lib/spec.ts index 8603a3c8..5b36e7ca 100644 --- a/examples/astro/src/lib/spec.ts +++ b/examples/astro/src/lib/spec.ts @@ -18,8 +18,9 @@ export const demoSpec: Spec = { }, { id: "3", - name: "Edge-ready", - description: "Works in Cloudflare Workers, Deno, Bun", + name: "SSG + SSR", + description: + "Works with any Astro adapter (Cloudflare, Vercel, Netlify, Node)", }, ], }, diff --git a/examples/astro/src/pages/index.astro b/examples/astro/src/pages/index.astro index 6dd05684..c7944e51 100644 --- a/examples/astro/src/pages/index.astro +++ b/examples/astro/src/pages/index.astro @@ -1,23 +1,44 @@ --- -import { renderToHtml } from "@json-render/astro"; -import { registry } from "../lib/registry"; +/** + * Full static demo with defineRegistry + Renderer. + * + * Components are real .astro files with syntax highlighting, autocompletion, + * and automatic XSS protection. The walks the JSON spec tree + * and renders each element using the matching Astro component. + */ +import Renderer from "@json-render/astro/Renderer.astro"; +import { defineRegistry } from "@json-render/astro"; +import { catalog } from "../lib/catalog"; import { demoSpec } from "../lib/spec"; +import Section from "../components/Section.astro"; +import Card from "../components/Card.astro"; +import Heading from "../components/Heading.astro"; +import AstroText from "../components/AstroText.astro"; +import Badge from "../components/Badge.astro"; +import List from "../components/List.astro"; +import ListItem from "../components/ListItem.astro"; +import AstroLink from "../components/AstroLink.astro"; + +const { registry } = defineRegistry(catalog, { + components: { + Section, + Card, + Heading, + Text: AstroText, + Badge, + List, + ListItem, + Link: AstroLink, + }, +}); + // Simulate request-time state (e.g. from a database, auth middleware, or API) -// In a real Astro SSR app, this would come from Astro.cookies, fetch(), etc. const requestState = { showBanner: true, userRole: "admin", - // Override spec defaults with server-side data serverTimestamp: new Date().toISOString(), }; - -// renderToHtml is synchronous — no await needed. -// State from options overrides spec.state, enabling per-request rendering. -const html = renderToHtml(demoSpec, { - registry, - state: requestState, -}); --- @@ -26,29 +47,19 @@ const html = renderToHtml(demoSpec, { @json-render/astro demo -
    +