From 3c4f5869f8eaf5e4c706b19acfd6fa7f260d16f7 Mon Sep 17 00:00:00 2001 From: Pawel Kosiec Date: Mon, 26 Jan 2026 12:02:34 +0100 Subject: [PATCH] docs: generate `llms.txt` from docs and host in on docs website --- docs/docs/api/appkit-ui/styling.md | 82 ++ docs/docs/app-management.mdx | 12 +- docs/docs/configuration.mdx | 145 +++ docs/docs/development/_category_.json | 11 + docs/docs/development/llm-guide.mdx | 82 ++ docs/docs/development/project-setup.mdx | 235 ++++ docs/docs/development/type-generation.mdx | 108 ++ docs/docs/plugins.md | 227 +++- docs/docusaurus.config.ts | 30 + docs/package.json | 1 + docs/static/appkit-ui/styles.gen.css | 10 + llms.txt | 1234 --------------------- pnpm-lock.yaml | 362 ++++-- 13 files changed, 1213 insertions(+), 1326 deletions(-) create mode 100644 docs/docs/api/appkit-ui/styling.md create mode 100644 docs/docs/configuration.mdx create mode 100644 docs/docs/development/_category_.json create mode 100644 docs/docs/development/llm-guide.mdx create mode 100644 docs/docs/development/project-setup.mdx create mode 100644 docs/docs/development/type-generation.mdx delete mode 100644 llms.txt diff --git a/docs/docs/api/appkit-ui/styling.md b/docs/docs/api/appkit-ui/styling.md new file mode 100644 index 00000000..3736962b --- /dev/null +++ b/docs/docs/api/appkit-ui/styling.md @@ -0,0 +1,82 @@ +--- +sidebar_position: 4 +--- + +# Styling + +This guide covers how to style AppKit UI components using CSS variables and theming. + +## CSS import + +In your main CSS file, import the AppKit UI styles: + +```css +@import "@databricks/appkit-ui/styles.css"; +``` + +This provides a default theme for your app using CSS variables. + +## Customizing theme + +AppKit UI uses CSS variables for theming, supporting both light and dark modes automatically. + +### Full variable list + +You can customize the theme by overriding CSS variables. See the [CSS variables](https://github.com/databricks/appkit/blob/main/packages/appkit-ui/src/react/styles/globals.css) for the full list of variables. + +:::warning Important +If you change any variable, you must change it for **both light and dark mode** to ensure consistent appearance across color schemes. +::: + +## Color system + +AppKit UI uses the OKLCH color space for better perceptual uniformity. The format is: + +``` +oklch(lightness chroma hue) +``` + +Where: +- **lightness**: 0-1 (0 = black, 1 = white) +- **chroma**: 0-0.4 (saturation) +- **hue**: 0-360 (color angle) + +## Semantic color variables + +### Core colors + +- `--background` / `--foreground` - Main background and text +- `--card` / `--card-foreground` - Card backgrounds +- `--popover` / `--popover-foreground` - Popover/dropdown backgrounds + +### Interactive colors + +- `--primary` / `--primary-foreground` - Primary actions +- `--secondary` / `--secondary-foreground` - Secondary actions +- `--muted` / `--muted-foreground` - Muted/disabled states +- `--accent` / `--accent-foreground` - Accent highlights + +### Status colors + +- `--destructive` / `--destructive-foreground` - Destructive actions +- `--success` / `--success-foreground` - Success states +- `--warning` / `--warning-foreground` - Warning states + +### UI elements + +- `--border` - Border colors +- `--input` - Input field borders +- `--ring` - Focus ring colors +- `--radius` - Border radius + +### Charts + +- `--chart-1` through `--chart-5` - Chart color palette + +### Sidebar + +- `--sidebar-*` - Sidebar-specific colors + +## See also + +- [API Reference](/docs/api/appkit-ui) - Complete UI components API documentation diff --git a/docs/docs/app-management.mdx b/docs/docs/app-management.mdx index 75d484bf..56c60354 100644 --- a/docs/docs/app-management.mdx +++ b/docs/docs/app-management.mdx @@ -1,5 +1,5 @@ --- -sidebar_position: 3 +sidebar_position: 2 --- import Prerequisites from './_prerequisites.mdx'; @@ -16,12 +16,10 @@ See the [Quick start](./index.md) section to create a new Databricks app with Ap ## Configuration -Before deploying your app, configure it according to your needs. See the [Databricks Apps Configuration](https://docs.databricks.com/aws/en/dev-tools/databricks-apps/configuration) documentation for details on: - -- App configuration file (`app.yaml`) -- Environment variables -- Authorization and permissions -- Networking configuration +Before deploying your app, you need to configure it. See the [Configuration guide](./configuration.mdx) for details on: +- `app.yaml` configuration and command specification +- Environment variables and SQL warehouse binding +- Local development authentication options ## Deploy app diff --git a/docs/docs/configuration.mdx b/docs/docs/configuration.mdx new file mode 100644 index 00000000..c7ca9a32 --- /dev/null +++ b/docs/docs/configuration.mdx @@ -0,0 +1,145 @@ +--- +sidebar_position: 5 +--- + +# Configuration + +This guide covers environment variables and configuration options for AppKit applications. + +## App deployment configuration + +### `app.yaml` file + +The `app.yaml` file configures your app's runtime environment in Databricks Apps. + +**Basic example:** + +```yaml +command: + - node + - build/index.mjs +env: + - name: DATABRICKS_WAREHOUSE_ID + valueFrom: sql-warehouse +``` + +### Command specification + +Specify how to start your app in the `command` field: + +```yaml +command: + - node + - build/index.mjs +``` + +This runs the production build of your AppKit server (created by `npm run build`). + +### Binding a SQL warehouse + +To use the analytics plugin, bind a SQL warehouse in your `app.yaml`: + +```yaml +env: + - name: DATABRICKS_WAREHOUSE_ID + valueFrom: sql-warehouse +``` + +This makes the warehouse ID available to your app at runtime. The `valueFrom: sql-warehouse` directive tells Databricks Apps to inject the configured warehouse ID. + +For advanced configuration options (authorization, networking, resource limits), see the [Databricks Apps Configuration](https://docs.databricks.com/aws/en/dev-tools/databricks-apps/configuration) documentation. + +## Environment variables + +### Required for Databricks Apps deployment + +These are typically **provided by Databricks Apps runtime** (exact set can vary by platform/version): + +| Variable | Description | +|----------|-------------| +| `DATABRICKS_HOST` | Workspace URL (e.g. `https://xxx.cloud.databricks.com`) | +| `DATABRICKS_APP_PORT` | Port to bind (default: `8000`) | +| `DATABRICKS_APP_NAME` | App name in Databricks | + +### Required for SQL queries (analytics plugin) + +| Variable | Description | How to Set | +|----------|-------------|------------| +| `DATABRICKS_WAREHOUSE_ID` | SQL warehouse ID | In `app.yaml`: `valueFrom: sql-warehouse` | + +See the [App deployment configuration](#app-deployment-configuration) section above for details on how to bind this variable. + +### Optional variables + +| Variable | Description | Default | +|----------|-------------|---------| +| `DATABRICKS_WORKSPACE_ID` | Workspace ID | Auto-fetched from API | +| `NODE_ENV` | `"development"` or `"production"` | — | +| `FLASK_RUN_HOST` | Host to bind | `0.0.0.0` | + +### Telemetry (optional) + +| Variable | Description | +|----------|-------------| +| `OTEL_EXPORTER_OTLP_ENDPOINT` | OpenTelemetry collector endpoint | +| `OTEL_SERVICE_NAME` | Service name for traces | + +## Local development authentication + +For local development, you need to authenticate with Databricks. Choose one of the following options: + +### Option 1: Databricks CLI authentication (recommended) + +Configure authentication once using the Databricks CLI: + +```bash +databricks auth login --host [host] --profile [profile-name] +``` + +If you use `DEFAULT` as the profile name, you can run your dev server directly: + +```bash +npm run dev +``` + +To run with a specific profile, set the `DATABRICKS_CONFIG_PROFILE` environment variable: + +```bash +DATABRICKS_CONFIG_PROFILE=my-profile npm run dev +``` + +Note: Some Databricks SDK versions use `DATABRICKS_PROFILE` instead of `DATABRICKS_CONFIG_PROFILE`. + +### Option 2: Environment variables + +```bash +export DATABRICKS_HOST="https://xxx.cloud.databricks.com" +export DATABRICKS_TOKEN="dapi..." +export DATABRICKS_WAREHOUSE_ID="abc123..." +npm run dev +``` + +### Option 3: `.env` file (auto-loaded by AppKit) + +Create a `.env` file in your project root (add to `.gitignore`!): + +```bash +DATABRICKS_HOST=https://xxx.cloud.databricks.com +DATABRICKS_TOKEN=dapi... +DATABRICKS_WAREHOUSE_ID=abc123... +``` + +Then run: + +```bash +npm run dev +``` + +## Advanced configuration + +For advanced Databricks Apps configuration (authorization, networking, resource limits), refer to the [Databricks Apps Configuration](https://docs.databricks.com/aws/en/dev-tools/databricks-apps/configuration) documentation. + +## See also + +- [App management](./app-management.mdx) - Deploying and managing apps +- [Plugins](./plugins.md) - Plugin configuration options diff --git a/docs/docs/development/_category_.json b/docs/docs/development/_category_.json new file mode 100644 index 00000000..a127caf5 --- /dev/null +++ b/docs/docs/development/_category_.json @@ -0,0 +1,11 @@ +{ + "label": "Development", + "position": 7, + "collapsible": true, + "collapsed": false, + "link": { + "type": "generated-index", + "title": "Development", + "description": "Guides for developing AppKit applications" + } +} diff --git a/docs/docs/development/llm-guide.mdx b/docs/docs/development/llm-guide.mdx new file mode 100644 index 00000000..6df10b17 --- /dev/null +++ b/docs/docs/development/llm-guide.mdx @@ -0,0 +1,82 @@ +--- +sidebar_position: 8 +--- + +# LLM Guide + +import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; + +export function LlmsTxtLink({ children = '`llms.txt`' }) { + const { siteConfig } = useDocusaurusContext(); + const llmsTxtUrl = `${siteConfig.baseUrl}llms.txt`; + return {children}; +} + +This document provides prescriptive guidance for AI coding assistants generating code with Databricks AppKit. It is intentionally opinionated to ensure consistent, production-ready code generation. + +:::note +This file contains just a subset of the LLM guidance. +To get the complete guidance, see the file for full guidance based on the AppKit documentation. +::: + +## High-level mission + +Build **full-stack TypeScript apps** on Databricks using: + +- **Backend**: `@databricks/appkit` +- **Frontend**: `@databricks/appkit-ui` +- **Analytics**: SQL files in `config/queries/*.sql` executed via the AppKit analytics plugin + +This guide is designed to work even when you *do not* have access to the AppKit source repo. Prefer only public package APIs and portable project structures. + +## Hard rules (LLM guardrails) + +- **Do not invent APIs**. If unsure, stick to the patterns shown in the documentation and only use documented exports from `@databricks/appkit` and `@databricks/appkit-ui`. +- **`createApp()` is async**. Prefer **top-level `await createApp(...)`**. If you can't, use `void createApp(...)` and do not ignore promise rejection. +- **Always memoize query parameters** passed to `useAnalyticsQuery` / charts to avoid refetch loops. +- **Always handle loading/error/empty states** in UI (use `Skeleton`, error text, empty state). +- **Always use `sql.*` helpers** for query parameters (do not pass raw strings/numbers unless the query expects none). +- **Never construct SQL strings dynamically**. Use parameterized queries with `:paramName`. +- **Never use `require()`**. Use ESM `import/export`. + +## TypeScript import rules + +If your `tsconfig.json` uses `"verbatimModuleSyntax": true`, **always use `import type` for type-only imports** (otherwise builds can fail in strict setups): + +```ts +import type { ReactNode } from "react"; +import { useMemo } from "react"; +``` + +## LLM checklist (before finalizing code) + +### Project setup + +- `package.json` has `"type": "module"` +- `tsx` is in devDependencies for dev server +- `dev` script uses `NODE_ENV=development tsx watch server/index.ts` +- `client/index.html` exists with `
` and script pointing to `client/src/main.tsx` + +### Backend + +- `await createApp({ plugins: [...] })` is used (or `void createApp` with intent) +- `server()` is included (always) +- If using SQL: `analytics({})` included + `config/queries/*.sql` present +- Queries use `:param` placeholders, and params are passed from UI using `sql.*` +- If query needs workspace scoping: uses `:workspaceId` + +### Frontend + +- `useMemo` wraps parameters objects +- Loading/error/empty states are explicit +- Charts use `format="auto"` unless you have a reason to force `"json"`/`"arrow"` +- Charts use props (`xKey`, `yKey`, `colors`) NOT children (they're ECharts-based, not Recharts) +- If using tooltips: root is wrapped with `` + +### Never + +- Don't build SQL strings manually +- Don't pass untyped raw params for annotated queries +- Don't ignore `createApp()`'s promise +- Don't invent UI components not listed in the documentation +- Don't pass Recharts children (``, ``, etc.) to AppKit chart components diff --git a/docs/docs/development/project-setup.mdx b/docs/docs/development/project-setup.mdx new file mode 100644 index 00000000..7f271ecb --- /dev/null +++ b/docs/docs/development/project-setup.mdx @@ -0,0 +1,235 @@ +--- +sidebar_position: 4 +--- + +# Project setup + +This guide covers the recommended project structure and scaffolding for AppKit applications. + +## Canonical project layout + +Recommended structure (client/server split): + +``` +my-app/ +├── server/ +│ ├── index.ts # backend entry point (AppKit) +│ └── .env # optional local dev env vars (do not commit) +├── client/ +│ ├── index.html +│ ├── vite.config.ts +│ └── src/ +│ ├── main.tsx +│ └── App.tsx +├── config/ +│ └── queries/ +│ └── my_query.sql +├── app.yaml +├── package.json +└── tsconfig.json +``` + +### Layout rationale + +The AppKit `server()` plugin automatically serves: +- **Dev**: Vite dev server (HMR) from `client/` +- **Prod**: static files from `client/dist` (built by Vite) + +## Project scaffolding + +### `package.json` + +```json +{ + "name": "my-app", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "NODE_ENV=development tsx watch server/index.ts", + "build": "npm run build:server && npm run build:client", + "build:server": "tsdown --out-dir build server/index.ts", + "build:client": "tsc -b && vite build --config client/vite.config.ts", + "start": "node build/index.mjs" + }, + "dependencies": { + "@databricks/appkit": "^0.1.2", + "@databricks/appkit-ui": "^0.1.2", + "react": "^19.2.3", + "react-dom": "^19.2.3" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", + "@vitejs/plugin-react": "^5.1.1", + "tsdown": "^0.15.7", + "tsx": "^4.19.0", + "typescript": "~5.6.0", + "vite": "^7.2.4" + } +} +``` + +### `client/index.html` + +```html + + + + + + My App + + +
+ + + +``` + +### `client/src/main.tsx` + +```tsx +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; +import App from "./App"; + +createRoot(document.getElementById("root")!).render( + + + , +); +``` + +### `client/src/App.tsx` (Minimal) + +```tsx +export default function App() { + return ( +
+

My App

+
+ ); +} +``` + +### `client/vite.config.ts` + +```ts +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [react()], +}); +``` + +### `tsconfig.json` + +```json +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "moduleResolution": "bundler", + "jsx": "react-jsx", + "strict": true, + "skipLibCheck": true, + "noEmit": true, + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true + }, + "include": ["server", "client/src"] +} +``` + +### `server/index.ts` + +```ts +import { createApp, server } from "@databricks/appkit"; + +await createApp({ + plugins: [server()], +}); +``` + +## Running the app + +```bash +# Install dependencies +npm install + +# Development (starts backend + Vite dev server) +npm run dev + +# Production build +npm run build +npm start +``` + +## Integrating into an existing app + +If you already have a React/Vite app and want to add AppKit: + +### 1. Install dependencies + +```bash +npm install @databricks/appkit @databricks/appkit-ui react react-dom +npm install -D tsx tsdown vite @vitejs/plugin-react typescript +``` + +If you don't already have a `client/` folder, create one and move your Vite app into it: +- Move `index.html` → `client/index.html` +- Move `vite.config.ts` → `client/vite.config.ts` +- Move `src/` → `client/src/` + +### 2. Create `server/index.ts` (New File) + +```ts +import { createApp, server } from "@databricks/appkit"; + +await createApp({ + plugins: [server()], +}); +``` + +### 3. Update `package.json` Scripts + +```json +{ + "scripts": { + "dev": "NODE_ENV=development tsx watch server/index.ts", + "build": "npm run build:server && npm run build:client", + "build:server": "tsdown --out-dir build server/index.ts", + "build:client": "tsc -b && vite build --config client/vite.config.ts", + "start": "node build/index.mjs" + } +} +``` + +### 4. Complete setup + +AppKit's server plugin will automatically serve your Vite app in dev mode and `client/dist` in production. If your Vite app must stay at the repo root (no `client/` folder), AppKit can still work, but the recommended layout is `client/` + `server/`. + +## Adding analytics to an existing app + +To add SQL query execution capabilities: + +```ts +// server/index.ts +import { createApp, server, analytics } from "@databricks/appkit"; + +await createApp({ + plugins: [server(), analytics()], +}); +``` + +Then create `config/queries/` and add your `.sql` files. + +## See also + +- [Local development](./local-development.mdx) - Running the dev server +- [Configuration](../configuration.mdx) - Environment variables +- [Plugins](../plugins.md) - Plugin configuration diff --git a/docs/docs/development/type-generation.mdx b/docs/docs/development/type-generation.mdx new file mode 100644 index 00000000..2de17706 --- /dev/null +++ b/docs/docs/development/type-generation.mdx @@ -0,0 +1,108 @@ +--- +sidebar_position: 5 +--- + +# Type generation + +AppKit can automatically generate TypeScript types for your SQL queries, providing end-to-end type safety from database to UI. + +## Goal + +Generate `client/src/appKitTypes.d.ts` so query keys, parameters, and result rows are type-safe. + +## Vite plugin: `appKitTypesPlugin` + +The recommended approach is to use the Vite plugin, which watches your SQL files and regenerates types automatically during development. + +### Configuration + +- `outFile?: string` - Output file path (default: `src/appKitTypes.d.ts`) +- `watchFolders?: string[]` - Folders to watch for SQL files (default: `["../config/queries"]`) + +### Example + +```ts +// client/vite.config.ts +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; +import { appKitTypesPlugin } from "@databricks/appkit"; + +export default defineConfig({ + plugins: [ + react(), + appKitTypesPlugin({ + outFile: "src/appKitTypes.d.ts", + watchFolders: ["../config/queries"], + }), + ], +}); +``` + +### Important nuance + +When the frontend is served through AppKit in dev mode, AppKit's dev server already includes `appKitTypesPlugin()` internally. You still want it in your client build pipeline if you run `vite build` separately. + +## CLI: `appkit-generate-types` + +For manual type generation or CI/CD pipelines, use the CLI command: + +```bash +# Requires DATABRICKS_WAREHOUSE_ID (or pass as 3rd arg) +npx appkit-generate-types [rootDir] [outFile] [warehouseId] +``` + +### Examples + +- Generate types using warehouse ID from environment + + ```bash + npx appkit-generate-types . client/src/appKitTypes.d.ts + ``` + +- Generate types using warehouse ID explicitly + + ```bash + npx appkit-generate-types . client/src/appKitTypes.d.ts abc123... + ``` + +- Force regeneration (skip cache) + + ```bash + npx appkit-generate-types --no-cache + ``` + +## How it works + +The type generator: + +1. Scans your `config/queries/` folder for `.sql` files +2. Parses SQL parameter annotations (e.g., `-- @param startDate DATE`) +3. Connects to your Databricks SQL Warehouse to infer result column types +4. Generates TypeScript interfaces for query parameters and results +5. Creates a `QueryRegistry` type for type-safe query execution + +## Using generated types + +Once types are generated, your IDE will provide autocomplete and type checking: + +```tsx +import { useAnalyticsQuery } from "@databricks/appkit-ui/react"; +import { sql } from "@databricks/appkit-ui/js"; + +// TypeScript knows "users_list" is a valid query key +// and what parameters it expects +const { data } = useAnalyticsQuery("users_list", { + status: sql.string("active"), + limit: sql.number(50), +}); + +// TypeScript knows the shape of the result rows +data?.forEach(row => { + console.log(row.email); // ✓ autocomplete works +}); +``` + +## See also + +- [Plugins](../plugins.md) - Analytics plugin configuration +- [API Reference](/docs/api/appkit-ui) - Complete UI components API documentation diff --git a/docs/docs/plugins.md b/docs/docs/plugins.md index f9159cbd..d93e9208 100644 --- a/docs/docs/plugins.md +++ b/docs/docs/plugins.md @@ -22,6 +22,63 @@ Provides HTTP server capabilities with development and production modes. The Server plugin uses the deferred initialization phase to access routes from other plugins. +#### What it does + +- Starts an Express server (default `host=0.0.0.0`, `port=8000`) +- Mounts plugin routes under `/api//...` +- Adds `/health` endpoint (returns `{ status: "ok" }`) +- Serves frontend: + - **Development** (`NODE_ENV=development`): runs a Vite dev server in middleware mode + - **Production**: auto-detects static frontend directory (checks `dist`, `client/dist`, `build`, `public`, `out`) + +#### Minimal server example + +The smallest valid AppKit server: + +```ts +// server/index.ts +import { createApp, server } from "@databricks/appkit"; + +await createApp({ + plugins: [server()], +}); +``` + +#### Manual server start example + +When you need to extend Express with custom routes: + +```ts +import { createApp, server } from "@databricks/appkit"; + +const appkit = await createApp({ + plugins: [server({ autoStart: false })], +}); + +appkit.server.extend((app) => { + app.get("/custom", (_req, res) => res.json({ ok: true })); +}); + +await appkit.server.start(); +``` + +#### Configuration options + +```ts +import { createApp, server } from "@databricks/appkit"; + +await createApp({ + plugins: [ + server({ + port: 8000, // default: Number(process.env.DATABRICKS_APP_PORT) || 8000 + host: "0.0.0.0", // default: process.env.FLASK_RUN_HOST || "0.0.0.0" + autoStart: true, // default: true + staticPath: "dist", // optional: force a specific static directory + }), + ], +}); +``` + ### Analytics plugin Enables SQL query execution against Databricks SQL Warehouses. @@ -33,7 +90,104 @@ Enables SQL query execution against Databricks SQL Warehouses. - Built-in caching and retry logic - Server-Sent Events (SSE) streaming -Store SQL queries in `config/queries/` directory and use parameterized queries with the [`sql`](api/appkit/Variable.sql.md) helper for type safety. +#### Basic usage + +```ts +import { analytics, createApp, server } from "@databricks/appkit"; + +await createApp({ + plugins: [server(), analytics({})], +}); +``` + +#### Where queries live + +- Put `.sql` files in `config/queries/` +- Query key is the filename without `.sql` (e.g. `spend_summary.sql` → `"spend_summary"`) + +#### SQL parameters + +Use `:paramName` placeholders and optionally annotate parameter types using SQL comments: + +```sql +-- @param startDate DATE +-- @param endDate DATE +-- @param limit NUMERIC +SELECT ... +WHERE usage_date BETWEEN :startDate AND :endDate +LIMIT :limit +``` + +**Supported `-- @param` types** (case-insensitive): +- `STRING`, `NUMERIC`, `BOOLEAN`, `DATE`, `TIMESTAMP`, `BINARY` + +#### Server-injected parameters + +`:workspaceId` is **injected by the server** and **must not** be annotated: + +```sql +WHERE workspace_id = :workspaceId +``` + +#### HTTP endpoints + +The analytics plugin exposes these endpoints (mounted under `/api/analytics`): + +- `POST /api/analytics/query/:query_key` +- `POST /api/analytics/users/me/query/:query_key` +- `GET /api/analytics/arrow-result/:jobId` +- `GET /api/analytics/users/me/arrow-result/:jobId` + +#### Format options + +- `format: "JSON"` (default) returns JSON rows +- `format: "ARROW"` returns an Arrow "statement_id" payload over SSE, then the client fetches binary Arrow from `/api/analytics/arrow-result/:jobId` + +### Execution context and `asUser(req)` + +AppKit manages Databricks authentication via two contexts: + +- **ServiceContext** (singleton): Initialized at app startup with service principal credentials +- **ExecutionContext**: Determined at runtime - either service principal or user context + +#### Headers for user context + +- `x-forwarded-user`: required in production; identifies the user +- `x-forwarded-access-token`: required for user token passthrough + +#### Using `asUser(req)` for user-scoped operations + +The `asUser(req)` pattern allows plugins to execute operations using the requesting user's credentials: + +```ts +// In a custom plugin route handler +router.post("/users/me/data", async (req, res) => { + // Execute as the user (uses their Databricks permissions) + const result = await this.asUser(req).query("SELECT ..."); + res.json(result); +}); + +// Service principal execution (default) +router.post("/system/data", async (req, res) => { + const result = await this.query("SELECT ..."); + res.json(result); +}); +``` + +#### Context helper functions + +Exported from `@databricks/appkit`: + +- `getExecutionContext()`: Returns current context (user or service) +- `getCurrentUserId()`: Returns user ID in user context, service user ID otherwise +- `getWorkspaceClient()`: Returns the appropriate WorkspaceClient for current context +- `getWarehouseId()`: `Promise` (from `DATABRICKS_WAREHOUSE_ID` or auto-selected in dev) +- `getWorkspaceId()`: `Promise` (from `DATABRICKS_WORKSPACE_ID` or fetched) +- `isInUserContext()`: Returns `true` if currently executing in user context + +#### Development mode behavior + +In local development (`NODE_ENV=development`), if `asUser(req)` is called without a user token, it logs a warning and falls back to the service principal. ## Using plugins @@ -54,35 +208,40 @@ For complete configuration options, see [`createApp`](api/appkit/Function.create ## Creating custom plugins -Extend the [`Plugin`](api/appkit/Class.Plugin.md) class and export with `toPlugin()`: +If you need custom API routes or background logic, implement an AppKit plugin. -```typescript -import { Plugin, toPlugin } from "@databricks/app-kit"; +### Basic plugin example -interface MyPluginConfig { - apiKey?: string; -} +Extend the [`Plugin`](api/appkit/Class.Plugin.md) class and export with `toPlugin()`: -export class MyPlugin extends Plugin { - name = "myPlugin"; - envVars = ["MY_API_KEY"]; +```typescript +import { Plugin, toPlugin } from "@databricks/appkit"; +import type express from "express"; - async setup() { - // Initialize your plugin - } +class MyPlugin extends Plugin { + name = "my-plugin"; + envVars = []; // list required env vars here - async shutdown() { - // Clean up resources + injectRoutes(router: express.Router) { + this.route(router, { + name: "hello", + method: "get", + path: "/hello", + handler: async (_req, res) => { + res.json({ ok: true }); + }, + }); } } -export const myPlugin = toPlugin( +export const myPlugin = toPlugin, "my-plugin">( MyPlugin, - "myPlugin" + "my-plugin", ); ``` -**Key extension points:** +### Key extension points + - **Route injection**: Implement `injectRoutes()` to add custom endpoints using [`IAppRouter`](api/appkit/TypeAlias.IAppRouter.md) - **Lifecycle hooks**: Override `setup()`, `shutdown()`, and `validateEnv()` methods - **Shared services**: @@ -92,6 +251,38 @@ export const myPlugin = toPlugin( See the [`Plugin`](api/appkit/Class.Plugin.md) API reference for complete documentation. +## Caching + +AppKit provides both global and plugin-level caching capabilities. + +### Global cache configuration + +```ts +await createApp({ + plugins: [server(), analytics({})], + cache: { + enabled: true, + ttl: 3600, // seconds + strictPersistence: false, + }, +}); +``` + +Storage auto-selects **Lakebase persistent cache when healthy**, otherwise falls back to in-memory. + +### Plugin-level caching + +Inside a Plugin subclass: + +```ts +const value = await this.cache.getOrExecute( + ["my-plugin", "data", userId], + async () => expensiveWork(), + userKey, + { ttl: 300 }, +); +``` + ## Plugin phases Plugins initialize in three phases: diff --git a/docs/docusaurus.config.ts b/docs/docusaurus.config.ts index 0e0e7994..cc93a3ab 100644 --- a/docs/docusaurus.config.ts +++ b/docs/docusaurus.config.ts @@ -3,6 +3,7 @@ import path from "node:path"; import type { Config } from "@docusaurus/types"; import type * as Preset from "@docusaurus/preset-classic"; import webpack from "webpack"; +import type { PluginOptions } from "@signalwire/docusaurus-plugin-llms-txt/public"; function appKitAliasPlugin() { return { @@ -132,6 +133,35 @@ const config: Config = { }, ], appKitAliasPlugin, + [ + "@signalwire/docusaurus-plugin-llms-txt", + // docs: https://github.com/signalwire/docusaurus-plugins/blob/main/packages/docusaurus-plugin-llms-txt/README.md + { + id: "appkit", + markdown: { + enableFiles: true, + relativePaths: true, + includeDocs: true, + includeVersionedDocs: false, + includeBlog: false, + includePages: false, + includeGeneratedIndex: true, + }, + llmsTxt: { + siteTitle: "AppKit", + siteDescription: + "Node.js + React SDK for Databricks Apps. Built for humans and AI.", + enableLlmsFullTxt: true, + }, + ui: { + copyPageContent: { + display: { + docs: true, + }, + }, + }, + } satisfies PluginOptions, + ], ], themeConfig: { diff --git a/docs/package.json b/docs/package.json index 9bdca8f3..658df190 100644 --- a/docs/package.json +++ b/docs/package.json @@ -24,6 +24,7 @@ "@docusaurus/preset-classic": "3.9.2", "@docusaurus/theme-mermaid": "^3.9.2", "@mdx-js/react": "^3.0.0", + "@signalwire/docusaurus-plugin-llms-txt": "2.0.0-alpha.7", "@tailwindcss/postcss": "^4.1.18", "clsx": "^2.0.0", "docusaurus-lunr-search": "^3.6.0", diff --git a/docs/static/appkit-ui/styles.gen.css b/docs/static/appkit-ui/styles.gen.css index 336bd67e..e497c06a 100644 --- a/docs/static/appkit-ui/styles.gen.css +++ b/docs/static/appkit-ui/styles.gen.css @@ -24,6 +24,8 @@ --text-base--line-height: calc(1.5 / 1); --text-lg: 1.125rem; --text-lg--line-height: calc(1.75 / 1.125); + --text-2xl: 1.5rem; + --text-2xl--line-height: calc(2 / 1.5); --text-4xl: 2.25rem; --text-4xl--line-height: calc(2.5 / 2.25); --text-7xl: 4.5rem; @@ -1455,6 +1457,10 @@ .font-sans { font-family: var(--font-sans); } + .text-2xl { + font-size: var(--text-2xl); + line-height: var(--tw-leading, var(--text-2xl--line-height)); + } .text-4xl { font-size: var(--text-4xl); line-height: var(--tw-leading, var(--text-4xl--line-height)); @@ -1653,6 +1659,10 @@ --tw-shadow: 0 1px 2px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.05)); box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); } + .ring { + --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } .ring-0 { --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor); box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); diff --git a/llms.txt b/llms.txt deleted file mode 100644 index b4f576d1..00000000 --- a/llms.txt +++ /dev/null @@ -1,1234 +0,0 @@ -# llms.txt — LLM Guide for Building Great Databricks Apps with AppKit -Project: Databricks AppKit - -This document is written *for LLMs* generating code in a brand-new project folder that installs AppKit from npm. It is intentionally prescriptive. - -## High-level mission - -Build **full-stack TypeScript apps** on Databricks using: - -- **Backend**: `@databricks/appkit` -- **Frontend**: `@databricks/appkit-ui` -- **Analytics**: SQL files in `config/queries/*.sql` executed via the AppKit analytics plugin - -This file is designed to work even when you *do not* have access to the AppKit source repo. Prefer only public package APIs and portable project structures. - -## Hard rules (LLM guardrails) - -- **Do not invent APIs**. If unsure, stick to the patterns shown in this file and only documented exports from `@databricks/appkit` and `@databricks/appkit-ui`. -- **`createApp()` is async**. Prefer **top-level `await createApp(...)`**. If you can’t, use `void createApp(...)` and do not ignore promise rejection. -- **Always memoize query parameters** passed to `useAnalyticsQuery` / charts to avoid refetch loops. -- **Always handle loading/error/empty states** in UI (use `Skeleton`, error text, empty state). -- **Always use `sql.*` helpers** for query parameters (do not pass raw strings/numbers unless the query expects none). -- **Never construct SQL strings dynamically**. Use parameterized queries with `:paramName`. -- **Never use `require()`**. Use ESM `import/export`. - -## TypeScript import rules (when using `verbatimModuleSyntax`) - -If your `tsconfig.json` uses `"verbatimModuleSyntax": true`, **always use `import type` for type-only imports** (otherwise builds can fail in strict setups): - -```ts -import type { ReactNode } from "react"; -import { useMemo } from "react"; -``` - -## Canonical project layout - -Recommended structure (client/server split): - -``` -my-app/ -├── server/ -│ ├── index.ts # backend entry point (AppKit) -│ └── .env # optional local dev env vars (do not commit) -├── client/ -│ ├── index.html -│ ├── vite.config.ts -│ └── src/ -│ ├── main.tsx -│ └── App.tsx -├── config/ -│ └── queries/ -│ └── my_query.sql -├── app.yaml -├── package.json -└── tsconfig.json -``` - -Why this layout: - -- The AppKit `server()` plugin automatically serves: - - **Dev**: Vite dev server (HMR) from `client/` - - **Prod**: static files from `client/dist` (built by Vite) - -## Project scaffolding (start here) - -### `package.json` - -```json -{ - "name": "my-app", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "NODE_ENV=development tsx watch server/index.ts", - "build": "npm run build:server && npm run build:client", - "build:server": "tsdown --out-dir build server/index.ts", - "build:client": "tsc -b && vite build --config client/vite.config.ts", - "start": "node build/index.mjs" - }, - "dependencies": { - "@databricks/appkit": "^0.1.2" - "@databricks/appkit-ui": "^0.1.2", - "react": "^19.2.3", - "react-dom": "^19.2.3" - }, - "devDependencies": { - "@types/node": "^20.0.0", - "@types/react": "^19.0.0", - "@types/react-dom": "^19.0.0", - "@vitejs/plugin-react": "^5.1.1", - "tsdown": "^0.15.7", - "tsx": "^4.19.0", - "typescript": "~5.6.0", - "vite": "^7.2.4" - } -} -``` - -### `client/index.html` - -```html - - - - - - My App - - -
- - - -``` - -### `client/src/main.tsx` - -```tsx -import { StrictMode } from "react"; -import { createRoot } from "react-dom/client"; -import App from "./App"; - -createRoot(document.getElementById("root")!).render( - - - , -); -``` - -### `client/src/App.tsx` (minimal) - -```tsx -export default function App() { - return ( -
-

My App

-
- ); -} -``` - -### `client/vite.config.ts` - -```ts -import { defineConfig } from "vite"; -import react from "@vitejs/plugin-react"; - -export default defineConfig({ - plugins: [react()], -}); -``` - -### `tsconfig.json` - -```json -{ - "compilerOptions": { - "target": "ES2022", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "moduleResolution": "bundler", - "jsx": "react-jsx", - "strict": true, - "skipLibCheck": true, - "noEmit": true, - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true - }, - "include": ["server", "client/src"] -} -``` - -### `server/index.ts` - -```ts -import { createApp, server } from "@databricks/appkit"; - -await createApp({ - plugins: [server()], -}); -``` - -### Running the app - -```bash -# Install dependencies -npm install - -# Development (starts backend + Vite dev server) -npm run dev - -# Production build -npm run build -npm start -``` - -## Integrating into an existing app - -If you already have a React/Vite app and want to add AppKit: - -### 1. Install dependencies - -```bash -npm install @databricks/appkit @databricks/appkit-ui react react-dom -npm install -D tsx tsdown vite @vitejs/plugin-react typescript - -# If you don't already have a client/ folder, create one and move your Vite app into it: -# - move index.html -> client/index.html -# - move vite.config.ts -> client/vite.config.ts -# - move src/ -> client/src/ -# -``` - -### 2. Create `server/index.ts` (new file) - -```ts -import { createApp, server } from "@databricks/appkit"; - -await createApp({ - plugins: [server()], -}); -``` - -### 3. Update `package.json` scripts - -```json -{ - "scripts": { - "dev": "NODE_ENV=development tsx watch server/index.ts", - "build": "npm run build:server && npm run build:client", - "build:server": "tsdown --out-dir build server/index.ts", - "build:client": "tsc -b && vite build --config client/vite.config.ts", - "start": "node build/index.mjs" - } -} -``` - -### 4. That's it - -- AppKit's server plugin will automatically serve your Vite app in dev mode and `client/dist` in production. -- If your Vite app must stay at the repo root (no `client/` folder), AppKit can still work, but the recommended layout is `client/` + `server/`. - -### Adding analytics to an existing app - -```ts -// server/index.ts -import { createApp, server, analytics } from "@databricks/appkit"; - -await createApp({ - plugins: [server(), analytics()], -}); -``` - -Then create `config/queries/` and add your `.sql` files. - -## Environment variables - -### Required for Databricks Apps deployment - -These are typically **provided by Databricks Apps runtime** (exact set can vary by platform/version): - -| Variable | Description | -|----------|-------------| -| `DATABRICKS_HOST` | Workspace URL (e.g. `https://xxx.cloud.databricks.com`) | -| `DATABRICKS_APP_PORT` | Port to bind (default: `8000`) | -| `DATABRICKS_APP_NAME` | App name in Databricks | - -### Required for SQL queries (analytics plugin) - -| Variable | Description | How to set | -|----------|-------------|------------| -| `DATABRICKS_WAREHOUSE_ID` | SQL warehouse ID | In `app.yaml`: `valueFrom: sql-warehouse` | - -### Optional - -| Variable | Description | Default | -|----------|-------------|---------| -| `DATABRICKS_WORKSPACE_ID` | Workspace ID | Auto-fetched from API | -| `NODE_ENV` | `"development"` or `"production"` | — | -| `FLASK_RUN_HOST` | Host to bind | `0.0.0.0` | - -### Local development - -For local development, you need to authenticate with Databricks. Options: - -**Option 1: Databricks CLI Auth (recommended)** - -```bash -# Configure once -databricks auth login --host [host] --profile [profile-name] - -# If you used `DEFAULT` as the profile name then you can just run - -`npm run dev` - -# To run with a specific profile -DATABRICKS_CONFIG_PROFILE=my-profile npm run dev -# If your Databricks SDK expects a different variable name, try: -# DATABRICKS_PROFILE=my-profile npm run dev -``` - -**Option 2: Environment variables** - -```bash -export DATABRICKS_HOST="https://xxx.cloud.databricks.com" -export DATABRICKS_TOKEN="dapi..." -export DATABRICKS_WAREHOUSE_ID="abc123..." -npm run dev -``` - -**Option 3: `.env` file (auto-loaded by AppKit)** - -```bash -# .env (add to .gitignore!) -DATABRICKS_HOST=https://xxx.cloud.databricks.com -DATABRICKS_TOKEN=dapi... -DATABRICKS_WAREHOUSE_ID=abc123... -``` - -### Telemetry (optional) - -| Variable | Description | -|----------|-------------| -| `OTEL_EXPORTER_OTLP_ENDPOINT` | OpenTelemetry collector endpoint | -| `OTEL_SERVICE_NAME` | Service name for traces | - -## Backend: `@databricks/appkit` - -### Minimal server (golden template) - -The smallest valid AppKit server: - -```ts -// server/index.ts -import { createApp, server } from "@databricks/appkit"; - -await createApp({ - plugins: [server()], -}); -``` - -### Server plugin (`server()`) - -What it does: - -- Starts an Express server (default `host=0.0.0.0`, `port=8000`) -- Mounts plugin routes under `/api//...` -- Adds `/health` (returns `{ status: "ok" }`) -- Serves frontend: - - **Development** (`NODE_ENV=development`): runs a Vite dev server in middleware mode - - **Production**: auto-detects static frontend directory (checks `dist`, `client/dist`, `build`, `public`, `out`) - -Config (real options): - -```ts -import { createApp, server } from "@databricks/appkit"; - -await createApp({ - plugins: [ - server({ - port: 8000, // default: Number(process.env.DATABRICKS_APP_PORT) || 8000 - host: "0.0.0.0", // default: process.env.FLASK_RUN_HOST || "0.0.0.0" - autoStart: true, // default: true - staticPath: "dist", // optional: force a specific static directory - }), - ], -}); -``` - -Manual server start (when you need to `.extend()` Express): - -```ts -import { createApp, server } from "@databricks/appkit"; - -const appkit = await createApp({ - plugins: [server({ autoStart: false })], -}); - -appkit.server.extend((app) => { - app.get("/custom", (_req, res) => res.json({ ok: true })); -}); - -await appkit.server.start(); -``` - -### Analytics plugin (`analytics()`) - -Add SQL query execution backed by Databricks SQL Warehouses. - -```ts -import { analytics, createApp, server } from "@databricks/appkit"; - -await createApp({ - plugins: [server(), analytics({})], -}); -``` - -Where queries live: - -- Put `.sql` files in `config/queries/`. -- Query key is the filename without `.sql` (e.g. `spend_summary.sql` → `"spend_summary"`). - -SQL parameters: - -- Use `:paramName` placeholders. -- Optionally annotate parameter types using SQL comments: - -```sql --- @param startDate DATE --- @param endDate DATE --- @param limit NUMERIC -SELECT ... -WHERE usage_date BETWEEN :startDate AND :endDate -LIMIT :limit -``` - -Supported `-- @param` types (case-insensitive): - -- `STRING`, `NUMERIC`, `BOOLEAN`, `DATE`, `TIMESTAMP`, `BINARY` - -Server-injected params (important): - -- `:workspaceId` is **injected by the server** and **must not** be annotated. -- Example: - -```sql -WHERE workspace_id = :workspaceId -``` - -HTTP endpoints exposed (mounted under `/api/analytics`): - -- `POST /api/analytics/query/:query_key` -- `GET /api/analytics/arrow-result/:jobId` - -**Query file naming convention determines execution context:** - -- `config/queries/.sql` - Executes as service principal (shared cache) -- `config/queries/.obo.sql` - Executes as user (OBO = On-Behalf-Of, per-user cache) - -Formats: - -- `format: "JSON"` (default) returns JSON rows -- `format: "ARROW"` returns an Arrow “statement_id” payload over SSE, then the client fetches binary Arrow from `/api/analytics/arrow-result/:jobId` - -### Execution context and `asUser(req)` - -AppKit manages Databricks authentication via two contexts: - -- **ServiceContext** (singleton): Initialized at app startup with service principal credentials -- **ExecutionContext**: Determined at runtime - either service principal or user context - -**Headers used for user context:** - -- `x-forwarded-user`: required in production; identifies the user -- `x-forwarded-access-token`: required for user token passthrough - -**Using `asUser(req)` for user-scoped operations:** - -The `asUser(req)` pattern allows plugins to execute operations using the requesting user's credentials: - -```ts -// In a custom plugin route handler -router.post("/users/me/data", async (req, res) => { - // Execute as the user (uses their Databricks permissions) - const result = await this.asUser(req).query("SELECT ..."); - res.json(result); -}); - -// Service principal execution (default) -router.post("/system/data", async (req, res) => { - const result = await this.query("SELECT ..."); - res.json(result); -}); -``` - -**Context helper functions (exported from `@databricks/appkit`):** - -- `getExecutionContext()`: Returns current context (user or service) -- `getCurrentUserId()`: Returns user ID in user context, service user ID otherwise -- `getWorkspaceClient()`: Returns the appropriate WorkspaceClient for current context -- `getWarehouseId()`: `Promise` (from `DATABRICKS_WAREHOUSE_ID` or auto-selected in dev) -- `getWorkspaceId()`: `Promise` (from `DATABRICKS_WORKSPACE_ID` or fetched) -- `isInUserContext()`: Returns `true` if currently executing in user context - -**Development mode behavior:** - -In local development (`NODE_ENV=development`), if `asUser(req)` is called without a user token, it logs a warning and falls back to the service principal. - -### Custom plugins (backend) - -If you need custom API routes or background logic, implement an AppKit plugin. - -```ts -import { Plugin, toPlugin } from "@databricks/appkit"; -import type express from "express"; - -class MyPlugin extends Plugin { - name = "my-plugin"; - envVars = []; // list required env vars here - - injectRoutes(router: express.Router) { - this.route(router, { - name: "hello", - method: "get", - path: "/hello", - handler: async (_req, res) => { - res.json({ ok: true }); - }, - }); - } -} - -export const myPlugin = toPlugin, "my-plugin">( - MyPlugin, - "my-plugin", -); -``` - -### Caching (global + plugin-level) - -Global: - -```ts -await createApp({ - plugins: [server(), analytics({})], - cache: { - enabled: true, - ttl: 3600, // seconds - strictPersistence: false, - }, -}); -``` - -- Storage auto-selects **Lakebase persistent cache when healthy**, otherwise falls back to in-memory. - -Plugin-level: - -```ts -// inside a Plugin subclass: -const value = await this.cache.getOrExecute( - ["my-plugin", "data", userId], - async () => expensiveWork(), - userKey, - { ttl: 300 }, -); -``` - -## Frontend: `@databricks/appkit-ui` - -### Imports - -- React-facing APIs: `@databricks/appkit-ui/react` -- Non-React utilities (sql markers, arrow, SSE): `@databricks/appkit-ui/js` - -```tsx -import { useAnalyticsQuery, Card, Skeleton } from "@databricks/appkit-ui/react"; -import { sql } from "@databricks/appkit-ui/js"; -``` - -### `useAnalyticsQuery(queryKey, parameters, options?)` - -Facts: - -- Uses **SSE** under the hood (not `fetch()` polling). -- By default it hits `POST /api/analytics/query/:queryKey`. -- Returns `{ data, loading, error }` where `data` is `null` until loaded. -- `format` is `"JSON"` or `"ARROW"` (uppercase). - -When to use it: - -- Use `useAnalyticsQuery` **only** when you need a custom UI (cards/KPIs/forms/conditional rendering). -- If you just need a standard chart or table, prefer the built-in components (`BarChart`, `LineChart`, `DataTable`, etc.) so you don’t re-implement loading/error/empty states. - -Limitations (common LLM pitfall): - -- There is **no `enabled` option**. Use conditional rendering to mount/unmount the component. -- There is **no `refetch()`**. Change `parameters` (memoized) or re-mount to re-run the query. - -Recommended usage pattern (memoized params + explicit states): - -```tsx -import { useMemo } from "react"; -import { useAnalyticsQuery, Skeleton } from "@databricks/appkit-ui/react"; -import { sql } from "@databricks/appkit-ui/js"; - -export function Users() { - const params = useMemo( - () => ({ - status: sql.string("active"), - limit: sql.number(50), - }), - [], - ); - - const { data, loading, error } = useAnalyticsQuery("users_list", params); - - if (loading) return ; - if (error) return
Error: {error}
; - if (!data || data.length === 0) return
No results
; - - return
{JSON.stringify(data[0], null, 2)}
; -} -``` - -Options: - -- `format?: "JSON" | "ARROW"` (default `"JSON"`) -- `autoStart?: boolean` (default `true`) -- `maxParametersSize?: number` (default `100 * 1024` bytes) - -### `useChartData({ queryKey, parameters, format, transformer })` - -- `format` here is **lowercase**: `"json" | "arrow" | "auto"` (default `"auto"`) -- Auto-selection heuristics: - - If `parameters._preferArrow === true` → Arrow - - If `parameters._preferJson === true` → JSON - - If `parameters.limit` is a number > 500 → Arrow - - If `parameters.startDate` and `parameters.endDate` exist → Arrow - -### Charts (unified query/data API) - -All charts support: - -- **Query mode**: `queryKey` + `parameters` -- **Data mode**: `data` (inline JSON, no server) - -Available chart components: - -- `BarChart`, `LineChart`, `AreaChart`, `PieChart`, `DonutChart`, `HeatmapChart`, `ScatterChart`, `RadarChart` - -Avoid double-fetching: - -```tsx -// ❌ Wrong: fetches the same query twice -// const { data } = useAnalyticsQuery("spend_data", params); -// return ; - -// ✅ Correct: let the chart fetch -return ; -``` - -Query mode (recommended for Databricks-backed analytics): - -```tsx -import { LineChart } from "@databricks/appkit-ui/react"; -import { sql } from "@databricks/appkit-ui/js"; -import { useMemo } from "react"; - -export function SpendChart() { - const params = useMemo( - () => ({ - startDate: sql.date("2024-01-01"), - endDate: sql.date("2024-12-31"), - aggregationLevel: sql.string("day"), - }), - [], - ); - - return ( - - ); -} -``` - -**Chart props reference (important):** - -Charts are **self-contained ECharts components**. Configure via props, NOT children: - -```tsx -// ✅ Correct: use props for customization - - - -``` - -**❌ CRITICAL: Charts do NOT accept Recharts children** - -```tsx -// ❌ WRONG - AppKit charts are NOT Recharts wrappers -import { BarChart } from "@databricks/appkit-ui/react"; -import { Bar, XAxis, YAxis, CartesianGrid } from "recharts"; - - - // ❌ This will cause TypeScript errors - // ❌ Not supported - // ❌ Not supported - - -// ✅ CORRECT - use props instead - -``` - -### SQL helpers (`sql.*`) - -Use these to build typed parameters (they return marker objects: `{ __sql_type, value }`): - -- `sql.string(value)` → STRING (accepts string|number|boolean) -- `sql.number(value)` → NUMERIC (accepts number|string) -- `sql.boolean(value)` → BOOLEAN (accepts boolean|string("true"/"false")|number(1/0)) -- `sql.date(value)` → DATE (accepts Date or `"YYYY-MM-DD"`) -- `sql.timestamp(value)` → TIMESTAMP (accepts Date, ISO string, or unix time) - -Binary parameters (important): - -- Databricks SQL Warehouse doesn't support `BINARY` as a parameter type. -- `sql.binary(value)` returns a **STRING marker containing hex**, so use `UNHEX(:param)` in SQL. -- `sql.binary` accepts `Uint8Array`, `ArrayBuffer`, or a hex string. - -### SQL result types (important) - -Databricks SQL JSON results can return some numeric-like fields (especially `DECIMAL`) as strings. If a field behaves like a string at runtime, convert explicitly: - -```ts -const value = Number(row.amount); -``` - -If you need more reliable numeric fidelity for large datasets, prefer `format: "ARROW"` and process Arrow on the client. - -### `connectSSE` (custom SSE connections) - -For custom streaming endpoints (not analytics), use the `connectSSE` utility: - -```tsx -import { connectSSE } from "@databricks/appkit-ui/js"; -import { useEffect, useState } from "react"; - -function useCustomStream(endpoint: string) { - const [messages, setMessages] = useState([]); - const [connected, setConnected] = useState(false); - - useEffect(() => { - const controller = new AbortController(); - - connectSSE({ - url: endpoint, - payload: { key: "value" }, // optional: makes it a POST - onMessage: async ({ data }) => { - setConnected(true); - setMessages((prev) => [...prev, data]); - }, - onError: (error) => { - console.error("SSE error:", error); - setConnected(false); - }, - signal: controller.signal, - maxRetries: 3, // default: 3 - retryDelay: 2000, // default: 2000ms (exponential backoff) - timeout: 300000, // default: 5 minutes - maxBufferSize: 1048576, // default: 1MB - }); - - return () => controller.abort(); - }, [endpoint]); - - return { messages, connected }; -} -``` - -Options: - -- `url`: SSE endpoint URL (required) -- `payload`: Optional request body (if provided, uses POST; otherwise GET) -- `onMessage({ id, data })`: Called for each SSE message -- `onError(error)`: Called on connection errors -- `signal`: AbortSignal to cancel the connection -- `lastEventId`: Resume from a specific event ID -- `maxRetries`: Max retry attempts (default: 3) -- `retryDelay`: Base delay between retries in ms (default: 2000) -- `timeout`: Connection timeout in ms (default: 300000) -- `maxBufferSize`: Max buffer size in bytes (default: 1MB) - -### `ArrowClient` (advanced Arrow processing) - -For low-level Arrow data handling: - -```tsx -import { ArrowClient } from "@databricks/appkit-ui/js"; - -// Process Arrow buffer -const table = await ArrowClient.processArrowBuffer(buffer); - -// Fetch and process Arrow data in one call -const table = await ArrowClient.fetchAndProcessArrow(url, headers); - -// Extract fields from table -const fields = ArrowClient.extractArrowFields(table); -// → [{ name: "date", type: ... }, { name: "value", type: ... }] - -// Extract columns as arrays -const columns = ArrowClient.extractArrowColumns(table); -// → { date: [...], value: [...] } - -// Extract chart data -const { xData, yDataMap } = ArrowClient.extractChartData(table, "date", ["value", "count"]); -// → { xData: [...], yDataMap: { value: [...], count: [...] } } - -// Auto-detect chart fields from Arrow table -const detected = ArrowClient.detectFieldsFromArrow(table); -// → { xField: "date", yFields: ["value"], chartType: "timeseries" } -``` - -### DataTable - -`DataTable` is a production-ready table integrated with `useAnalyticsQuery`. - -Key behaviors: - -- `parameters` is required (use `{}` if none) -- Supports opinionated mode (auto columns) and full-control mode (`children(table)`) - -```tsx -import { DataTable } from "@databricks/appkit-ui/react"; - -export function UsersTable() { - return ( - - ); -} -``` - -### UI components (primitives) - -AppKit-UI ships shadcn-style primitives. Import from `@databricks/appkit-ui/react`. - -Note: Exact exports can vary by AppKit-UI version. Prefer using IDE auto-import/autocomplete to confirm what your installed version exports. - -Radix constraint (common bug): - -- `SelectItem` cannot have `value=""`. Use a sentinel value like `"all"` or `"none"`. - -**Available components:** - -`Accordion`, `Alert`, `AlertDialog`, `AspectRatio`, `Avatar`, `Badge`, `Breadcrumb`, `Button`, `ButtonGroup`, `Calendar`, `Card`, `CardHeader`, `CardTitle`, `CardDescription`, `CardContent`, `CardFooter`, `Carousel`, `Checkbox`, `Collapsible`, `Command`, `ContextMenu`, `Dialog`, `DialogTrigger`, `DialogContent`, `DialogHeader`, `DialogTitle`, `DialogDescription`, `DialogFooter`, `Drawer`, `DropdownMenu`, `Empty`, `Field`, `Form`, `HoverCard`, `Input`, `InputGroup`, `InputOtp`, `Item`, `Kbd`, `Label`, `Menubar`, `NavigationMenu`, `Pagination`, `Popover`, `Progress`, `RadioGroup`, `Resizable`, `ScrollArea`, `Select`, `SelectTrigger`, `SelectValue`, `SelectContent`, `SelectItem`, `Separator`, `Sheet`, `Sidebar`, `Skeleton`, `Slider`, `Sonner`, `Spinner`, `Switch`, `Table`, `Tabs`, `TabsList`, `TabsTrigger`, `TabsContent`, `Textarea`, `Toggle`, `ToggleGroup`, `Tooltip`, `TooltipTrigger`, `TooltipContent`, `TooltipProvider` - -### Card pattern - -```tsx -import { - Card, - CardHeader, - CardTitle, - CardDescription, - CardContent, - CardFooter, -} from "@databricks/appkit-ui/react"; - -function MetricCard({ title, value, description }: Props) { - return ( - - - {description} - {value} - - - {/* Optional content */} - - - {/* Optional footer */} - - - ); -} -``` - -### Select pattern - -```tsx -import { - Select, - SelectTrigger, - SelectValue, - SelectContent, - SelectItem, -} from "@databricks/appkit-ui/react"; - -function DateRangeSelect({ value, onChange }: Props) { - return ( - - ); -} -``` - -### Tabs pattern - -```tsx -import { Tabs, TabsList, TabsTrigger, TabsContent } from "@databricks/appkit-ui/react"; - -function Dashboard() { - return ( - - - Overview - Analytics - - -

Overview content

-
- -

Analytics content

-
-
- ); -} -``` - -### Dialog pattern - -```tsx -import { - Dialog, - DialogTrigger, - DialogContent, - DialogHeader, - DialogTitle, - DialogDescription, - DialogFooter, - Button, -} from "@databricks/appkit-ui/react"; - -function ConfirmDialog() { - return ( - - - - - - - Confirm deletion - - This action cannot be undone. - - - - - - - - - ); -} -``` - -### TooltipProvider requirement - -If using tooltips anywhere in your app, wrap your root component with `TooltipProvider`: - -```tsx -import { TooltipProvider } from "@databricks/appkit-ui/react"; - -function App() { - return ( - - {/* Your app content */} - - ); -} -``` - -### Button variants - -```tsx -import { Button } from "@databricks/appkit-ui/react"; - - - - - - - -``` - -### Loading skeleton pattern - -```tsx -import { Card, CardHeader, Skeleton } from "@databricks/appkit-ui/react"; - -function LoadingCard() { - return ( - - - - - - - - ); -} -``` - -## Stylesheet - -In the main css file import the following - -```css -@import "@databricks/appkit-ui/styles.css"; -``` - -That will provide a default theme for the app using css variables. - -### Customizing theme (light/dark mode) - -- Full list of variables to customize the theme. - -```css -@import "@databricks/appkit-ui/styles.css"; - -:root { - --radius: 0.625rem; - --background: oklch(1 0 0); - --foreground: oklch(0.141 0.005 285.823); - --card: oklch(1 0 0); - --card-foreground: oklch(0.141 0.005 285.823); - --popover: oklch(1 0 0); - --popover-foreground: oklch(0.141 0.005 285.823); - --primary: oklch(0.21 0.006 285.885); - --primary-foreground: oklch(0.985 0 0); - --secondary: oklch(0.967 0.001 286.375); - --secondary-foreground: oklch(0.21 0.006 285.885); - --muted: oklch(0.967 0.001 286.375); - --muted-foreground: oklch(0.552 0.016 285.938); - --accent: oklch(0.967 0.001 286.375); - --accent-foreground: oklch(0.21 0.006 285.885); - --destructive: oklch(0.577 0.245 27.325); - --destructive-foreground: oklch(0.985 0 0); - --success: oklch(0.603 0.135 166.892); - --success-foreground: oklch(1 0 0); - --warning: oklch(0.795 0.157 78.748); - --warning-foreground: oklch(0.199 0.027 238.732); - --border: oklch(0.92 0.004 286.32); - --input: oklch(0.92 0.004 286.32); - --ring: oklch(0.705 0.015 286.067); - --chart-1: oklch(0.646 0.222 41.116); - --chart-2: oklch(0.6 0.118 184.704); - --chart-3: oklch(0.398 0.07 227.392); - --chart-4: oklch(0.828 0.189 84.429); - --chart-5: oklch(0.769 0.188 70.08); - --sidebar: oklch(0.985 0 0); - --sidebar-foreground: oklch(0.141 0.005 285.823); - --sidebar-primary: oklch(0.21 0.006 285.885); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.967 0.001 286.375); - --sidebar-accent-foreground: oklch(0.21 0.006 285.885); - --sidebar-border: oklch(0.92 0.004 286.32); - --sidebar-ring: oklch(0.705 0.015 286.067); -} - -@media (prefers-color-scheme: dark) { - :root { - --background: oklch(0.141 0.005 285.823); - --foreground: oklch(0.985 0 0); - --card: oklch(0.21 0.006 285.885); - --card-foreground: oklch(0.985 0 0); - --popover: oklch(0.21 0.006 285.885); - --popover-foreground: oklch(0.985 0 0); - --primary: oklch(0.92 0.004 286.32); - --primary-foreground: oklch(0.21 0.006 285.885); - --secondary: oklch(0.274 0.006 286.033); - --secondary-foreground: oklch(0.985 0 0); - --muted: oklch(0.274 0.006 286.033); - --muted-foreground: oklch(0.705 0.015 286.067); - --accent: oklch(0.274 0.006 286.033); - --accent-foreground: oklch(0.985 0 0); - --destructive: oklch(0.704 0.191 22.216); - --destructive-foreground: oklch(0.985 0 0); - --success: oklch(0.67 0.12 167); - --success-foreground: oklch(1 0 0); - --warning: oklch(0.83 0.165 85); - --warning-foreground: oklch(0.199 0.027 238.732); - --border: oklch(1 0 0 / 10%); - --input: oklch(1 0 0 / 15%); - --ring: oklch(0.552 0.016 285.938); - --chart-1: oklch(0.488 0.243 264.376); - --chart-2: oklch(0.696 0.17 162.48); - --chart-3: oklch(0.769 0.188 70.08); - --chart-4: oklch(0.627 0.265 303.9); - --chart-5: oklch(0.645 0.246 16.439); - --sidebar: oklch(0.21 0.006 285.885); - --sidebar-foreground: oklch(0.985 0 0); - --sidebar-primary: oklch(0.488 0.243 264.376); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.274 0.006 286.033); - --sidebar-accent-foreground: oklch(0.985 0 0); - --sidebar-border: oklch(1 0 0 / 10%); - --sidebar-ring: oklch(0.552 0.016 285.938); - } -} - -``` - -- If any variable is changed, it must be changed for both light and dark mode. - -## Type generation (QueryRegistry + IntelliSense) - -Goal: generate `client/src/appKitTypes.d.ts` so query keys, params, and result rows are type-safe. - -### Vite plugin: `appKitTypesPlugin` - -Correct option names: - -- `outFile?: string` (default `src/appKitTypes.d.ts`) -- `watchFolders?: string[]` (default `["../config/queries"]`) - -```ts -// client/vite.config.ts -import { defineConfig } from "vite"; -import react from "@vitejs/plugin-react"; -import { appKitTypesPlugin } from "@databricks/appkit"; - -export default defineConfig({ - plugins: [ - react(), - appKitTypesPlugin({ - outFile: "src/appKitTypes.d.ts", - watchFolders: ["../config/queries"], - }), - ], -}); -``` - -Important nuance: - -- When the frontend is served through AppKit in dev mode, AppKit’s dev server already includes `appKitTypesPlugin()` internally. -- You still want it in your client build pipeline if you run `vite build` separately. - -### CLI: `appkit-generate-types` - -```bash -# Requires DATABRICKS_WAREHOUSE_ID (or pass as 3rd arg) -npx appkit-generate-types [rootDir] [outFile] [warehouseId] - -# Example: -npx appkit-generate-types . client/src/appKitTypes.d.ts - -# Force regeneration (skip cache): -npx appkit-generate-types --no-cache -``` - -## Databricks Apps config: `app.yaml` - -Bind a SQL warehouse for Apps runtime: - -```yaml -env: - - name: DATABRICKS_WAREHOUSE_ID - valueFrom: sql-warehouse -``` - -Full example with command: - -```yaml -command: - - node - - build/index.mjs -env: - - name: DATABRICKS_WAREHOUSE_ID - valueFrom: sql-warehouse -``` - -## LLM checklist (before you "finalize" code) - -- **Project setup** - - `package.json` has `"type": "module"` - - `tsx` is in devDependencies for dev server - - `dev` script uses `NODE_ENV=development tsx watch server/index.ts` - - `client/index.html` exists with `
` and script pointing to `client/src/main.tsx` - -- **Backend** - - `await createApp({ plugins: [...] })` is used (or `void createApp` with intent) - - `server()` is included (always) - - If using SQL: `analytics({})` included + `config/queries/*.sql` present - - Queries use `:param` placeholders, and params are passed from UI using `sql.*` - - If query needs workspace scoping: uses `:workspaceId` - -- **Frontend** - - `useMemo` wraps parameters objects - - Loading/error/empty states are explicit - - Charts use `format="auto"` unless you have a reason to force `"json"`/`"arrow"` - - Charts use props (`xKey`, `yKey`, `colors`) NOT children (they're ECharts-based, not Recharts) - - If using tooltips: root is wrapped with `` - -- **Never** - - Don't build SQL strings manually - - Don't pass untyped raw params for annotated queries - - Don't ignore `createApp()`'s promise - - Don't invent UI components not listed in this file - - Don't pass Recharts children (``, ``, etc.) to AppKit chart components - diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d63a0a85..2f5662d6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -175,6 +175,9 @@ importers: '@mdx-js/react': specifier: ^3.0.0 version: 3.1.1(@types/react@19.2.7)(react@19.2.0) + '@signalwire/docusaurus-plugin-llms-txt': + specifier: 2.0.0-alpha.7 + version: 2.0.0-alpha.7(@docusaurus/core@3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.0))(bufferutil@4.0.9)(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3)) '@tailwindcss/postcss': specifier: ^4.1.18 version: 4.1.18 @@ -3000,8 +3003,8 @@ packages: resolution: {integrity: sha512-Z7x2dZOmznihvdvCvLKMl+nswtOSVxS2H2ocar+U9xx6iMfTp0VGIrX6a4xB1v80IwOPC7dT1LXIJrY70Xu3Jw==} engines: {node: ^20.19.0 || >=22.12.0} - '@oxc-project/types@0.108.0': - resolution: {integrity: sha512-7lf13b2IA/kZO6xgnIZA88sq3vwrxWk+2vxf6cc+omwYCRTiA5e63Beqf3fz/v8jEviChWWmFYBwzfSeyrsj7Q==} + '@oxc-project/types@0.110.0': + resolution: {integrity: sha512-6Ct21OIlrEnFEJk5LT4e63pk3btsI6/TusD/GStLi7wYlGJNOl1GI9qvXAnRAxQU9zqA2Oz+UwhfTOU2rPZVow==} '@oxc-project/types@0.93.0': resolution: {integrity: sha512-yNtwmWZIBtJsMr5TEfoZFDxIWV6OdScOpza/f5YxbqUMJk+j6QX3Cf3jgZShGEFYWQJ5j9mJ6jM0tZHu2J9Yrg==} @@ -3721,8 +3724,8 @@ packages: cpu: [arm64] os: [android] - '@rolldown/binding-android-arm64@1.0.0-beta.60': - resolution: {integrity: sha512-hOW6iQXtpG4uCW1zGK56+KhEXGttSkTp2ykncW/nkOIF/jOKTqbM944Q73HVeMXP1mPRvE2cZwNp3xeLIeyIGQ==} + '@rolldown/binding-android-arm64@1.0.0-rc.1': + resolution: {integrity: sha512-He6ZoCfv5D7dlRbrhNBkuMVIHd0GDnjJwbICE1OWpG7G3S2gmJ+eXkcNLJjzjNDpeI2aRy56ou39AJM9AD8YFA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] @@ -3733,8 +3736,8 @@ packages: cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-arm64@1.0.0-beta.60': - resolution: {integrity: sha512-vyDA4HXY2mP8PPtl5UE17uGPxUNG4m1wkfa3kAkR8JWrFbarV97UmLq22IWrNhtBPa89xqerzLK8KoVmz5JqCQ==} + '@rolldown/binding-darwin-arm64@1.0.0-rc.1': + resolution: {integrity: sha512-YzJdn08kSOXnj85ghHauH2iHpOJ6eSmstdRTLyaziDcUxe9SyQJgGyx/5jDIhDvtOcNvMm2Ju7m19+S/Rm1jFg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] @@ -3745,8 +3748,8 @@ packages: cpu: [x64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.0-beta.60': - resolution: {integrity: sha512-WnxyqxAKP2BsxouwGY/RCF5UFw/LA4QOHhJ7VEl+UCelHokiwqNHRbryLAyRy3TE1FZ5eae+vAFcaetAu/kWLw==} + '@rolldown/binding-darwin-x64@1.0.0-rc.1': + resolution: {integrity: sha512-cIvAbqM+ZVV6lBSKSBtlNqH5iCiW933t1q8j0H66B3sjbe8AxIRetVqfGgcHcJtMzBIkIALlL9fcDrElWLJQcQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] @@ -3757,8 +3760,8 @@ packages: cpu: [x64] os: [freebsd] - '@rolldown/binding-freebsd-x64@1.0.0-beta.60': - resolution: {integrity: sha512-JtyWJ+zXOHof5gOUYwdTWI2kL6b8q9eNwqB/oD4mfUFaC/COEB2+47JMhcq78dey9Ahmec3DZKRDZPRh9hNAMQ==} + '@rolldown/binding-freebsd-x64@1.0.0-rc.1': + resolution: {integrity: sha512-rVt+B1B/qmKwCl1XD02wKfgh3vQPXRXdB/TicV2w6g7RVAM1+cZcpigwhLarqiVCxDObFZ7UgXCxPC7tpDoRog==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] @@ -3769,8 +3772,8 @@ packages: cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.60': - resolution: {integrity: sha512-LrMoKqpHx+kCaNSk84iSBd4yVOymLIbxJQtvFjDN2CjQraownR+IXcwYDblFcj9ivmS54T3vCboXBbm3s1zbPQ==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.1': + resolution: {integrity: sha512-69YKwJJBOFprQa1GktPgbuBOfnn+EGxu8sBJ1TjPER+zhSpYeaU4N07uqmyBiksOLGXsMegymuecLobfz03h8Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] @@ -3781,8 +3784,8 @@ packages: cpu: [arm64] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.60': - resolution: {integrity: sha512-sqI+Vdx1gmXJMsXN3Fsewm3wlt7RHvRs1uysSp//NLsCoh9ZFEUr4ZzGhWKOg6Rvf+njNu/vCsz96x7wssLejQ==} + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.1': + resolution: {integrity: sha512-9JDhHUf3WcLfnViFWm+TyorqUtnSAHaCzlSNmMOq824prVuuzDOK91K0Hl8DUcEb9M5x2O+d2/jmBMsetRIn3g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] @@ -3793,8 +3796,8 @@ packages: cpu: [arm64] os: [linux] - '@rolldown/binding-linux-arm64-musl@1.0.0-beta.60': - resolution: {integrity: sha512-8xlqGLDtTP8sBfYwneTDu8+PRm5reNEHAuI/+6WPy9y350ls0KTFd3EJCOWEXWGW0F35ko9Fn9azmurBTjqOrQ==} + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.1': + resolution: {integrity: sha512-UvApLEGholmxw/HIwmUnLq3CwdydbhaHHllvWiCTNbyGom7wTwOtz5OAQbAKZYyiEOeIXZNPkM7nA4Dtng7CLw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] @@ -3805,8 +3808,8 @@ packages: cpu: [x64] os: [linux] - '@rolldown/binding-linux-x64-gnu@1.0.0-beta.60': - resolution: {integrity: sha512-iR4nhVouVZK1CiGGGyz+prF5Lw9Lmz30Rl36Hajex+dFVFiegka604zBwzTp5Tl0BZnr50ztnVJ30tGrBhDr8Q==} + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.1': + resolution: {integrity: sha512-uVctNgZHiGnJx5Fij7wHLhgw4uyZBVi6mykeWKOqE7bVy9Hcxn0fM/IuqdMwk6hXlaf9fFShDTFz2+YejP+x0A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] @@ -3817,8 +3820,8 @@ packages: cpu: [x64] os: [linux] - '@rolldown/binding-linux-x64-musl@1.0.0-beta.60': - resolution: {integrity: sha512-HbfNcqNeqxFjSMf1Kpe8itr2e2lr0Bm6HltD2qXtfU91bSSikVs9EWsa1ThshQ1v2ZvxXckGjlVLtah6IoslPg==} + '@rolldown/binding-linux-x64-musl@1.0.0-rc.1': + resolution: {integrity: sha512-T6Eg0xWwcxd/MzBcuv4Z37YVbUbJxy5cMNnbIt/Yr99wFwli30O4BPlY8hKeGyn6lWNtU0QioBS46lVzDN38bg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] @@ -3829,8 +3832,8 @@ packages: cpu: [arm64] os: [openharmony] - '@rolldown/binding-openharmony-arm64@1.0.0-beta.60': - resolution: {integrity: sha512-BiiamFcgTJ+ZFOUIMO9AHXUo9WXvHVwGfSrJ+Sv0AsTd2w3VN7dJGiH3WRcxKFetljJHWvGbM4fdpY5lf6RIvw==} + '@rolldown/binding-openharmony-arm64@1.0.0-rc.1': + resolution: {integrity: sha512-PuGZVS2xNJyLADeh2F04b+Cz4NwvpglbtWACgrDOa5YDTEHKwmiTDjoD5eZ9/ptXtcpeFrMqD2H4Zn33KAh1Eg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] @@ -3840,8 +3843,8 @@ packages: engines: {node: '>=14.0.0'} cpu: [wasm32] - '@rolldown/binding-wasm32-wasi@1.0.0-beta.60': - resolution: {integrity: sha512-6roXGbHMdR2ucnxXuwbmQvk8tuYl3VGu0yv13KxspyKBxxBd4RS6iykzLD6mX2gMUHhfX8SVWz7n/62gfyKHow==} + '@rolldown/binding-wasm32-wasi@1.0.0-rc.1': + resolution: {integrity: sha512-2mOxY562ihHlz9lEXuaGEIDCZ1vI+zyFdtsoa3M62xsEunDXQE+DVPO4S4x5MPK9tKulG/aFcA/IH5eVN257Cw==} engines: {node: '>=14.0.0'} cpu: [wasm32] @@ -3851,8 +3854,8 @@ packages: cpu: [arm64] os: [win32] - '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.60': - resolution: {integrity: sha512-JBOm8/DC/CKnHyMHoJFdvzVHxUixid4dGkiTqGflxOxO43uSJMpl77pSPXvzwZ/VXwqblU2V0/PanyCBcRLowQ==} + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.1': + resolution: {integrity: sha512-oQVOP5cfAWZwRD0Q3nGn/cA9FW3KhMMuQ0NIndALAe6obqjLhqYVYDiGGRGrxvnjJsVbpLwR14gIUYnpIcHR1g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] @@ -3869,8 +3872,8 @@ packages: cpu: [x64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.0-beta.60': - resolution: {integrity: sha512-MKF0B823Efp+Ot8KsbwIuGhKH58pf+2rSM6VcqyNMlNBHheOM0Gf7JmEu+toc1jgN6fqjH7Et+8hAzsLVkIGfA==} + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.1': + resolution: {integrity: sha512-Ydsxxx++FNOuov3wCBPaYjZrEvKOOGq3k+BF4BPridhg2pENfitSRD2TEuQ8i33bp5VptuNdC9IzxRKU031z5A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -3884,8 +3887,8 @@ packages: '@rolldown/pluginutils@1.0.0-beta.47': resolution: {integrity: sha512-8QagwMH3kNCuzD8EWL8R2YPW5e4OrHNSAHRFDdmFqEwEaD/KcNKjVoumo+gP2vW5eKB2UPbM6vTYiGZX0ixLnw==} - '@rolldown/pluginutils@1.0.0-beta.60': - resolution: {integrity: sha512-Jz4aqXRPVtqkH1E3jRDzLO5cgN5JwW+WG0wXGE4NiJd25nougv/AHzxmKCzmVQUYnxLmTM0M4wrZp+LlC2FKLg==} + '@rolldown/pluginutils@1.0.0-rc.1': + resolution: {integrity: sha512-UTBjtTxVOhodhzFVp/ayITaTETRHPUPYZPXQe0WU0wOgxghMojXxYjOiPOauKIYNWJAWS2fd7gJgGQK8GU8vDA==} '@rollup/rollup-android-arm-eabi@4.52.4': resolution: {integrity: sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA==} @@ -4021,6 +4024,12 @@ packages: '@sideway/pinpoint@2.0.0': resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} + '@signalwire/docusaurus-plugin-llms-txt@2.0.0-alpha.7': + resolution: {integrity: sha512-v9EcYXVNvMydIWVIzI1H2iC4/BNdystE0jJAQIFu68SHy1a13dESz9hn5YJE9Izx18QPny1jhXym/3wEP9+8LA==} + engines: {node: '>=18.0.0'} + peerDependencies: + '@docusaurus/core': ^3.0.0 + '@simple-libs/child-process-utils@1.0.1': resolution: {integrity: sha512-3nWd8irxvDI6v856wpPCHZ+08iQR0oHTZfzAZmnbsLzf+Sf1odraP6uKOHDZToXq3RPRV/LbqGVlSCogm9cJjg==} engines: {node: '>=18'} @@ -5088,6 +5097,9 @@ packages: bcp-47-match@1.0.3: resolution: {integrity: sha512-LggQ4YTdjWQSKELZF5JwchnBa1u0pIQSZf5lSdOHEdbVP55h0qICA/FUp3+W99q0xqxYa1ZQizTUH87gecII5w==} + bcp-47-match@2.0.3: + resolution: {integrity: sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==} + before-after-hook@4.0.0: resolution: {integrity: sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==} @@ -5697,6 +5709,9 @@ packages: css-selector-parser@1.4.1: resolution: {integrity: sha512-HYPSb7y/Z7BNDCOrakL4raGO2zltZkbeXyAd6Tg9obzix6QhzxCotdBl6VT0Dv4vZfJGVz3WL/xaEI9Ly3ul0g==} + css-selector-parser@3.3.0: + resolution: {integrity: sha512-Y2asgMGFqJKF4fq4xHDSlFYIkeVfRsm69lQC1q9kbEsH5XtnINTMrweLkjYMeaUgiXBy/uvKeO/a1JHTNnmB2g==} + 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'} @@ -6130,6 +6145,10 @@ packages: resolution: {integrity: sha512-GYqKi1aH7PJXxdhTeZBFrg8vUBeKXi+cNprXsC1kpJcbcVnV9wBsrOu1cQEdG0WeQwlfHiy3XvnKfIrJ2R0NzQ==} hasBin: true + direction@2.0.1: + resolution: {integrity: sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==} + hasBin: true + dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} @@ -6939,6 +6958,12 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + hast-util-embedded@3.0.0: + resolution: {integrity: sha512-naH8sld4Pe2ep03qqULEtvYr7EjrLK2QHY8KJR6RJkTUjPGObe1vnx585uzem2hGra+s1q08DZZpfgDVYRbaXA==} + + hast-util-from-html@2.0.3: + resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} + hast-util-from-parse5@6.0.1: resolution: {integrity: sha512-jeJUWiN5pSxW12Rh01smtVkZgZr33wBokLzKLwinYOUfSzm1Nl/c3GUGebDyOKjdsRgMvoVbV0VpAcpjF4NrJA==} @@ -6948,36 +6973,66 @@ packages: hast-util-has-property@1.0.4: resolution: {integrity: sha512-ghHup2voGfgFoHMGnaLHOjbYFACKrRh9KFttdCzMCbFoBMJXiNi2+XTrPP8+q6cDJM/RSqlCfVWrjp1H201rZg==} + hast-util-has-property@3.0.0: + resolution: {integrity: sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==} + + hast-util-is-body-ok-link@3.0.1: + resolution: {integrity: sha512-0qpnzOBLztXHbHQenVB8uNuxTnm/QBFUOmdOSsEn7GnBtyY07+ENTWVFBAnXd/zEgd9/SUG3lRY7hSIBWRgGpQ==} + hast-util-is-element@1.1.0: resolution: {integrity: sha512-oUmNua0bFbdrD/ELDSSEadRVtWZOf3iF6Lbv81naqsIV99RnSCieTbWuWCY8BAeEfKJTKl0gRdokv+dELutHGQ==} + hast-util-is-element@3.0.0: + resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} + + hast-util-minify-whitespace@1.0.1: + resolution: {integrity: sha512-L96fPOVpnclQE0xzdWb/D12VT5FabA7SnZOUMtL1DbXmYiHJMXZvFkIZfiMmTCNJHUeO2K9UYNXoVyfz+QHuOw==} + hast-util-parse-selector@2.2.5: resolution: {integrity: sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==} hast-util-parse-selector@4.0.0: resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} + hast-util-phrasing@3.0.1: + resolution: {integrity: sha512-6h60VfI3uBQUxHqTyMymMZnEbNl1XmEGtOxxKYL7stY2o601COo62AWAYBQR9lZbYXYSBoxag8UpPRXK+9fqSQ==} + hast-util-raw@9.1.0: resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==} hast-util-select@4.0.2: resolution: {integrity: sha512-8EEG2//bN5rrzboPWD2HdS3ugLijNioS1pqOTIolXNf67xxShYw4SQEmVXd3imiBG+U2bC2nVTySr/iRAA7Cjg==} + hast-util-select@6.0.4: + resolution: {integrity: sha512-RqGS1ZgI0MwxLaKLDxjprynNzINEkRHY2i8ln4DDjgv9ZhcYVIHN9rlpiYsqtFwrgpYU361SyWDQcGNIBVu3lw==} + hast-util-to-estree@3.1.3: resolution: {integrity: sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==} + hast-util-to-html@9.0.5: + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} + hast-util-to-jsx-runtime@2.3.6: resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==} + hast-util-to-mdast@10.1.2: + resolution: {integrity: sha512-FiCRI7NmOvM4y+f5w32jPRzcxDIz+PUqDwEqn1A+1q2cdp3B8Gx7aVrXORdOKjMNDQsD1ogOr896+0jJHW1EFQ==} + hast-util-to-parse5@8.0.1: resolution: {integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==} hast-util-to-string@1.0.4: resolution: {integrity: sha512-eK0MxRX47AV2eZ+Lyr18DCpQgodvaS3fAQO2+b9Two9F5HEoRPhiUMNzoXArMJfZi2yieFzUBMRl3HNJ3Jus3w==} + hast-util-to-string@3.0.1: + resolution: {integrity: sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==} + hast-util-to-text@2.0.1: resolution: {integrity: sha512-8nsgCARfs6VkwH2jJU9b8LNTuR4700na+0h3PqCaEk4MAnMDeu5P0tP8mjk9LLNGxIeQRLbiDbZVw6rku+pYsQ==} + hast-util-to-text@4.0.2: + resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==} + hast-util-whitespace@1.0.4: resolution: {integrity: sha512-I5GTdSfhYfAPNztx2xJRQpG8cuDSNt599/7YUn7Gx/WxNMsG+a835k97TDkFgk123cwjfwINaZknkKkphx/f2A==} @@ -8493,6 +8548,10 @@ packages: resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} engines: {node: '>=10'} + p-map@7.0.4: + resolution: {integrity: sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==} + engines: {node: '>=18'} + p-queue@6.6.2: resolution: {integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==} engines: {node: '>=8'} @@ -9440,15 +9499,24 @@ packages: resolution: {integrity: sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==} hasBin: true + rehype-minify-whitespace@6.0.2: + resolution: {integrity: sha512-Zk0pyQ06A3Lyxhe9vGtOtzz3Z0+qZ5+7icZ/PL/2x1SHPbKao5oB/g/rlc6BCTajqBb33JcOe71Ye1oFsuYbnw==} + rehype-parse@7.0.1: resolution: {integrity: sha512-fOiR9a9xH+Le19i4fGzIEowAbwG7idy2Jzs4mOrFWBSJ0sNUgy0ev871dwWnbOo371SjgjG4pwzrbgSVrKxecw==} + rehype-parse@9.0.1: + resolution: {integrity: sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==} + rehype-raw@7.0.0: resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==} rehype-recma@1.0.0: resolution: {integrity: sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==} + rehype-remark@10.0.1: + resolution: {integrity: sha512-EmDndlb5NVwXGfUa4c9GPK+lXeItTilLhE6ADSaQuHr4JUlKw9MidzGzx4HpqZrNCt6vnHmEifXQiiA+CEnjYQ==} + relateurl@0.2.7: resolution: {integrity: sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==} engines: {node: '>= 0.10'} @@ -9641,8 +9709,8 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - rolldown@1.0.0-beta.60: - resolution: {integrity: sha512-YYgpv7MiTp9LdLj1fzGzCtij8Yi2OKEc3HQtfbIxW4yuSgpQz9518I69U72T5ErPA/ATOXqlcisiLrWy+5V9YA==} + rolldown@1.0.0-rc.1: + resolution: {integrity: sha512-M3AeZjYE6UclblEf531Hch0WfVC/NOL43Cc+WdF3J50kk5/fvouHhDumSGTh0oRjbZ8C4faaVr5r6Nx1xMqDGg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -10225,6 +10293,9 @@ packages: trim-lines@3.0.1: resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + trim-trailing-lines@2.1.0: + resolution: {integrity: sha512-5UR5Biq4VlVOtzqkm2AZlgvSlDJtME46uV0br0gENbwN4l5+mMKT4b9gJKqWtuL2zAIqajGJGuvbCbcAJUZqBg==} + trough@1.0.5: resolution: {integrity: sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==} @@ -10458,6 +10529,9 @@ packages: unist-util-find-after@3.0.0: resolution: {integrity: sha512-ojlBqfsBftYXExNu3+hHLfJQ/X1jYY/9vdm4yZWjIbf0VuWF6CRufci1ZyoD/wV2TYMKxXUoNuoqwy+CkgzAiQ==} + unist-util-find-after@5.0.0: + resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==} + unist-util-is@4.1.0: resolution: {integrity: sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==} @@ -14578,7 +14652,7 @@ snapshots: '@oxc-project/runtime@0.92.0': {} - '@oxc-project/types@0.108.0': {} + '@oxc-project/types@0.110.0': {} '@oxc-project/types@0.93.0': {} @@ -15322,61 +15396,61 @@ snapshots: '@rolldown/binding-android-arm64@1.0.0-beta.41': optional: true - '@rolldown/binding-android-arm64@1.0.0-beta.60': + '@rolldown/binding-android-arm64@1.0.0-rc.1': optional: true '@rolldown/binding-darwin-arm64@1.0.0-beta.41': optional: true - '@rolldown/binding-darwin-arm64@1.0.0-beta.60': + '@rolldown/binding-darwin-arm64@1.0.0-rc.1': optional: true '@rolldown/binding-darwin-x64@1.0.0-beta.41': optional: true - '@rolldown/binding-darwin-x64@1.0.0-beta.60': + '@rolldown/binding-darwin-x64@1.0.0-rc.1': optional: true '@rolldown/binding-freebsd-x64@1.0.0-beta.41': optional: true - '@rolldown/binding-freebsd-x64@1.0.0-beta.60': + '@rolldown/binding-freebsd-x64@1.0.0-rc.1': optional: true '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.41': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.60': + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.1': optional: true '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.41': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.60': + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.1': optional: true '@rolldown/binding-linux-arm64-musl@1.0.0-beta.41': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.0-beta.60': + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.1': optional: true '@rolldown/binding-linux-x64-gnu@1.0.0-beta.41': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-beta.60': + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.1': optional: true '@rolldown/binding-linux-x64-musl@1.0.0-beta.41': optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-beta.60': + '@rolldown/binding-linux-x64-musl@1.0.0-rc.1': optional: true '@rolldown/binding-openharmony-arm64@1.0.0-beta.41': optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-beta.60': + '@rolldown/binding-openharmony-arm64@1.0.0-rc.1': optional: true '@rolldown/binding-wasm32-wasi@1.0.0-beta.41': @@ -15384,7 +15458,7 @@ snapshots: '@napi-rs/wasm-runtime': 1.0.7 optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-beta.60': + '@rolldown/binding-wasm32-wasi@1.0.0-rc.1': dependencies: '@napi-rs/wasm-runtime': 1.1.1 optional: true @@ -15392,7 +15466,7 @@ snapshots: '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.41': optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.60': + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.1': optional: true '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.41': @@ -15401,7 +15475,7 @@ snapshots: '@rolldown/binding-win32-x64-msvc@1.0.0-beta.41': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-beta.60': + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.1': optional: true '@rolldown/pluginutils@1.0.0-beta.38': {} @@ -15410,7 +15484,7 @@ snapshots: '@rolldown/pluginutils@1.0.0-beta.47': {} - '@rolldown/pluginutils@1.0.0-beta.60': {} + '@rolldown/pluginutils@1.0.0-rc.1': {} '@rollup/rollup-android-arm-eabi@4.52.4': optional: true @@ -15506,6 +15580,24 @@ snapshots: '@sideway/pinpoint@2.0.0': {} + '@signalwire/docusaurus-plugin-llms-txt@2.0.0-alpha.7(@docusaurus/core@3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.0))(bufferutil@4.0.9)(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3))': + dependencies: + '@docusaurus/core': 3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.0))(bufferutil@4.0.9)(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) + fs-extra: 11.3.2 + hast-util-select: 6.0.4 + hast-util-to-html: 9.0.5 + hast-util-to-string: 3.0.1 + p-map: 7.0.4 + rehype-parse: 9.0.1 + rehype-remark: 10.0.1 + remark-gfm: 4.0.1 + remark-stringify: 11.0.0 + string-width: 5.1.2 + unified: 11.0.5 + unist-util-visit: 5.0.0 + transitivePeerDependencies: + - supports-color + '@simple-libs/child-process-utils@1.0.1': dependencies: '@simple-libs/stream-utils': 1.1.0 @@ -16777,6 +16869,8 @@ snapshots: bcp-47-match@1.0.3: {} + bcp-47-match@2.0.3: {} + before-after-hook@4.0.0: {} bidi-js@1.0.3: @@ -17432,6 +17526,8 @@ snapshots: css-selector-parser@1.4.1: {} + css-selector-parser@3.3.0: {} + css-tree@2.2.1: dependencies: mdn-data: 2.0.28 @@ -17898,6 +17994,8 @@ snapshots: direction@1.0.4: {} + direction@2.0.1: {} + dlv@1.1.3: {} dns-packet@5.6.1: @@ -18858,6 +18956,20 @@ snapshots: dependencies: function-bind: 1.1.2 + hast-util-embedded@3.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-is-element: 3.0.0 + + hast-util-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@6.0.1: dependencies: '@types/parse5': 5.0.3 @@ -18880,14 +18992,42 @@ snapshots: hast-util-has-property@1.0.4: {} + hast-util-has-property@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-is-body-ok-link@3.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-is-element@1.1.0: {} + hast-util-is-element@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-minify-whitespace@1.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-embedded: 3.0.0 + hast-util-is-element: 3.0.0 + hast-util-whitespace: 3.0.0 + unist-util-is: 6.0.1 + hast-util-parse-selector@2.2.5: {} hast-util-parse-selector@4.0.0: dependencies: '@types/hast': 3.0.4 + hast-util-phrasing@3.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-embedded: 3.0.0 + hast-util-has-property: 3.0.0 + hast-util-is-body-ok-link: 3.0.1 + hast-util-is-element: 3.0.0 + hast-util-raw@9.1.0: dependencies: '@types/hast': 3.0.4 @@ -18921,6 +19061,24 @@ snapshots: unist-util-visit: 2.0.3 zwitch: 1.0.5 + hast-util-select@6.0.4: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + bcp-47-match: 2.0.3 + comma-separated-tokens: 2.0.3 + css-selector-parser: 3.3.0 + devlop: 1.1.0 + direction: 2.0.1 + hast-util-has-property: 3.0.0 + hast-util-to-string: 3.0.1 + hast-util-whitespace: 3.0.0 + nth-check: 2.1.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + unist-util-visit: 5.0.0 + zwitch: 2.0.4 + hast-util-to-estree@3.1.3: dependencies: '@types/estree': 1.0.8 @@ -18942,6 +19100,20 @@ snapshots: transitivePeerDependencies: - supports-color + hast-util-to-html@9.0.5: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + hast-util-to-jsx-runtime@2.3.6: dependencies: '@types/estree': 1.0.8 @@ -18962,6 +19134,23 @@ snapshots: transitivePeerDependencies: - supports-color + hast-util-to-mdast@10.1.2: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.0 + hast-util-phrasing: 3.0.1 + hast-util-to-html: 9.0.5 + hast-util-to-text: 4.0.2 + hast-util-whitespace: 3.0.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-hast: 13.2.1 + mdast-util-to-string: 4.0.0 + rehype-minify-whitespace: 6.0.2 + trim-trailing-lines: 2.1.0 + unist-util-position: 5.0.0 + unist-util-visit: 5.0.0 + hast-util-to-parse5@8.0.1: dependencies: '@types/hast': 3.0.4 @@ -18974,12 +19163,23 @@ snapshots: hast-util-to-string@1.0.4: {} + hast-util-to-string@3.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-to-text@2.0.1: dependencies: hast-util-is-element: 1.1.0 repeat-string: 1.6.1 unist-util-find-after: 3.0.0 + 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@1.0.4: {} hast-util-whitespace@3.0.0: @@ -20766,6 +20966,8 @@ snapshots: dependencies: aggregate-error: 3.1.0 + p-map@7.0.4: {} + p-queue@6.6.2: dependencies: eventemitter3: 4.0.7 @@ -21834,11 +22036,22 @@ snapshots: dependencies: jsesc: 3.1.0 + rehype-minify-whitespace@6.0.2: + dependencies: + '@types/hast': 3.0.4 + hast-util-minify-whitespace: 1.0.1 + rehype-parse@7.0.1: dependencies: hast-util-from-parse5: 6.0.1 parse5: 6.0.1 + 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 @@ -21853,6 +22066,14 @@ snapshots: transitivePeerDependencies: - supports-color + rehype-remark@10.0.1: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + hast-util-to-mdast: 10.1.2 + unified: 11.0.5 + vfile: 6.0.3 + relateurl@0.2.7: {} release-it@19.2.0(@types/node@24.7.2)(magicast@0.3.5): @@ -22033,7 +22254,7 @@ snapshots: robust-predicates@3.0.2: {} - rolldown-plugin-dts@0.16.11(rolldown@1.0.0-beta.60)(typescript@5.9.3): + rolldown-plugin-dts@0.16.11(rolldown@1.0.0-rc.1)(typescript@5.9.3): dependencies: '@babel/generator': 7.28.3 '@babel/parser': 7.28.5 @@ -22044,7 +22265,7 @@ snapshots: dts-resolver: 2.1.2 get-tsconfig: 4.12.0 magic-string: 0.30.19 - rolldown: 1.0.0-beta.60 + rolldown: 1.0.0-rc.1 optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -22108,24 +22329,24 @@ snapshots: '@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.41 '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.41 - rolldown@1.0.0-beta.60: + rolldown@1.0.0-rc.1: dependencies: - '@oxc-project/types': 0.108.0 - '@rolldown/pluginutils': 1.0.0-beta.60 + '@oxc-project/types': 0.110.0 + '@rolldown/pluginutils': 1.0.0-rc.1 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-beta.60 - '@rolldown/binding-darwin-arm64': 1.0.0-beta.60 - '@rolldown/binding-darwin-x64': 1.0.0-beta.60 - '@rolldown/binding-freebsd-x64': 1.0.0-beta.60 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.60 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.60 - '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.60 - '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.60 - '@rolldown/binding-linux-x64-musl': 1.0.0-beta.60 - '@rolldown/binding-openharmony-arm64': 1.0.0-beta.60 - '@rolldown/binding-wasm32-wasi': 1.0.0-beta.60 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.60 - '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.60 + '@rolldown/binding-android-arm64': 1.0.0-rc.1 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.1 + '@rolldown/binding-darwin-x64': 1.0.0-rc.1 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.1 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.1 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.1 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.1 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.1 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.1 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.1 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.1 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.1 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.1 rollup@4.52.4: dependencies: @@ -22744,6 +22965,8 @@ snapshots: trim-lines@3.0.1: {} + trim-trailing-lines@2.1.0: {} + trough@1.0.5: {} trough@2.2.0: {} @@ -22773,8 +22996,8 @@ snapshots: diff: 8.0.2 empathic: 2.0.0 hookable: 5.5.3 - rolldown: 1.0.0-beta.60 - rolldown-plugin-dts: 0.16.11(rolldown@1.0.0-beta.60)(typescript@5.9.3) + rolldown: 1.0.0-rc.1 + rolldown-plugin-dts: 0.16.11(rolldown@1.0.0-rc.1)(typescript@5.9.3) semver: 7.7.3 tinyexec: 1.0.1 tinyglobby: 0.2.15 @@ -22952,6 +23175,11 @@ snapshots: dependencies: unist-util-is: 4.1.0 + unist-util-find-after@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-is@4.1.0: {} unist-util-is@6.0.1: