diff --git a/apps/docs/.gitignore b/apps/docs/.gitignore new file mode 100644 index 0000000..a0def09 --- /dev/null +++ b/apps/docs/.gitignore @@ -0,0 +1,19 @@ +node_modules + +.DS_Store +.cache +.vercel +.output +.nitro +/build/ +/api/ +/server/build +/public/build +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ +.tanstack + +src/routeTree.gen.ts +.source \ No newline at end of file diff --git a/apps/docs/README.md b/apps/docs/README.md new file mode 100644 index 0000000..108fabd --- /dev/null +++ b/apps/docs/README.md @@ -0,0 +1,14 @@ +# docs + +This is a Tanstack Start application generated with +[Create Fumadocs](https://github.com/fuma-nama/fumadocs). + +Run development server: + +```bash +npm run dev +# or +pnpm dev +# or +yarn dev +``` diff --git a/apps/docs/cli.json b/apps/docs/cli.json new file mode 100644 index 0000000..8a9e336 --- /dev/null +++ b/apps/docs/cli.json @@ -0,0 +1,11 @@ +{ + "aliases": { + "uiDir": "./components/ui", + "componentsDir": "./components", + "blockDir": "./components", + "cssDir": "./styles", + "libDir": "./lib" + }, + "baseDir": "src", + "commands": {} +} \ No newline at end of file diff --git a/apps/docs/content/docs/en/advanced-features.mdx b/apps/docs/content/docs/en/advanced-features.mdx new file mode 100644 index 0000000..aab9842 --- /dev/null +++ b/apps/docs/content/docs/en/advanced-features.mdx @@ -0,0 +1,720 @@ +--- +title: Advanced Features +description: Parallel execution, type safety, error handling, and advanced workflow patterns +icon: Sparkles +--- + +# Advanced Features + +Learn about advanced OpenWorkflow features including parallel execution, TypeScript type safety, error handling, and sophisticated workflow patterns. + +## Parallel Step Execution + +Run multiple steps concurrently using JavaScript's native `Promise.all`: + +### Basic Parallel Execution + +```ts +const workflow = ow.defineWorkflow( + { name: "fetch-user-data" }, + async ({ input, step }) => { + // Execute all three steps in parallel + const [user, subscription, settings] = await Promise.all([ + step.run({ name: "fetch-user" }, async () => { + return await db.users.findOne({ id: input.userId }); + }), + step.run({ name: "fetch-subscription" }, async () => { + return await stripe.subscriptions.retrieve(input.subId); + }), + step.run({ name: "fetch-settings" }, async () => { + return await db.settings.findOne({ userId: input.userId }); + }), + ]); + + return { user, subscription, settings }; + } +); +``` + +### How It Works + +Each step is still memoized individually: + +1. All three steps start executing concurrently +2. Each step creates its own `step_attempt` record with status `running` +3. The worker waits for all to complete +4. If the workflow crashes mid-execution: + - Completed steps return instantly on replay (cached) + - In-flight steps re-execute + +### Nested Parallel Execution + +You can combine sequential and parallel execution: + +```ts +const workflow = ow.defineWorkflow( + { name: "process-order" }, + async ({ input, step }) => { + // Step 1: Validate (sequential) + const validation = await step.run({ name: "validate" }, async () => { + return await validateOrder(input.orderId); + }); + + // Step 2-4: Process in parallel + const [payment, inventory, notification] = await Promise.all([ + step.run({ name: "charge-card" }, async () => { + return await stripe.charges.create({ amount: validation.total }); + }), + step.run({ name: "reserve-inventory" }, async () => { + return await inventory.reserve(input.items); + }), + step.run({ name: "notify-warehouse" }, async () => { + return await warehouse.notify({ orderId: input.orderId }); + }), + ]); + + // Step 5: Finalize (sequential) + const confirmation = await step.run({ name: "confirm" }, async () => { + return await db.orders.update(input.orderId, { status: "confirmed" }); + }); + + return { payment, inventory, notification, confirmation }; + } +); +``` + +### Error Handling in Parallel Steps + +If any step in `Promise.all` fails, the entire workflow fails: + +```ts +try { + const [result1, result2] = await Promise.all([ + step.run({ name: "step-1" }, async () => { + // This might throw + return await riskyOperation(); + }), + step.run({ name: "step-2" }, async () => { + return await safeOperation(); + }), + ]); +} catch (error) { + // Handle the error + await step.run({ name: "cleanup" }, async () => { + await performCleanup(); + }); + throw error; +} +``` + +## Type Safety + +OpenWorkflow provides full TypeScript support with generic type parameters. + +### Typed Workflows + +Define input and output types for compile-time safety: + +```ts +interface ProcessOrderInput { + orderId: string; + userId: string; + items: Array<{ sku: string; quantity: number }>; +} + +interface ProcessOrderOutput { + orderId: string; + paymentId: string; + shipmentId: string; + total: number; +} + +const processOrder = ow.defineWorkflow( + { name: "process-order" }, + async ({ input, step }) => { + // input is typed as ProcessOrderInput + const orderId = input.orderId; // ✅ Type-safe + const invalid = input.invalidField; // ❌ TypeScript error + + // Return type must match ProcessOrderOutput + return { + orderId: input.orderId, + paymentId: "pay_123", + shipmentId: "ship_456", + total: 5000, + // extraField: "invalid" // ❌ TypeScript error + }; + } +); + +// Usage is also type-safe +const run = await processOrder.run({ + orderId: "order_123", + userId: "user_456", + items: [{ sku: "SKU-001", quantity: 2 }], +}); + +const result = await run.result(); +// result is typed as ProcessOrderOutput +console.log(result.paymentId); // ✅ Type-safe +``` + +### Typed Steps + +Step outputs are automatically inferred: + +```ts +const workflow = ow.defineWorkflow( + { name: "typed-steps" }, + async ({ input, step }) => { + // TypeScript infers user: { id: string; email: string } + const user = await step.run({ name: "fetch-user" }, async () => { + return { id: "123", email: "user@example.com" }; + }); + + // Type-safe access + console.log(user.email); // ✅ + console.log(user.invalidField); // ❌ TypeScript error + } +); +``` + +### Reusable Type Definitions + +Create reusable types for common workflows: + +```ts +// types.ts +export interface User { + id: string; + email: string; + name: string; +} + +export interface SendEmailInput { + userId: string; + template: "welcome" | "confirmation" | "reset"; +} + +export interface SendEmailOutput { + emailId: string; + sentAt: string; +} + +// workflow.ts +import { SendEmailInput, SendEmailOutput, User } from "./types"; + +const sendEmail = ow.defineWorkflow( + { name: "send-email" }, + async ({ input, step }) => { + const user = await step.run({ name: "fetch-user" }, async (): Promise => { + return await db.users.findOne({ id: input.userId }); + }); + + const emailId = await step.run({ name: "send" }, async () => { + return await emailService.send({ + to: user.email, + template: input.template, + }); + }); + + return { + emailId, + sentAt: new Date().toISOString(), + }; + } +); +``` + +## Error Handling & Retries + +### Automatic Retries + +When a step throws an error, the entire workflow can be retried automatically with exponential backoff. + +```ts +const workflow = ow.defineWorkflow( + { name: "resilient-api-call" }, + async ({ input, step }) => { + const data = await step.run({ name: "fetch-external-api" }, async () => { + // If this throws, the workflow will retry automatically + return await externalAPI.getData(); + }); + + return data; + } +); +``` + +**How Retries Work:** + +1. Step throws an error +2. Workflow is marked with retry metadata +3. Worker sets `availableAt = NOW() + backoff` +4. Another worker picks it up after the backoff period +5. Workflow replays from the beginning +6. Completed steps return cached results +7. Failed step is re-executed + +### Manual Error Handling + +Handle errors explicitly in your workflow logic: + +```ts +const workflow = ow.defineWorkflow( + { name: "manual-error-handling" }, + async ({ input, step }) => { + try { + const result = await step.run({ name: "risky-operation" }, async () => { + return await riskyAPI.call(); + }); + return { success: true, result }; + } catch (error) { + // Log the error + await step.run({ name: "log-error" }, async () => { + await logger.error("Operation failed", { error }); + }); + + // Attempt fallback + const fallbackResult = await step.run({ name: "fallback" }, async () => { + return await fallbackAPI.call(); + }); + + return { success: true, result: fallbackResult }; + } + } +); +``` + +### Compensating Actions + +Implement compensating actions for cleanup: + +```ts +const workflow = ow.defineWorkflow( + { name: "saga-pattern" }, + async ({ input, step }) => { + // Step 1: Charge payment + const payment = await step.run({ name: "charge" }, async () => { + return await stripe.charges.create({ amount: 5000 }); + }); + + try { + // Step 2: Reserve inventory (might fail) + const inventory = await step.run({ name: "reserve" }, async () => { + return await inventory.reserve(input.items); + }); + + return { payment, inventory }; + } catch (error) { + // Compensating action: Refund payment + await step.run({ name: "refund" }, async () => { + await stripe.refunds.create({ charge: payment.id }); + }); + + throw error; + } + } +); +``` + +### Partial Failure Recovery + +Handle partial failures gracefully: + +```ts +const workflow = ow.defineWorkflow( + { name: "bulk-email" }, + async ({ input, step }) => { + const results = []; + + for (const userId of input.userIds) { + try { + const result = await step.run( + { name: `send-email-${userId}` }, + async () => { + return await emailService.send({ userId }); + } + ); + results.push({ userId, success: true, result }); + } catch (error) { + // Don't fail the entire workflow if one email fails + results.push({ userId, success: false, error }); + } + } + + return { results }; + } +); +``` + +## Sleeping (Pausing) Workflows + +You can pause a workflow until a future time and, because sleeping releases the +worker slot, you can pause thousands of workflows without tying up compute: + +```ts +// Pause for 1 hour (durable, non-blocking) +await step.sleep("wait-one-hour", "1h"); +``` + +The sleep step is memoized after it completes. If the workflow is replayed +again (for example due to a later retry), the completed sleep is not re-applied. + +### Duration Formats + +Durations accept a number followed by a unit: + +| Unit | Aliases | Examples | +| ------------ | --------------------- | ---------------- | +| milliseconds | `ms`, `msec`, `msecs` | `100ms`, `1.5ms` | +| seconds | `s`, `sec`, `secs` | `5s`, `0.25s` | +| minutes | `m`, `min`, `mins` | `2m`, `1.5m` | +| hours | `h`, `hr`, `hrs` | `1h`, `0.25h` | +| days | `d`, `day(s)` | `1d`, `0.5d` | +| weeks | `w`, `week(s)` | `1w`, `2w` | +| months | `mo`, `month(s)` | `1mo`, `2mo` | +| years | `y`, `yr`, `yrs` | `1y`, `2yr` | + +Durations are parsed from strings; see the `DurationString` type in the SDK and +the `duration.test.ts` file for more examples of accepted formats. + +## Workflow Versioning + +Handle code changes safely while workflows are in-flight. + +### The Problem + +Changing step names breaks deterministic replay: + +```ts +// Old code (deployed with in-flight workflows) +await step.run({ name: "old-step-name" }, ...); + +// New code (deployed while old workflows are running) +await step.run({ name: "new-step-name" }, ...); +// ❌ Replay fails: "old-step-name" in history, "new-step-name" in code +``` + +### Solution: Version Parameter + +Use the `version` parameter for conditional logic. Workflows declare an optional +`version` in `defineWorkflow`, and the resolved version is passed into the +handler: + +```ts +const workflow = ow.defineWorkflow( + { name: "versioned-workflow", version: "v2" }, + async ({ input, step, version }) => { + if (version === "v1") { + // Old code path + const data = await step.run({ name: "old-step-name" }, async () => { + return await legacyAPI.getData(); + }); + return { data }; + } else { + // New code path (v2) + const data = await step.run({ name: "new-step-name" }, async () => { + return await newAPI.getData(); + }); + return { data }; + } + } +); +``` + +New workflow runs will use the latest configured version; existing runs can +continue to replay using the version they were created with. + +### Best Practices + +1. **Always version breaking changes**: Step renames, order changes, removals +2. **Keep old versions** until all in-flight workflows complete +3. **Use version constants**: + +```ts +const WORKFLOW_V1 = "v1"; +const WORKFLOW_V2 = "v2"; + +if (version === WORKFLOW_V1) { + // ... +} +``` + +## Waiting for Results + +### Synchronous Wait + +Wait for a workflow to complete: + +```ts +const runHandle = await myWorkflow.run({ userId: "123" }); + +// Blocks until workflow completes (polls database) +const result = await runHandle.result(); +console.log(result); +``` + +### Canceling Workflows + +You can cancel a workflow that is pending, running, or sleeping to prevent it +from continuing to the next step: + +```ts +const handle = await myWorkflow.run({ data: "..." }); + +// Cancel the workflow +await handle.cancel(); +``` + +Canceled workflows transition to a `canceled` status. If a workflow is canceled +while a worker is processing it, the worker will detect the cancelation and stop +execution before committing further progress. + +### Async Fire-and-Forget + +Start a workflow without waiting: + +```ts +app.post("/users/:id/welcome", async (req, res) => { + // Start the workflow + const runHandle = await sendWelcomeEmail.run({ userId: req.params.id }); + + // Return immediately + res.json({ workflowRunId: runHandle.workflowRun.id }); +}); +``` + +### Poll for Status + +Check workflow status manually: + +```ts +const runHandle = await myWorkflow.run({ userId: "123" }); + +// Poll every 5 seconds +const checkStatus = async () => { + const run = await backend.getWorkflowRun({ + workflowRunId: runHandle.workflowRun.id, + }); + + if (run.status === "succeeded") { + console.log("Workflow completed:", run.output); + } else if (run.status === "failed") { + console.error("Workflow failed:", run.error); + } else { + setTimeout(checkStatus, 5000); + } +}; + +checkStatus(); +``` + +## Workflow Deadlines + +Set time limits for workflow completion: + +```ts +const runHandle = await myWorkflow.run( + { userId: "123" }, + { + deadlineAt: new Date(Date.now() + 3600000), // Must complete in 1 hour + } +); +``` + +If the deadline is reached: + +- New steps are skipped +- The workflow is marked as `failed` +- No further retries occur + +**Use Cases:** + +- Time-sensitive operations (e.g., flash sales) +- SLA enforcement +- Resource cleanup + +## Dynamic Workflows + +### Conditional Steps + +Create workflows with conditional logic: + +```ts +const workflow = ow.defineWorkflow( + { name: "conditional-workflow" }, + async ({ input, step }) => { + const user = await step.run({ name: "fetch-user" }, async () => { + return await db.users.findOne({ id: input.userId }); + }); + + if (user.isPremium) { + await step.run({ name: "send-premium-email" }, async () => { + return await email.sendPremium(user); + }); + } else { + await step.run({ name: "send-standard-email" }, async () => { + return await email.sendStandard(user); + }); + } + + return { success: true }; + } +); +``` + +**Important:** Step names must be unique across all branches. Don't use the same step name in multiple branches. + +### Loops + +Iterate over data: + +```ts +const workflow = ow.defineWorkflow( + { name: "bulk-process" }, + async ({ input, step }) => { + const results = []; + + for (let i = 0; i < input.items.length; i++) { + const item = input.items[i]; + + // Use unique step names + const result = await step.run({ name: `process-item-${i}` }, async () => { + return await processItem(item); + }); + + results.push(result); + } + + return { results }; + } +); +``` + +**Caution:** The number of iterations must be deterministic (based on input, not external state). + +## Workflow Context + +Share data across steps without explicit passing: + +```ts +const workflow = ow.defineWorkflow( + { name: "context-example" }, + async ({ input, step }) => { + // Create a context object + const context = { + userId: input.userId, + startTime: new Date().toISOString(), + }; + + const user = await step.run({ name: "fetch-user" }, async () => { + return await db.users.findOne({ id: context.userId }); + }); + + const email = await step.run({ name: "send-email" }, async () => { + return await emailService.send({ + to: user.email, + metadata: { startTime: context.startTime }, + }); + }); + + return { user, email }; + } +); +``` + +## Best Practices + +### ✅ Do + +- **Use descriptive step names**: `fetch-user` not `step1` +- **Keep steps idempotent**: Safe to retry multiple times +- **Handle errors gracefully**: Use try-catch for critical operations +- **Use TypeScript types**: Catch errors at compile-time +- **Test workflow logic**: Unit test individual steps + +### ❌ Don't + +- **Don't use dynamic step names**: `step-${Date.now()}` breaks replay +- **Don't make side effects outside steps**: Database writes, API calls must be in steps +- **Don't rely on external state**: Workflows must be deterministic +- **Don't use very large inputs/outputs**: Keep data reasonable for database storage + +## Performance Tips + +### Minimize Step Count + +Combine related operations: + +```ts +// ❌ Too many steps +const user = await step.run({ name: "fetch-user" }, ...); +const email = await step.run({ name: "get-email" }, () => user.email); +const domain = await step.run({ name: "get-domain" }, () => email.split("@")[1]); + +// ✅ One step +const userData = await step.run({ name: "fetch-user-data" }, async () => { + const user = await db.users.findOne(); + return { + user, + email: user.email, + domain: user.email.split("@")[1], + }; +}); +``` + +### Use Parallel Execution + +Maximize throughput with `Promise.all`: + +```ts +// ❌ Sequential (slow) +const user = await step.run({ name: "user" }, ...); +const settings = await step.run({ name: "settings" }, ...); +const subscription = await step.run({ name: "subscription" }, ...); + +// ✅ Parallel (fast) +const [user, settings, subscription] = await Promise.all([ + step.run({ name: "user" }, ...), + step.run({ name: "settings" }, ...), + step.run({ name: "subscription" }, ...), +]); +``` + +### Optimize Worker Concurrency + +Tune concurrency based on your workload: + +```ts +// Low-latency, many short workflows +const worker = ow.newWorker({ concurrency: 100 }); + +// High-latency, few long workflows +const worker = ow.newWorker({ concurrency: 10 }); +``` + +## Next Steps + + + + + + + diff --git a/apps/docs/content/docs/en/api-reference.mdx b/apps/docs/content/docs/en/api-reference.mdx new file mode 100644 index 0000000..0c994e0 --- /dev/null +++ b/apps/docs/content/docs/en/api-reference.mdx @@ -0,0 +1,723 @@ +--- +title: API Reference +description: Complete API documentation for OpenWorkflow classes, methods, and types +icon: Code +--- + +# API Reference + +Complete API documentation for all OpenWorkflow components. + +## OpenWorkflow Client + +The main client class for defining workflows and creating workers. + +### Constructor + +```ts +constructor(options: OpenWorkflowOptions) +``` + +Creates a new OpenWorkflow client instance. + +**Parameters:** + +- `options.backend` (`Backend`) - The backend implementation to use (e.g., `BackendPostgres`) + +**Example:** + + + + +```ts +import { OpenWorkflow } from "openworkflow"; +import { BackendPostgres } from "@openworkflow/backend-postgres"; + +const backend = await BackendPostgres.connect(process.env.DATABASE_URL); +const ow = new OpenWorkflow({ backend }); +``` + + + + +### Methods + +#### `defineWorkflow()` + +```ts +defineWorkflow( + config: WorkflowDefinitionConfig, + fn: WorkflowFunction +): WorkflowDefinition +``` + +Defines and registers a new workflow. + +**Type Parameters:** + +- `Input` - The type of the workflow input +- `Output` - The type of the workflow output + +**Parameters:** + +- `config.name` (`string`) - The unique name of the workflow +- `fn` - The workflow function that defines the workflow's logic + +**Returns:** + +A `WorkflowDefinition` instance that can be used to start workflow runs. + +**Example:** + + + + +```ts +const myWorkflow = ow.defineWorkflow( + { name: "my-workflow" }, + async ({ input, step }) => { + return { result: "done" }; + } +); +``` + + + + +#### `newWorker()` + +```ts +newWorker(options?: WorkerOptions): Worker +``` + +Creates a new worker with this client's backend and registered workflows. + +**Parameters:** + +- `options.concurrency` (`number`, optional) - Maximum number of concurrent workflow executions (default: 1) + +**Returns:** + +A `Worker` instance. + +**Example:** + + + + +```ts +const worker = ow.newWorker({ concurrency: 10 }); +await worker.start(); +``` + + + + +## WorkflowDefinition + +Represents a defined workflow that can be started. + +### Properties + +- `name` (`string`, readonly) - The workflow's name +- `fn` (`WorkflowFunction`, readonly) - The workflow function + +### Methods + +#### `run()` + +```ts +run( + input?: Input, + options?: WorkflowRunOptions +): Promise> +``` + +Starts a new workflow run. + +**Parameters:** + +- `input` (`Input`, optional) - The input data for the workflow +- `options` (`WorkflowRunOptions`, optional) - Configuration options + - `deadlineAt` (`Date`, optional) - Deadline for workflow completion + +**Returns:** + +A `WorkflowRunHandle` that can be used to wait for the result. + +**Example:** + +```ts +// Fire and forget +const runHandle = await myWorkflow.run({ userId: "123" }); + +// With deadline +const runHandle = await myWorkflow.run( + { userId: "123" }, + { deadlineAt: new Date(Date.now() + 3600000) } // 1 hour +); + +// Wait for result +const result = await runHandle.result(); +``` + +## WorkflowRunHandle + +Represents a started workflow run. Returned from `workflowDef.run()`. + +### Properties + +- `workflowRun` (`WorkflowRun`, readonly) - The workflow run record from the backend + +### Methods + +#### `result()` + +```ts +result(): Promise +``` + +Waits for the workflow run to complete and returns its result. Polls the database until the workflow reaches a terminal state (such as `succeeded`, `failed`, or `canceled`). + +**Returns:** + +The workflow's output value. + +**Throws:** + +- `Error` if the workflow fails +- `Error` if the workflow is canceled +- `Error` if the result times out (default: 5 minutes) + +**Example:** + +```ts +const runHandle = await myWorkflow.run({ userId: "123" }); +const result = await runHandle.result(); +console.log(result); // { userId: "123", ... } +``` + +## WorkflowFunction + +The function signature for defining workflow logic. + +### Type + +```ts +type WorkflowFunction = ( + params: WorkflowFunctionParams +) => Promise | Output +``` + +**Parameters:** + +- `params.input` (`Input`) - The input data passed to the workflow +- `params.step` (`StepApi`) - The step API for creating checkpoints + +**Returns:** + +The workflow's output (can be synchronous or asynchronous). + +**Example:** + +```ts +const workflow = ow.defineWorkflow( + { name: "my-workflow" }, + async ({ input, step }) => { + // Use input + const userId = input.userId; + + // Create steps + const user = await step.run({ name: "fetch-user" }, async () => { + return await db.users.findOne({ id: userId }); + }); + + return { user }; + } +); +``` + +## StepApi + +The API for defining steps within a workflow. + +### Methods + +#### `run()` + +```ts +run( + config: StepFunctionConfig, + fn: StepFunction +): Promise +``` + +Executes a step with memoization. If the step has already been completed in a previous execution, returns the cached result without re-executing the function. + +**Type Parameters:** + +- `Output` - The type of the step's return value + +**Parameters:** + +- `config.name` (`string`) - The unique name of the step within the workflow +- `fn` (`StepFunction`) - The function to execute + +**Returns:** + +The step's output value. + +**Example:** + +```ts +const result = await step.run({ name: "fetch-data" }, async () => { + return await api.getData(); +}); +``` + +**Important Rules:** + +- Step names must be unique within a workflow +- Step names must be deterministic (no `step-${Date.now()}`) +- Step functions should be idempotent when possible +- Steps execute synchronously in the worker + +#### `sleep()` + +```ts +sleep(name: string, duration: DurationString): Promise +``` + +Pauses the workflow until a specified time in the future. When encountered, the +worker marks the workflow run as `sleeping`, sets its `availableAt` to the +resume time, and releases the worker slot. When the sleep completes, the +workflow can be picked up by any worker and resumes execution from after the +sleep. + +The `duration` parameter is a parsed duration string. See **DurationString** and +the “Sleeping (Pausing) Workflows” section for accepted formats. + +## StepFunction + +The function signature for step logic. + +### Type + +```ts +type StepFunction = () => + | Promise + | Output + | undefined +``` + +**Returns:** + +The step's output (can be synchronous or asynchronous, can be `undefined`). + +**Example:** + +```ts +// Async step +await step.run({ name: "async-step" }, async () => { + return await someAsyncWork(); +}); + +// Sync step +await step.run({ name: "sync-step" }, () => { + return someValue; +}); + +// Void step +await step.run({ name: "void-step" }, async () => { + await doSomething(); + // returns undefined (converted to null) +}); +``` + +## Worker + +The execution engine that polls for and executes workflows. + +### Constructor + +```ts +constructor(options: WorkerOptions) +``` + +**Parameters:** + +- `options.backend` (`Backend`) - The backend to poll +- `options.workflows` (`WorkflowDefinition[]`) - The workflows to execute +- `options.concurrency` (`number`, optional) - Maximum concurrent executions (default: 1) + +**Note:** Typically created using `ow.newWorker()` instead of directly constructing. + +### Methods + +#### `start()` + +```ts +start(): Promise +``` + +Starts the worker. It begins polling for and executing workflows. + +**Example:** + +```ts +await worker.start(); +console.log("Worker is running"); +``` + +#### `stop()` + +```ts +stop(): Promise +``` + +Stops the worker gracefully. Waits for all active workflow runs to complete before returning. + +**Example:** + +```ts +await worker.stop(); +console.log("Worker stopped"); +``` + +**Graceful Shutdown Pattern:** + +```ts +process.on("SIGTERM", async () => { + await worker.stop(); + await backend.stop(); + process.exit(0); +}); +``` + +#### `tick()` + +```ts +tick(): Promise +``` + +Processes one round of work claims and execution. Primarily used for testing. + +**Returns:** + +The number of workflow runs claimed. + +## Backend Interface + +The interface that all backend implementations must implement. + +### Methods + +#### Workflow Run Methods + +```ts +createWorkflowRun(params: CreateWorkflowRunParams): Promise +getWorkflowRun(params: GetWorkflowRunParams): Promise +claimWorkflowRun(params: ClaimWorkflowRunParams): Promise +heartbeatWorkflowRun(params: HeartbeatWorkflowRunParams): Promise +sleepWorkflowRun(params: SleepWorkflowRunParams): Promise +markWorkflowRunSucceeded(params: MarkWorkflowRunSucceededParams): Promise +markWorkflowRunFailed(params: MarkWorkflowRunFailedParams): Promise +cancelWorkflowRun(params: CancelWorkflowRunParams): Promise +``` + +#### Step Attempt Methods + +```ts +listStepAttempts(params: ListStepAttemptsParams): Promise +createStepAttempt(params: CreateStepAttemptParams): Promise +getStepAttempt(params: GetStepAttemptParams): Promise +markStepAttemptSucceeded(params: MarkStepAttemptSucceededParams): Promise +markStepAttemptFailed(params: MarkStepAttemptFailedParams): Promise +``` + +## BackendPostgres + +PostgreSQL implementation of the Backend interface. + +### Static Methods + +#### `connect()` + +```ts +static connect( + connectionString: string, + options?: BackendPostgresOptions +): Promise +``` + +Connects to a PostgreSQL database and creates the necessary tables if they don't exist. + +**Parameters:** + +- `connectionString` (`string`) - PostgreSQL connection URL +- `options.namespaceId` (`string`, optional) - Namespace for isolating workflows (default: "default") + +**Returns:** + +A connected `BackendPostgres` instance. + +**Example:** + +```ts +import { BackendPostgres } from "@openworkflow/backend-postgres"; + +const backend = await BackendPostgres.connect( + "postgresql://user:pass@localhost:5432/db", + { namespaceId: "production" } +); +``` + +### Methods + +#### `stop()` + +```ts +stop(): Promise +``` + +Closes the database connection pool. + +**Example:** + +```ts +await backend.stop(); +``` + +## Types + +### WorkflowRun + +Represents a workflow run record from the backend. + +```ts +interface WorkflowRun { + namespaceId: string; + id: string; + workflowName: string; + version: string | null; + status: "pending" | "running" | "sleeping" | "succeeded" | "failed" | "canceled"; + workerId: string | null; + idempotencyKey: string | null; + config: JsonValue; + context: JsonValue | null; + input: JsonValue | null; + output: JsonValue | null; + error: JsonValue | null; + attempts: number; + availableAt: Date | null; + deadlineAt: Date | null; + createdAt: Date; + startedAt: Date | null; + finishedAt: Date | null; + updatedAt: Date; +} +``` + +### StepAttempt + +Represents a step attempt record from the backend. + +```ts +interface StepAttempt { + namespaceId: string; + id: string; + workflowRunId: string; + stepName: string; + kind: StepKind; + status: "running" | "succeeded" | "failed"; + config: JsonValue; + context: StepAttemptContext | null; + output: JsonValue | null; + error: JsonValue | null; + childWorkflowRunNamespaceId: string | null; + childWorkflowRunId: string | null; + startedAt: Date | null; + finishedAt: Date | null; + createdAt: Date; + updatedAt: Date; +} +``` + +### StepKind + +The type of step. + +```ts +type StepKind = "function" | "sleep" +``` + +`"function"` corresponds to steps created with `step.run()`, and `"sleep"` +corresponds to durable sleep steps created with `step.sleep()`. + +### DurationString + +Type for duration strings accepted by `step.sleep`: + +```ts +type DurationString = string; // e.g. "5s", "1h", "2d" +``` + +Durations accept a number followed by a unit like `ms`, `s`, `m`, `h`, `d`, +`w`, `mo`, or `y`. See the “Sleeping (Pausing) Workflows” docs and the +`duration.test.ts` file for concrete examples. + +### JsonValue + +Type for JSON-serializable values. + +```ts +type JsonPrimitive = string | number | boolean | null; +type JsonValue = + | JsonPrimitive + | JsonValue[] + | { [key: string]: JsonValue }; +``` + +All workflow inputs, outputs, and step results must be JSON-serializable. + +## Usage Examples + +### Basic Workflow + +```ts +import { OpenWorkflow } from "openworkflow"; +import { BackendPostgres } from "@openworkflow/backend-postgres"; + +const backend = await BackendPostgres.connect(process.env.DATABASE_URL); +const ow = new OpenWorkflow({ backend }); + +const greet = ow.defineWorkflow( + { name: "greet" }, + async ({ input, step }) => { + const greeting = await step.run({ name: "generate" }, () => { + return `Hello, ${input.name}!`; + }); + return { greeting }; + } +); + +const worker = ow.newWorker(); +await worker.start(); + +const result = await greet.run({ name: "Alice" }); +console.log(await result.result()); // { greeting: "Hello, Alice!" } +``` + +### Typed Workflow + +```ts +interface SendEmailInput { + userId: string; + subject: string; +} + +interface SendEmailOutput { + emailId: string; + sentAt: Date; +} + +const sendEmail = ow.defineWorkflow( + { name: "send-email" }, + async ({ input, step }) => { + const user = await step.run({ name: "fetch-user" }, async () => { + return await db.users.findOne({ id: input.userId }); + }); + + const emailId = await step.run({ name: "send" }, async () => { + return await emailService.send({ + to: user.email, + subject: input.subject, + }); + }); + + return { emailId, sentAt: new Date() }; + } +); +``` + +### Parallel Steps + +```ts +const workflow = ow.defineWorkflow( + { name: "parallel-example" }, + async ({ input, step }) => { + const [user, settings, subscription] = await Promise.all([ + step.run({ name: "user" }, () => db.users.findOne()), + step.run({ name: "settings" }, () => db.settings.findOne()), + step.run({ name: "subscription" }, () => stripe.subscriptions.retrieve()), + ]); + + return { user, settings, subscription }; + } +); +``` + +### Error Handling + +```ts +const workflow = ow.defineWorkflow( + { name: "with-error-handling" }, + async ({ input, step }) => { + try { + const result = await step.run({ name: "risky-operation" }, async () => { + return await riskyAPI.call(); + }); + return { success: true, result }; + } catch (error) { + // Handle the error + await step.run({ name: "log-error" }, async () => { + await logger.error(error); + }); + throw error; // Re-throw to mark workflow as failed + } + } +); +``` + +## Constants + +### Default Values + +```ts +// Client +DEFAULT_RESULT_POLL_INTERVAL_MS = 1000 // 1 second +DEFAULT_RESULT_TIMEOUT_MS = 300000 // 5 minutes + +// Worker +DEFAULT_LEASE_DURATION_MS = 30000 // 30 seconds +DEFAULT_POLL_INTERVAL_MS = 100 // 100ms +DEFAULT_CONCURRENCY = 1 + +// Backend +DEFAULT_NAMESPACE_ID = "default" +``` + +## Next Steps + + + + + + + diff --git a/apps/docs/content/docs/en/architecture.mdx b/apps/docs/content/docs/en/architecture.mdx new file mode 100644 index 0000000..b2748fe --- /dev/null +++ b/apps/docs/content/docs/en/architecture.mdx @@ -0,0 +1,745 @@ +--- +title: Architecture +description: Deep dive into OpenWorkflow's execution model, state machine replication, and worker-driven architecture +icon: Network +--- + +# Architecture + +This document provides a deep dive into how OpenWorkflow works under the hood, covering the worker-driven architecture, deterministic replay model, and state management. + +## System Architecture Overview + +OpenWorkflow uses a **worker-driven model** where the database is the central point of coordination. There is no separate orchestrator server. + +### Architecture Diagram + +``` ++---------------------------------+ +--------------------------------+ +| | | | +| Your Application Code | | OpenWorkflow Worker | +| (e.g., a web server) | | (Separate Process) | +| | | | +| +---------------------------+ | | +---------------------------+ | +| | OpenWorkflow Client | | | | Workflow Definitions | | +| | (Creates Workflow Runs) | | | | | | +| +---------------------------+ | | +---------------------------+ | +| | | | | | ++---------------+-----------------+ +---------------+----------------+ + | | + | +------------------------+ | + +--| Backend Interface |--+ + | (e.g., Postgres) | + +------------------------+ + | + | + +------------------------------+ + | | + | Backend Storage | + | | + | - workflow_runs | + | - step_attempts | + +------------------------------+ +``` + +### Core Components + +#### Client + +The entry point for applications to interact with OpenWorkflow. Responsibilities: + +- Creating new workflow runs +- Writing to the `workflow_runs` table +- Providing the `defineWorkflow()` API +- Creating workers + +#### Worker + +The execution engine that runs workflow code. Responsibilities: + +- Polling the backend for available workflows +- Claiming workflows atomically +- Executing workflow code using deterministic replay +- Managing concurrency pools +- Heartbeating to maintain leases +- Handling errors and retries + +#### Backend + +The source of truth for all workflow state. Responsibilities: + +- Storing workflow runs and step attempts +- Serving as the job queue (via `availableAt` timestamps) +- Providing atomic claim operations +- Enabling memoization through step history + +## The Execution Model: State Machine Replication + + +OpenWorkflow treats each workflow run as a **state machine**. The worker's job is to advance the state of that machine from its last known checkpoint to the next one. + + +### The Replay Loop + +When a worker claims a workflow run, it **always executes the code from the beginning**. This is the core of the deterministic replay model. + + + + +```ts +// A worker claims a workflow run. +// It loads the step history and begins execution. + +const user = await step.run({ name: "fetch-user" }, async () => { + // 1. The framework sees "fetch-user". + // 2. It finds a completed result in the history. + // 3. It returns the cached output immediately without executing the function. + return await db.users.findOne({ id: 1 }); +}); + +const welcomeEmail = await step.run({ name: "welcome-email" }, async () => { + // 4. The framework sees "welcome-email". + // 5. It is NOT in the history. + // 6. It creates a step_attempt with status "running". + // 7. It executes the function and saves the result. + // 8. It updates the step_attempt to status "succeeded" and continues. + return await email.send(user); +}); +``` + + + + +### Why Replay? + +The replay model provides several key benefits: + +1. **Durability**: Workflows can resume from any point by replaying from the start +2. **Simplicity**: No complex state machine definitions needed +3. **Debuggability**: Workflow code looks like normal async code +4. **Flexibility**: Easy to add new steps or modify logic + +### Replay Guarantees + +During replay: + +- **Completed steps** return their cached result instantly (no re-execution) +- **Failed steps** can be retried with new attempts +- **New steps** execute normally and are added to the history +- **Step order** must remain consistent (determinism requirement) + +## Basic Execution Flow + +Here's what happens when you run a workflow: + + + + + +### Workflow Registration + +Workflows are defined in code. When a worker starts, it automatically discovers and registers workflows in an in-memory map: + + + + +```ts +const ow = new OpenWorkflow({ backend }); + +// This registers the workflow in the client's registry +const myWorkflow = ow.defineWorkflow({ name: "my-workflow" }, async ({ step }) => { + // ... +}); + +// The worker inherits the registered workflows +const worker = ow.newWorker(); +``` + + + + +There is no sync process with an external server. + + + + + +### Workflow Invocation + +Your application code uses the **Client** to start a new workflow run: + + + + +```ts +const runHandle = await myWorkflow.run({ userId: "123" }); +``` + + + + +This creates a new entry in the `workflow_runs` table: + +```sql +INSERT INTO workflow_runs ( + id, + workflow_name, + status, + available_at, + input +) VALUES ( + 'run_abc123', + 'my-workflow', + 'pending', + NOW(), + '{"userId":"123"}' +); +``` + + + + + +### Job Polling + +A **Worker** process polls the `workflow_runs` table, looking for runs whose +`available_at` timestamp is in the past and whose status indicates that work is +ready to be done (for example, newly created work, completed sleeps, or runs +with an expired lease). A simplified version of this pattern looks like: + +```sql +SELECT * FROM workflow_runs +WHERE available_at <= NOW() +ORDER BY available_at ASC +LIMIT 1 +FOR UPDATE SKIP LOCKED; +``` + +The worker then updates the claimed run to mark it as `running` and extend its +lease: + +```sql +UPDATE workflow_runs +SET status = 'running', + worker_id = 'worker_xyz', + available_at = NOW() + INTERVAL '30 seconds' +WHERE id = 'run_abc123'; +``` + + + + + +### Code Execution (Replay Loop) + +The worker loads the history of completed `step_attempts` for the claimed workflow run: + +```sql +SELECT * FROM step_attempts +WHERE workflow_run_id = 'run_abc123' +ORDER BY created_at ASC; +``` + +It then executes the workflow code **from the beginning**, using the history to memoize results: + + + + +```ts +async function executeWorkflow(workflowRun, stepHistory) { + // Create a step API that checks the history + const step = { + run: async (config, fn) => { + const historyEntry = stepHistory.find(s => s.step_name === config.name); + + if (historyEntry && historyEntry.status === 'succeeded') { + // Return cached result + return historyEntry.output; + } + + // Execute the step + const stepAttempt = await backend.createStepAttempt({ + workflowRunId: workflowRun.id, + stepName: config.name, + status: 'running', + }); + + const result = await fn(); + + await backend.markStepAttemptSucceeded({ + stepAttemptId: stepAttempt.id, + output: result, + }); + + return result; + }, + }; + + // Execute the workflow function + return await workflowDefinition.fn({ input: workflowRun.input, step }); +} +``` + + + + + + + + +### Step Processing + +When the worker encounters a **new step** (not in history): + +1. **Create** a `step_attempt` record with status `running` +2. **Execute** the step function inline +3. **Update** the `step_attempt` to `succeeded` or `failed` + +All steps execute **synchronously** within the worker. There is no async queueing of steps. + + + + + +### State Update + +After each step, the worker updates the backend. When the workflow completes: + +```sql +UPDATE workflow_runs +SET status = 'succeeded', + output = '{"result":"done"}', + completed_at = NOW() +WHERE id = 'run_abc123'; +``` + + + + + +## The `availableAt` Mechanism + + +The `availableAt` timestamp is the **core of OpenWorkflow's fault tolerance**. It enables scheduling, heartbeating, crash recovery, and retry backoff—all with a single database field. + + +It serves multiple purposes: + +### Scheduling + +Workflows can be scheduled for future execution by setting `available_at` in +the future. Internally, OpenWorkflow uses this for features like durable +sleeping (`step.sleep`) and retry backoff. + +### Heartbeating + +When a worker claims a workflow, it sets: + +``` +availableAt = NOW() + leaseDuration (e.g., 30 seconds) +``` + +The worker must periodically update this timestamp to maintain its lease: + +```sql +UPDATE workflow_runs +SET available_at = NOW() + INTERVAL '30 seconds' +WHERE id = 'run_abc123' + AND worker_id = 'worker_xyz'; +``` + +### Crash Recovery + +If a worker crashes: + +1. Heartbeats **stop** +2. The `availableAt` timestamp **expires** +3. The workflow becomes **visible** to other workers' polling queries +4. Another worker **claims** it and **resumes** from the last completed step + +This provides automatic fault tolerance without manual intervention or external monitoring. + +### Retry Backoff + +Failed workflows can be retried with exponential backoff: + +```sql +UPDATE workflow_runs +SET status = 'pending', + available_at = NOW() + INTERVAL '2 seconds' -- Exponential backoff +WHERE id = 'run_abc123'; +``` + +## Step Execution Details + +### Synchronous Execution + +All steps execute **synchronously** within the worker's event loop: + +```ts +const result1 = await step.run({ name: "step-1" }, async () => { + // This runs inline, blocking the workflow execution + return await apiCall(); +}); + +const result2 = await step.run({ name: "step-2" }, async () => { + // This runs after step-1 completes + return await anotherApiCall(); +}); +``` + +### Sleeping Steps + +In addition to regular function steps, workflows can use durable sleeps to pause +execution until a future time without tying up a worker slot: + +```ts +// Pause for 1 hour (durable, non-blocking) +await step.sleep("wait-one-hour", "1h"); +``` + +When the worker encounters `step.sleep`: + +1. It marks the `workflow_run` as `sleeping` +2. It sets `available_at` to the wake-up time +3. It releases the workflow so other work can run + +When `available_at` is reached, another worker will claim the run and resume +execution after the sleep. + +### High Concurrency + +Workers can be configured with high concurrency limits (e.g., 100) to handle many workflow runs simultaneously: + +```ts +const worker = ow.newWorker({ concurrency: 100 }); +``` + +Each workflow occupies a concurrency slot for its entire execution. This is acceptable because: + +- Workers have high concurrency capacity +- Most workflows are I/O-bound +- The model is simple to reason about + +### Parallel Steps + +Use `Promise.all` for parallel execution: + +```ts +const [user, settings, subscription] = await Promise.all([ + step.run({ name: "fetch-user" }, async () => await db.users.findOne()), + step.run({ name: "fetch-settings" }, async () => await db.settings.findOne()), + step.run({ name: "fetch-sub" }, async () => await stripe.subscriptions.retrieve()), +]); +``` + +The worker executes all steps concurrently and waits for all to complete. Each step is persisted individually as a `step_attempt`. + +## Error Handling & Retries + +### Step Failures + +When a step throws an error: + +1. The `step_attempt` is marked as `failed` +2. The error is stored in the `step_attempt` +3. The error propagates up to the workflow level + +### Workflow Failures + +When a workflow fails: + +1. The `workflow_run` is marked as `failed` (or retried) +2. The error is stored in the `workflow_run` +3. The workflow can be retried with exponential backoff + +### Retry Logic + +Workflows can be retried automatically: + +```ts +// Future API (not yet implemented) +const myWorkflow = ow.defineWorkflow( + { + name: "my-workflow", + retry: { maxAttempts: 3, backoff: "exponential" } + }, + async ({ input, step }) => { + // ... + } +); +``` + +On retry: + +1. The workflow status is reset to `pending` +2. The `availableAt` is set to `NOW() + backoff` +3. A new worker claims and executes the workflow +4. Completed steps return cached results +5. Failed steps are re-executed + +### Deadlines + +Workflows can have optional deadlines: + +```ts +await myWorkflow.run( + { userId: "123" }, + { deadlineAt: new Date(Date.now() + 3600000) } // Must complete in 1 hour +); +``` + +If the deadline is reached: + +- New steps are skipped +- The workflow is marked as `failed` +- No further retries occur + +### Workflow Cancelation + +Workflows can also be explicitly canceled via the Client API: + +```ts +const handle = await myWorkflow.run({ userId: "123" }); + +// Later on, cancel the workflow +await handle.cancel(); +``` + +If a workflow is canceled while a worker is executing it, the worker will detect +the cancelation, stop further execution, and mark the run as `canceled`. This +prevents partially executed work from being committed as a successful result. + +## Concurrency & Parallelism + +### Workflow Concurrency + +Workers maintain a concurrency pool: + +```ts +const worker = ow.newWorker({ concurrency: 10 }); +``` + +The worker will: + +- Maintain up to 10 in-flight workflow runs simultaneously +- Poll for new work only when slots are available +- Execute workflows in parallel using async/await + +### Database Concurrency + +Multiple workers can poll the same table concurrently: + +```sql +FOR UPDATE SKIP LOCKED +``` + +This SQL feature ensures: + +- No two workers claim the same workflow +- Workers don't block each other +- Claims are atomic and race-free + +### Handling Crashes During Parallel Execution + +If a worker crashes while executing parallel steps: + +1. Its heartbeat stops +2. The `availableAt` for the workflow run expires +3. Another worker claims it +4. The new worker replays the workflow: + - Completed steps return cached results + - In-flight steps are re-executed + +## Versioning + +### The Challenge + +If workflow code is changed while runs are in-flight, deterministic replay can break: + +```ts +// Old code +await step.run({ name: "old-step-name" }, ...); + +// New code (deployed while runs are in-flight) +await step.run({ name: "new-step-name" }, ...); +``` + +The replaying worker fails because `old-step-name` is in the history but `new-step-name` is in the code. + +### Code-Based Versioning + +Workflows receive a `version` parameter for conditional logic: + +```ts +const workflow = ow.defineWorkflow( + { name: "versioned-workflow", version: "v2" }, + async ({ step, version }) => { + if (version === "v1") { + await step.run({ name: "old-step-name" }, ...); + } else { + await step.run({ name: "new-step-name" }, ...); + } + } +); +``` + +This enables: + +- **Zero-downtime deploys**: Old runs replay on v1, new runs use v2 +- **Gradual rollout**: Version can be set per run +- **Rollback safety**: Old code can still replay old runs + +## Workers Deep Dive + +### Worker Responsibilities + +1. **Polling**: Continuously query the backend for available workflows +2. **Claiming**: Atomically claim workflows using `FOR UPDATE SKIP LOCKED` +3. **Executing**: Run workflow code using the deterministic replay model +4. **Heartbeating**: Periodically update `availableAt` to maintain the lease +5. **Error Handling**: Catch errors, mark workflows as failed, and implement retries +6. **Graceful Shutdown**: Wait for active workflows to complete before exiting + +### The Polling Loop + +```ts +async function runLoop() { + while (this.running) { + const availableSlots = this.concurrency - this.activeExecutions.size; + + if (availableSlots > 0) { + // Claim and process workflows for each available slot + for (let i = 0; i < availableSlots; i++) { + const workflowRun = await this.backend.claimWorkflowRun({ + workerId: this.workerId, + leaseDurationMs: 30000, + }); + + if (workflowRun) { + this.executeWorkflowInBackground(workflowRun); + } + } + } + + await sleep(100); // Poll interval + } +} +``` + +### Graceful Shutdown + +When a worker receives `SIGTERM`: + +1. **Stop polling**: Set `running = false` +2. **Wait for active executions**: `while (activeExecutions.size > 0) await sleep(100)` +3. **Exit**: `process.exit(0)` + +This ensures no work is lost during deploys. + +## Database Schema + +### `workflow_runs` Table + +```sql +CREATE TABLE workflow_runs ( + id UUID PRIMARY KEY, + workflow_name TEXT NOT NULL, + version TEXT, + status TEXT NOT NULL, -- 'pending' | 'running' | 'sleeping' | 'succeeded' | 'failed' | 'canceled' + worker_id TEXT, + input JSONB, + output JSONB, + config JSONB, + context JSONB, + available_at TIMESTAMP NOT NULL, + deadline_at TIMESTAMP, + created_at TIMESTAMP NOT NULL DEFAULT NOW(), + completed_at TIMESTAMP +); + +CREATE INDEX idx_workflow_runs_available ON workflow_runs (available_at) + WHERE status = 'pending'; +``` + +### `step_attempts` Table + +```sql +CREATE TABLE step_attempts ( + id UUID PRIMARY KEY, + workflow_run_id UUID NOT NULL REFERENCES workflow_runs(id), + step_name TEXT NOT NULL, + kind TEXT NOT NULL, + status TEXT NOT NULL, -- 'running' | 'succeeded' | 'failed' + config JSONB, + context JSONB, + output JSONB, + error JSONB, + created_at TIMESTAMP NOT NULL DEFAULT NOW(), + completed_at TIMESTAMP +); + +CREATE INDEX idx_step_attempts_workflow_run ON step_attempts (workflow_run_id); +``` + +## Performance Characteristics + +### Latency + +- **Workflow start**: 1 database write (~1-5ms) +- **Worker claim**: 1 database query + 1 update (~2-10ms) +- **Step execution**: 2 database writes per step (~2-10ms) + +### Throughput + +- **Single worker**: 100-1000 workflows/sec (depending on workflow complexity) +- **Multiple workers**: Scales linearly with worker count + +### Scaling Strategies + +1. **Increase worker concurrency**: `concurrency: 100` +2. **Add more workers**: Run multiple worker processes +3. **Optimize database**: Add indexes, use connection pooling +4. **Reduce step count**: Combine related operations + +## Comparison to Other Systems + +### vs. Temporal + +- **OpenWorkflow**: Worker-driven, no separate server, database as queue +- **Temporal**: Server-driven, separate history service, gRPC communication + +### vs. Inngest + +- **OpenWorkflow**: Self-hosted, PostgreSQL backend, open-source +- **Inngest**: Cloud-hosted, managed service, proprietary + +### vs. BullMQ + +- **OpenWorkflow**: Workflow orchestration with steps and memoization +- **BullMQ**: Job queue with retries but no built-in workflow concepts + +## Next Steps + + + + + + + diff --git a/apps/docs/content/docs/en/backend-postgres.mdx b/apps/docs/content/docs/en/backend-postgres.mdx new file mode 100644 index 0000000..00ae635 --- /dev/null +++ b/apps/docs/content/docs/en/backend-postgres.mdx @@ -0,0 +1,521 @@ +--- +title: PostgreSQL Backend +description: Learn about the PostgreSQL backend for OpenWorkflow +icon: Database +--- + +# PostgreSQL Backend + +The PostgreSQL backend is the default persistence layer for OpenWorkflow, providing durable storage for workflow runs and step attempts. + +## Overview + +The `@openworkflow/backend-postgres` package implements the OpenWorkflow `Backend` interface using PostgreSQL as the underlying database. + +### Features + +- **Durable Storage**: All workflow state persisted to PostgreSQL +- **Atomic Operations**: Uses `FOR UPDATE SKIP LOCKED` for race-free workflow claiming +- **Automatic Migrations**: Creates tables automatically on first connection +- **Namespace Support**: Isolate workflows by environment (dev, staging, prod) +- **Connection Pooling**: Built-in connection pool management +- **Type-Safe**: Full TypeScript support + +## Installation + +```bash +npm install @openworkflow/backend-postgres +``` + +The backend requires PostgreSQL 12 or higher. + +## Connection + +### Basic Connection + +```ts +import { BackendPostgres } from "@openworkflow/backend-postgres"; + +const backend = await BackendPostgres.connect( + "postgresql://username:password@localhost:5432/database" +); +``` + +### With Options + +```ts +const backend = await BackendPostgres.connect( + process.env.DATABASE_URL!, + { + namespaceId: "production", // Isolate workflows by namespace + } +); +``` + +### Connection String Format + +``` +postgresql://[username]:[password]@[hostname]:[port]/[database]?[options] +``` + +**Examples:** + +``` +postgresql://postgres:postgres@localhost:5432/postgres +postgresql://user:pass@db.example.com:5432/myapp +postgresql://user:pass@localhost:5432/db?sslmode=require +``` + +### Environment Variables + +Store connection strings in environment variables: + +```bash +export DATABASE_URL="postgresql://postgres:postgres@localhost:5432/postgres" +``` + +```ts +const backend = await BackendPostgres.connect(process.env.DATABASE_URL!); +``` + +## Database Schema + +The backend automatically creates two tables on first connection. + +### `workflow_runs` Table + +Stores workflow execution state and serves as the job queue. + +```sql +CREATE TABLE workflow_runs ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + namespace_id TEXT NOT NULL DEFAULT 'default', + workflow_name TEXT NOT NULL, + version TEXT, + status TEXT NOT NULL, + worker_id TEXT, + config JSONB NOT NULL DEFAULT '{}', + context JSONB, + input JSONB, + output JSONB, + error JSONB, + available_at TIMESTAMPTZ NOT NULL, + deadline_at TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + completed_at TIMESTAMPTZ +); + +-- Index for efficient polling +CREATE INDEX idx_workflow_runs_available +ON workflow_runs (namespace_id, available_at) +WHERE status = 'pending'; + +-- Index for namespace lookups +CREATE INDEX idx_workflow_runs_namespace +ON workflow_runs (namespace_id, workflow_name, created_at DESC); +``` + +**Columns:** + +- `id`: Unique workflow run identifier (UUID) +- `namespace_id`: Namespace for isolation (default: "default") +- `workflow_name`: Name of the workflow definition +- `version`: Workflow version (for versioning support) +- `status`: Current status (`pending`, `running`, `succeeded`, `failed`) +- `worker_id`: ID of the worker currently executing the workflow +- `config`: Workflow configuration (JSONB) +- `context`: Additional context data (JSONB) +- `input`: Workflow input data (JSONB) +- `output`: Workflow result (JSONB, null until completed) +- `error`: Error information if failed (JSONB) +- `available_at`: Timestamp when workflow becomes available to workers +- `deadline_at`: Optional deadline for workflow completion +- `created_at`: When the workflow run was created +- `completed_at`: When the workflow finished + +### `step_attempts` Table + +Stores individual step execution results, enabling memoization. + +```sql +CREATE TABLE step_attempts ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + workflow_run_id UUID NOT NULL REFERENCES workflow_runs(id) ON DELETE CASCADE, + step_name TEXT NOT NULL, + kind TEXT NOT NULL, + status TEXT NOT NULL, + config JSONB NOT NULL DEFAULT '{}', + context JSONB, + output JSONB, + error JSONB, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + completed_at TIMESTAMPTZ +); + +-- Index for loading step history +CREATE INDEX idx_step_attempts_workflow_run +ON step_attempts (workflow_run_id, created_at); +``` + +**Columns:** + +- `id`: Unique step attempt identifier (UUID) +- `workflow_run_id`: Foreign key to `workflow_runs` +- `step_name`: Name of the step (from `step.run({ name: "..." })`) +- `kind`: Type of step (currently only `"run"`) +- `status`: Current status (`running`, `succeeded`, `failed`) +- `config`: Step configuration (JSONB) +- `context`: Additional context data (JSONB) +- `output`: Step result (JSONB, null until completed) +- `error`: Error information if failed (JSONB) +- `created_at`: When the step started +- `completed_at`: When the step finished + +## Namespaces + +Namespaces allow you to isolate workflows by environment or tenant. + +### Use Cases + +- **Environment Isolation**: Separate dev, staging, and production workflows +- **Multi-Tenancy**: Isolate workflows per customer/organization +- **Testing**: Create isolated namespaces for tests + +### Creating Namespaced Backends + +```ts +// Production +const prodBackend = await BackendPostgres.connect( + process.env.DATABASE_URL!, + { namespaceId: "production" } +); + +// Staging +const stagingBackend = await BackendPostgres.connect( + process.env.DATABASE_URL!, + { namespaceId: "staging" } +); + +// Development +const devBackend = await BackendPostgres.connect( + process.env.DATABASE_URL!, + { namespaceId: "development" } +); +``` + +Each namespace operates independently: + +- Workers only see workflows in their namespace +- Workflow runs don't interfere across namespaces +- Same database, logical separation + +### Default Namespace + +If you don't specify a namespace, the default is `"default"`: + +```ts +const backend = await BackendPostgres.connect(process.env.DATABASE_URL!); +// Equivalent to: { namespaceId: "default" } +``` + +## Connection Management + +### Connection Pooling + +The backend uses connection pooling automatically: + +```ts +const backend = await BackendPostgres.connect(connectionString); + +// The backend maintains a pool of connections +// No manual pool configuration needed +``` + +### Closing Connections + +Always close the backend when your application shuts down: + +```ts +await backend.stop(); +``` + +**Example with Graceful Shutdown:** + +```ts +const backend = await BackendPostgres.connect(process.env.DATABASE_URL!); +const ow = new OpenWorkflow({ backend }); +const worker = ow.newWorker(); + +await worker.start(); + +process.on("SIGTERM", async () => { + console.log("Shutting down gracefully..."); + await worker.stop(); + await backend.stop(); + process.exit(0); +}); +``` + +## Querying Workflows + +You can query workflow runs directly using SQL: + +### Get All Pending Workflows + +```sql +SELECT * FROM workflow_runs +WHERE status = 'pending' +ORDER BY created_at DESC; +``` + +### Get Workflows by Name + +```sql +SELECT * FROM workflow_runs +WHERE workflow_name = 'send-welcome-email' +ORDER BY created_at DESC +LIMIT 100; +``` + +### Get Failed Workflows + +```sql +SELECT * FROM workflow_runs +WHERE status = 'failed' +ORDER BY completed_at DESC; +``` + +### Get Workflow with Step History + +```sql +SELECT + wr.*, + json_agg( + json_build_object( + 'stepName', sa.step_name, + 'status', sa.status, + 'output', sa.output, + 'createdAt', sa.created_at + ) ORDER BY sa.created_at + ) AS steps +FROM workflow_runs wr +LEFT JOIN step_attempts sa ON sa.workflow_run_id = wr.id +WHERE wr.id = 'your-workflow-run-id' +GROUP BY wr.id; +``` + +## Performance Considerations + +### Indexes + +The default schema includes indexes for common queries: + +- `idx_workflow_runs_available`: Fast polling for pending workflows +- `idx_workflow_runs_namespace`: Namespace and workflow name lookups +- `idx_step_attempts_workflow_run`: Loading step history + +### Additional Indexes + +For high-volume production use, consider adding: + +```sql +-- Index for status filtering +CREATE INDEX idx_workflow_runs_status +ON workflow_runs (namespace_id, status, created_at DESC); + +-- Index for worker queries +CREATE INDEX idx_workflow_runs_worker +ON workflow_runs (worker_id, status); +``` + +### Connection Pool Sizing + +For production, use a database connection pool: + +```bash +postgresql://user:pass@localhost:5432/db?pool_size=20 +``` + +### Database Sizing + +Estimate storage requirements: + +- **Workflow runs**: ~1-5 KB per run (depending on input/output size) +- **Step attempts**: ~500 bytes - 2 KB per step + +For 1 million workflow runs with 10 steps each: + +- Workflows: ~5 GB +- Steps: ~20 GB +- Total: ~25 GB + +### Cleanup + +Implement a cleanup strategy for old workflow runs: + +```sql +-- Delete succeeded workflows older than 30 days +DELETE FROM workflow_runs +WHERE status = 'succeeded' + AND completed_at < NOW() - INTERVAL '30 days'; + +-- Step attempts are automatically deleted via CASCADE +``` + +## Troubleshooting + +### Connection Errors + +**Issue:** `ECONNREFUSED` or connection timeout + +**Solutions:** + +1. Verify PostgreSQL is running: + ```bash + psql -U postgres -h localhost + ``` + +2. Check connection string format +3. Verify firewall rules +4. Check PostgreSQL `pg_hba.conf` for authentication settings + +### Migration Errors + +**Issue:** Tables already exist + +The backend creates tables automatically. If you see errors: + +1. Ensure the database user has `CREATE TABLE` permissions +2. Drop existing tables if schema changed: + ```sql + DROP TABLE step_attempts; + DROP TABLE workflow_runs; + ``` + +### Performance Issues + +**Issue:** Slow workflow polling + +**Solutions:** + +1. Verify indexes exist: + ```sql + \d workflow_runs + ``` + +2. Analyze query performance: + ```sql + EXPLAIN ANALYZE + SELECT * FROM workflow_runs + WHERE status = 'pending' + AND available_at <= NOW() + ORDER BY available_at ASC + LIMIT 1; + ``` + +3. Increase worker poll interval: + ```ts + // This is internal, but reduce workers if polling too aggressively + const worker = ow.newWorker({ concurrency: 5 }); // Lower concurrency + ``` + +### Lock Contention + +**Issue:** Workers blocking each other + +PostgreSQL's `SKIP LOCKED` prevents this, but if you see issues: + +1. Ensure you're using PostgreSQL 9.5+ +2. Check for long-running transactions +3. Monitor with: + ```sql + SELECT * FROM pg_stat_activity WHERE state = 'active'; + ``` + +## Docker Setup + +### Development + +Use Docker for local development: + +```bash +docker run -d \ + --name openworkflow-postgres \ + -e POSTGRES_PASSWORD=postgres \ + -e POSTGRES_DB=openworkflow \ + -p 5432:5432 \ + postgres:16 +``` + +Connect with: + +```ts +const backend = await BackendPostgres.connect( + "postgresql://postgres:postgres@localhost:5432/openworkflow" +); +``` + +### Production + +Use Docker Compose for production-like setup: + +```yaml +version: "3.8" + +services: + postgres: + image: postgres:16 + environment: + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: openworkflow + volumes: + - postgres-data:/var/lib/postgresql/data + ports: + - "5432:5432" + +volumes: + postgres-data: +``` + +## Best Practices + +### ✅ Do + +- Use environment variables for connection strings +- Close connections on shutdown (`await backend.stop()`) +- Use namespaces for environment isolation +- Monitor database size and implement cleanup +- Use connection pooling in production +- Set appropriate `pg_hba.conf` rules for security + +### ❌ Don't + +- Don't hardcode connection strings +- Don't share backends across isolated services +- Don't manually modify `workflow_runs` or `step_attempts` unless necessary +- Don't forget to clean up old workflow data + +## Next Steps + + + + + + + diff --git a/apps/docs/content/docs/en/core-concepts.mdx b/apps/docs/content/docs/en/core-concepts.mdx new file mode 100644 index 0000000..dd3db5b --- /dev/null +++ b/apps/docs/content/docs/en/core-concepts.mdx @@ -0,0 +1,589 @@ +--- +title: Core Concepts +description: Understanding workflows, steps, workers, and the execution model in OpenWorkflow +icon: BookOpen +--- + +# Core Concepts + +This guide explains the fundamental concepts that power OpenWorkflow: workflows, steps, workers, backends, and the execution model. + +## Workflows + +A **workflow** is a durable function that orchestrates multiple steps. Workflows can: + +- Make external API calls +- Query databases +- Perform complex business logic +- Pause and resume across process restarts +- Run for seconds, minutes, hours, or even days + +### Defining a Workflow + + + + +```ts +const myWorkflow = ow.defineWorkflow( + { name: "my-workflow" }, + async ({ input, step }) => { + // Your workflow logic here + return result; + }, +); +``` + + + + +### Workflow Properties + +- **Durable**: Survives crashes, restarts, and deploys +- **Deterministic**: Must produce the same result given the same input +- **Resumable**: Continues from the last completed step after interruption +- **Versioned**: Can be versioned to handle code changes safely + +### The Workflow Function + +The workflow function receives a context object with: + +- `input`: The input data passed when starting the workflow +- `step`: The step API for creating checkpoints +- `version`: The workflow version (for versioning support) + + + + +```ts +async ({ input, step, version }) => { + // Access input + const userId = input.userId; + + // Create steps + const user = await step.run({ name: "fetch-user" }, async () => { + return await db.users.findOne({ id: userId }); + }); + + return { user }; +} +``` + + + + +## Steps + +**Steps** are the building blocks of workflows. Each step represents a checkpoint in your workflow's execution. + +### Why Steps Matter + + +Without steps, crashes can cause duplicate charges, double emails, or data inconsistencies. + + +Imagine this scenario without steps: + + + + +```ts +// ⚠️ Without steps - dangerous! +const workflow = async ({ input }) => { + await stripe.charges.create({ amount: 1000 }); // Charge customer + await email.send({ to: user.email }); // Send confirmation +}; +``` + + + + +If the worker crashes after charging the customer, the workflow retries from the beginning and charges them twice! + + +Steps provide automatic memoization, ensuring each operation executes exactly once. + + +With steps: + + + + +```ts +// ✅ With steps - safe! +const workflow = async ({ input, step }) => { + await step.run({ name: "charge" }, async () => { + return await stripe.charges.create({ amount: 1000 }); + }); + + await step.run({ name: "send-email" }, async () => { + return await email.send({ to: user.email }); + }); +}; +``` + + + + +Now if the worker crashes after the charge, the retry skips the charge step (cached) and goes straight to sending the email. + +### Step Execution + +Each step: + +1. **Creates a record** in the database with status `running` +2. **Executes the function** synchronously +3. **Stores the result** in the database +4. **Updates status** to `succeeded` or `failed` + +### Step Memoization + +When a workflow replays (after a crash or restart): + +- **Completed steps** return their cached result instantly without re-execution +- **New steps** execute normally and are added to the history +- **Failed steps** re-execute with retry logic + +### The `step.run()` API + + + + +```ts +const result = await step.run( + { name: "step-name" }, + async () => { + // This function runs once + // If the workflow restarts, this returns the cached result + return await someWork(); + } +); +``` + + + + + +- Step names must be **unique** within a workflow +- Step names must be **deterministic** (no dynamic names like `step-${Date.now()}`) +- Step functions should be **idempotent** when possible +- Steps execute **synchronously** in the worker + + +## Workers + +**Workers** are long-running processes that execute workflows. They are the execution engine of OpenWorkflow. + +### Worker Responsibilities + +Workers are responsible for: + +- **Polling** the backend for pending workflows +- **Claiming** workflow runs using atomic database operations +- **Executing** workflow code using deterministic replay +- **Heartbeating** to maintain their claim on active runs +- **Managing concurrency** to process multiple workflows simultaneously +- **Handling errors** and implementing retry logic + +### Creating and Starting a Worker + + + + +```ts +const worker = ow.newWorker({ concurrency: 10 }); +await worker.start(); +``` + + + + +### Worker Concurrency + +The `concurrency` option controls how many workflows a worker can execute simultaneously: + +```ts +const worker = ow.newWorker({ concurrency: 20 }); +``` + +- Each workflow occupies one concurrency slot +- Higher concurrency = more workflows processed in parallel +- Start with `10` and adjust based on your workload +- Multiple workers can run simultaneously for scale + +### Worker Lifecycle + +```ts +// Start the worker +await worker.start(); +console.log("Worker is running"); + +// Stop gracefully (waits for active workflows to complete) +await worker.stop(); +console.log("Worker stopped"); +``` + +### Graceful Shutdown + +Workers support graceful shutdown to prevent data loss during deploys: + +```ts +process.on("SIGTERM", async () => { + console.log("Received SIGTERM, shutting down gracefully..."); + await worker.stop(); // Waits for in-flight workflows + await backend.stop(); + process.exit(0); +}); +``` + +When `stop()` is called: + +1. Worker **stops polling** for new workflows +2. Worker **waits** for all active workflows to complete +3. Worker **exits** cleanly + +### Heartbeats and Fault Tolerance + +Workers maintain their claim on workflows through **heartbeats**: + +1. When a worker claims a workflow, it sets `availableAt = NOW() + leaseDuration` +2. The worker periodically updates this timestamp (heartbeat) +3. If a worker crashes, heartbeats stop +4. The `availableAt` timestamp expires +5. Another worker can now claim the workflow and resume it + +This mechanism provides automatic crash recovery without manual intervention. + +## Backend + +The **backend** is the persistence layer that stores all workflow state. It serves two purposes: + +1. **Job queue**: Workers poll the backend for pending workflows +2. **State store**: All workflow runs and step attempts are persisted + +### Backend Interface + +OpenWorkflow defines a `Backend` interface that can be implemented for different databases: + +```ts +interface Backend { + // Workflow Runs + createWorkflowRun(params: CreateWorkflowRunParams): Promise; + getWorkflowRun(params: GetWorkflowRunParams): Promise; + claimWorkflowRun(params: ClaimWorkflowRunParams): Promise; + heartbeatWorkflowRun(params: HeartbeatWorkflowRunParams): Promise; + markWorkflowRunSucceeded(params: MarkWorkflowRunSucceededParams): Promise; + markWorkflowRunFailed(params: MarkWorkflowRunFailedParams): Promise; + + // Step Attempts + listStepAttempts(params: ListStepAttemptsParams): Promise; + createStepAttempt(params: CreateStepAttemptParams): Promise; + markStepAttemptSucceeded(params: MarkStepAttemptSucceededParams): Promise; + markStepAttemptFailed(params: MarkStepAttemptFailedParams): Promise; +} +``` + +### PostgreSQL Backend + +Currently, OpenWorkflow supports PostgreSQL: + +```ts +import { BackendPostgres } from "@openworkflow/backend-postgres"; + +const backend = await BackendPostgres.connect( + "postgresql://user:pass@localhost:5432/db" +); +``` + +The backend automatically creates two tables: + +- `workflow_runs`: Stores workflow execution state +- `step_attempts`: Stores individual step results + +### Database as Queue + +The database serves as a distributed queue using atomic operations: + +```sql +-- Workers claim workflows atomically +SELECT * FROM workflow_runs +WHERE status = 'pending' + AND available_at <= NOW() +ORDER BY available_at ASC +LIMIT 1 +FOR UPDATE SKIP LOCKED; +``` + +This ensures: + +- No two workers claim the same workflow +- Workers can poll concurrently without conflicts +- Failed workers release their claims automatically (via heartbeat timeout) + +## Client + +The **OpenWorkflow client** is the entry point for defining workflows and creating workflow runs. + +### Creating a Client + +```ts +import { OpenWorkflow } from "openworkflow"; +import { BackendPostgres } from "@openworkflow/backend-postgres"; + +const backend = await BackendPostgres.connect(process.env.DATABASE_URL!); +const ow = new OpenWorkflow({ backend }); +``` + +### Defining Workflows + +```ts +const myWorkflow = ow.defineWorkflow( + { name: "my-workflow" }, + async ({ input, step }) => { + return { result: "done" }; + }, +); +``` + +### Running Workflows + +```ts +// Start a workflow run +const runHandle = await myWorkflow.run({ userId: "123" }); + +// Get the workflow run ID +console.log(runHandle.workflowRun.id); + +// Wait for the result (optional) +const result = await runHandle.result(); +``` + +### Creating Workers + +The client can create workers that have access to all registered workflows: + +```ts +const worker = ow.newWorker({ concurrency: 10 }); +await worker.start(); +``` + +## Workflow Run Lifecycle + +A workflow run progresses through several states: + +### Statuses + +| Status | Description | +|--------|-------------| +| `pending` | Workflow created, waiting for a worker to claim it | +| `running` | Worker is actively executing the workflow | +| `sleeping` | Workflow is paused until a future time (`step.sleep`) | +| `succeeded` | Workflow completed successfully | +| `failed` | Workflow failed and all retries exhausted | +| `canceled` | Workflow was explicitly canceled and will not continue | + +### Lifecycle Flow + +``` +pending → running → sleeping → running → succeeded + ↘ failed + ↘ canceled +``` + +### Transitions + +1. **Create**: Your app creates a workflow run → status: `pending` +2. **Claim**: A worker claims the run → status: `running` +3. **Execute**: Worker executes steps +4. **Complete**: + - Success → status: `succeeded` + - Failure → status: `failed` + - Canceled → status: `canceled` + +### The `availableAt` Timestamp + +The `availableAt` field controls when a workflow is visible to workers: + +- **Immediate execution**: `availableAt = NOW()` +- **Delayed execution**: `availableAt = NOW() + delay` +- **Retry backoff**: `availableAt = NOW() + exponentialBackoff` +- **Heartbeat**: `availableAt = NOW() + leaseDuration` + - **Sleep wake-up**: `availableAt = resumeTime` when a workflow calls `step.sleep` + +This single field enables: + +- Scheduling +- Retries with backoff +- Heartbeat mechanism +- Crash recovery + +## Step Attempt Lifecycle + +Step attempts have their own lifecycle: + +### Statuses + +| Status | Description | +|--------|-------------| +| `running` | Step is currently executing | +| `succeeded` | Step completed successfully | +| `failed` | Step execution failed | + +### Lifecycle Flow + +``` +running → succeeded + ↘ failed +``` + +## Deterministic Replay + +OpenWorkflow uses **deterministic replay** to achieve durability: + +### The Replay Model + +When a worker claims a workflow: + +1. **Load history**: Fetch all completed step attempts +2. **Execute from start**: Run the workflow function from the beginning +3. **Memoize steps**: Return cached results for completed steps +4. **Execute new steps**: Run new steps and persist results +5. **Continue**: Repeat until workflow completes + +### Example + + + + +```ts +const workflow = async ({ input, step }) => { + // First execution: runs and caches result + const user = await step.run({ name: "fetch-user" }, async () => { + return await db.users.findOne({ id: input.userId }); + }); + + // [Worker crashes here] + + // Second execution (replay): returns cached result instantly + const user = await step.run({ name: "fetch-user" }, async () => { + return await db.users.findOne({ id: input.userId }); + }); + + // New step: executes normally + await step.run({ name: "send-email" }, async () => { + return await email.send({ to: user.email }); + }); +}; +``` + + + + +### Why Deterministic? + +Workflows must be deterministic because: + +- The same input must produce the same execution path +- Step names must appear in the same order on replay +- Side effects must only occur in steps (not in workflow code) + +### Rules for Deterministic Workflows + + +- Put all side effects inside `step.run()` +- Use deterministic step names +- Use the input to make decisions +- Use step results to make decisions + + + +- Use `Date.now()` or `Math.random()` outside of steps +- Make API calls outside of steps +- Use dynamic step names like `step-${Date.now()}` +- Change step order based on external state + + +## Workflow Organization + +Organize your workflows in separate files for better maintainability: + + + + + + + + + + + + + + +## Putting It All Together + +Here's how all the concepts work together: + + + + +```ts +// 1. Set up the client with a backend +const backend = await BackendPostgres.connect(process.env.DATABASE_URL!); +const ow = new OpenWorkflow({ backend }); + +// 2. Define a workflow with steps +const processOrder = ow.defineWorkflow( + { name: "process-order" }, + async ({ input, step }) => { + // Each step is a checkpoint + const payment = await step.run({ name: "charge-card" }, async () => { + return await stripe.charges.create({ amount: input.amount }); + }); + + const shipment = await step.run({ name: "ship-order" }, async () => { + return await shipping.create({ orderId: input.orderId }); + }); + + return { payment, shipment }; + }, +); + +// 3. Start a worker to execute workflows +const worker = ow.newWorker({ concurrency: 10 }); +await worker.start(); + +// 4. Run the workflow from your app +const run = await processOrder.run({ orderId: "123", amount: 5000 }); + +// 5. Optionally wait for the result +const result = await run.result(); +console.log(result); // { payment: {...}, shipment: {...} } +``` + + + + +## Next Steps + + + + + + + diff --git a/apps/docs/content/docs/en/examples.mdx b/apps/docs/content/docs/en/examples.mdx new file mode 100644 index 0000000..1824e2d --- /dev/null +++ b/apps/docs/content/docs/en/examples.mdx @@ -0,0 +1,719 @@ +--- +title: Examples +description: Real-world OpenWorkflow examples and patterns +icon: Code2 +--- + +# Examples + +Real-world examples demonstrating common patterns and use cases with OpenWorkflow. + +## Basic Examples + +### Hello World + +The simplest possible workflow: + + + + +```ts +import { BackendPostgres } from "@openworkflow/backend-postgres"; +import { OpenWorkflow } from "openworkflow"; + +const backend = await BackendPostgres.connect(process.env.DATABASE_URL!); +const ow = new OpenWorkflow({ backend }); + +const helloWorld = ow.defineWorkflow( + { name: "hello-world" }, + async ({ input, step }) => { + const greeting = await step.run({ name: "greet" }, () => { + return `Hello, ${input.name}!`; + }); + + return { greeting }; + } +); + +// Start worker +const worker = ow.newWorker(); +await worker.start(); + +// Run workflow +const run = await helloWorld.run({ name: "World" }); +const result = await run.result(); +console.log(result.greeting); // "Hello, World!" +``` + + + + +### Send Welcome Email + +A common use case: sending a welcome email to new users. + + + + +```ts +interface SendWelcomeEmailInput { + userId: string; +} + +const sendWelcomeEmail = ow.defineWorkflow( + { name: "send-welcome-email" }, + async ({ input, step }) => { + // Step 1: Fetch user from database + const user = await step.run({ name: "fetch-user" }, async () => { + return await db.users.findOne({ id: input.userId }); + }); + + // Step 2: Send email + await step.run({ name: "send-email" }, async () => { + return await emailService.send({ + to: user.email, + subject: "Welcome to our platform!", + template: "welcome", + data: { name: user.name }, + }); + }); + + // Step 3: Mark email as sent + await step.run({ name: "mark-sent" }, async () => { + await db.users.update(input.userId, { welcomeEmailSent: true }); + }); + + return { success: true }; + } +); + +// Trigger from API route +app.post("/users", async (req, res) => { + const user = await db.users.create(req.body); + + // Start workflow asynchronously + await sendWelcomeEmail.run({ userId: user.id }); + + res.json({ user }); +}); +``` + + + + +## E-commerce Examples + + +These examples demonstrate critical patterns like parallel execution, compensating transactions, and idempotent payment processing. + + +### Process Order + +Complete order processing workflow with payment, inventory, and notifications. + +```ts +interface ProcessOrderInput { + orderId: string; + userId: string; + items: Array<{ sku: string; quantity: number; price: number }>; +} + +interface ProcessOrderOutput { + orderId: string; + paymentId: string; + shipmentId: string; + total: number; +} + +const processOrder = ow.defineWorkflow( + { name: "process-order" }, + async ({ input, step }) => { + // Step 1: Calculate total + const total = await step.run({ name: "calculate-total" }, () => { + return input.items.reduce((sum, item) => sum + item.price * item.quantity, 0); + }); + + // Step 2: Charge payment + const payment = await step.run({ name: "charge-payment" }, async () => { + return await stripe.charges.create({ + amount: total, + currency: "usd", + customer: input.userId, + }); + }); + + // Step 3-5: Parallel operations + const [inventory, shipment, notification] = await Promise.all([ + // Reserve inventory + step.run({ name: "reserve-inventory" }, async () => { + return await inventory.reserve(input.items); + }), + + // Create shipment + step.run({ name: "create-shipment" }, async () => { + return await shipping.createShipment({ + orderId: input.orderId, + items: input.items, + }); + }), + + // Send confirmation email + step.run({ name: "send-confirmation" }, async () => { + const user = await db.users.findOne({ id: input.userId }); + return await email.send({ + to: user.email, + template: "order-confirmation", + data: { orderId: input.orderId, total }, + }); + }), + ]); + + // Step 6: Update order status + await step.run({ name: "update-order" }, async () => { + await db.orders.update(input.orderId, { + status: "confirmed", + paymentId: payment.id, + shipmentId: shipment.id, + }); + }); + + return { + orderId: input.orderId, + paymentId: payment.id, + shipmentId: shipment.id, + total, + }; + } +); +``` + +### Abandoned Cart Recovery + +Send reminder emails to users with abandoned carts. + +```ts +interface AbandonedCartInput { + userId: string; + cartId: string; +} + +const abandonedCartRecovery = ow.defineWorkflow( + { name: "abandoned-cart-recovery" }, + async ({ input, step }) => { + // Wait 1 hour (schedule workflow for future execution) + // This would require scheduling support (coming soon) + + // Step 1: Check if cart still exists + const cart = await step.run({ name: "check-cart" }, async () => { + return await db.carts.findOne({ id: input.cartId }); + }); + + if (!cart || cart.items.length === 0) { + return { emailSent: false }; + } + + // Step 2: Get user + const user = await step.run({ name: "fetch-user" }, async () => { + return await db.users.findOne({ id: input.userId }); + }); + + // Step 3: Send reminder email + await step.run({ name: "send-reminder" }, async () => { + return await email.send({ + to: user.email, + template: "abandoned-cart", + data: { + items: cart.items, + total: cart.total, + checkoutUrl: `https://example.com/checkout/${cart.id}`, + }, + }); + }); + + return { emailSent: true }; + } +); +``` + +## API Integration Examples + +### Sync User Data + +Synchronize user data with external services. + +```ts +interface SyncUserDataInput { + userId: string; +} + +const syncUserData = ow.defineWorkflow( + { name: "sync-user-data" }, + async ({ input, step }) => { + // Fetch user + const user = await step.run({ name: "fetch-user" }, async () => { + return await db.users.findOne({ id: input.userId }); + }); + + // Sync to multiple services in parallel + const [hubspot, salesforce, segment] = await Promise.all([ + step.run({ name: "sync-hubspot" }, async () => { + return await hubspot.contacts.create({ + email: user.email, + firstName: user.firstName, + lastName: user.lastName, + }); + }), + + step.run({ name: "sync-salesforce" }, async () => { + return await salesforce.leads.create({ + Email: user.email, + FirstName: user.firstName, + LastName: user.lastName, + }); + }), + + step.run({ name: "sync-segment" }, async () => { + return await segment.identify({ + userId: user.id, + traits: { + email: user.email, + name: `${user.firstName} ${user.lastName}`, + }, + }); + }), + ]); + + return { synced: ["hubspot", "salesforce", "segment"] }; + } +); +``` + +### Webhook Processing + +Process incoming webhooks reliably. + +```ts +interface ProcessWebhookInput { + webhookId: string; + provider: string; + payload: any; +} + +const processWebhook = ow.defineWorkflow( + { name: "process-webhook" }, + async ({ input, step }) => { + // Step 1: Verify webhook signature + const verified = await step.run({ name: "verify-signature" }, async () => { + return await webhookService.verify(input.provider, input.payload); + }); + + if (!verified) { + throw new Error("Invalid webhook signature"); + } + + // Step 2: Parse webhook data + const data = await step.run({ name: "parse-webhook" }, () => { + return webhookService.parse(input.provider, input.payload); + }); + + // Step 3: Update database + await step.run({ name: "update-database" }, async () => { + await db[data.entity].update(data.id, data.updates); + }); + + // Step 4: Trigger downstream actions + await step.run({ name: "trigger-actions" }, async () => { + if (data.event === "payment.succeeded") { + await sendReceiptEmail.run({ paymentId: data.id }); + } + }); + + return { processed: true }; + } +); + +// API endpoint +app.post("/webhooks/:provider", async (req, res) => { + const webhookId = randomUUID(); + + // Start workflow + await processWebhook.run({ + webhookId, + provider: req.params.provider, + payload: req.body, + }); + + res.status(200).json({ received: true }); +}); +``` + +## Data Processing Examples + +### ETL Pipeline + +Extract, transform, and load data. + +```ts +interface ETLInput { + sourceTable: string; + targetTable: string; + batchSize: number; +} + +const etlPipeline = ow.defineWorkflow( + { name: "etl-pipeline" }, + async ({ input, step }) => { + // Step 1: Extract data + const records = await step.run({ name: "extract" }, async () => { + return await sourceDB.query( + `SELECT * FROM ${input.sourceTable} WHERE processed = false LIMIT ${input.batchSize}` + ); + }); + + if (records.length === 0) { + return { recordsProcessed: 0 }; + } + + // Step 2: Transform data + const transformed = await step.run({ name: "transform" }, () => { + return records.map(record => ({ + ...record, + fullName: `${record.firstName} ${record.lastName}`, + processedAt: new Date().toISOString(), + })); + }); + + // Step 3: Load data + await step.run({ name: "load" }, async () => { + await targetDB.batchInsert(input.targetTable, transformed); + }); + + // Step 4: Mark as processed + await step.run({ name: "mark-processed" }, async () => { + const ids = records.map(r => r.id); + await sourceDB.query( + `UPDATE ${input.sourceTable} SET processed = true WHERE id IN (${ids.join(",")})` + ); + }); + + return { recordsProcessed: records.length }; + } +); + +// Run ETL job +const batchSize = 1000; +let totalProcessed = 0; + +while (true) { + const run = await etlPipeline.run({ + sourceTable: "users", + targetTable: "users_warehouse", + batchSize, + }); + + const result = await run.result(); + totalProcessed += result.recordsProcessed; + + if (result.recordsProcessed < batchSize) { + break; // All records processed + } +} + +console.log(`Processed ${totalProcessed} records`); +``` + +### Report Generation + +Generate and email reports. + +```ts +interface GenerateReportInput { + reportType: "daily" | "weekly" | "monthly"; + recipientEmail: string; + dateRange: { start: string; end: string }; +} + +const generateReport = ow.defineWorkflow( + { name: "generate-report" }, + async ({ input, step }) => { + // Step 1: Fetch data + const data = await step.run({ name: "fetch-data" }, async () => { + return await analytics.query({ + type: input.reportType, + startDate: input.dateRange.start, + endDate: input.dateRange.end, + }); + }); + + // Step 2: Generate PDF + const reportUrl = await step.run({ name: "generate-pdf" }, async () => { + const pdf = await pdfGenerator.create({ + template: input.reportType, + data, + }); + + return await s3.upload(`reports/${Date.now()}.pdf`, pdf); + }); + + // Step 3: Send email + await step.run({ name: "send-email" }, async () => { + return await email.send({ + to: input.recipientEmail, + subject: `${input.reportType} Report`, + template: "report", + attachments: [{ url: reportUrl }], + }); + }); + + return { reportUrl }; + } +); + +// Schedule reports (using cron or scheduler) +import cron from "node-cron"; + +cron.schedule("0 9 * * *", async () => { + // Daily report at 9 AM + await generateReport.run({ + reportType: "daily", + recipientEmail: "team@example.com", + dateRange: { + start: new Date(Date.now() - 86400000).toISOString(), // Yesterday + end: new Date().toISOString(), // Today + }, + }); +}); +``` + +## Error Handling Examples + + +OpenWorkflow automatically retries failed steps with exponential backoff. Use try-catch blocks for custom error handling and compensating transactions. + + +### Retry with Exponential Backoff + +Handle transient failures with retries. + +```ts +const resilientAPICall = ow.defineWorkflow( + { name: "resilient-api-call" }, + async ({ input, step }) => { + const result = await step.run({ name: "api-call" }, async () => { + // This will automatically retry with exponential backoff if it fails + return await externalAPI.getData(input.id); + }); + + return result; + } +); +``` + +### Compensating Transaction (Saga Pattern) + + +The saga pattern uses compensating transactions to rollback distributed operations when failures occur. This is critical for maintaining consistency across services. + + +Implement compensating actions for distributed transactions. + +```ts +const bookTrip = ow.defineWorkflow( + { name: "book-trip" }, + async ({ input, step }) => { + let flightBooking, hotelBooking, carRental; + + try { + // Step 1: Book flight + flightBooking = await step.run({ name: "book-flight" }, async () => { + return await flights.book({ + from: input.origin, + to: input.destination, + date: input.date, + }); + }); + + // Step 2: Book hotel + hotelBooking = await step.run({ name: "book-hotel" }, async () => { + return await hotels.book({ + location: input.destination, + checkIn: input.date, + nights: input.nights, + }); + }); + + // Step 3: Rent car (might fail) + carRental = await step.run({ name: "rent-car" }, async () => { + return await cars.rent({ + location: input.destination, + date: input.date, + }); + }); + + return { flightBooking, hotelBooking, carRental }; + } catch (error) { + // Compensating actions (rollback) + if (hotelBooking) { + await step.run({ name: "cancel-hotel" }, async () => { + await hotels.cancel(hotelBooking.id); + }); + } + + if (flightBooking) { + await step.run({ name: "cancel-flight" }, async () => { + await flights.cancel(flightBooking.id); + }); + } + + throw error; + } + } +); +``` + +### Graceful Degradation + +Fall back to alternative approaches when operations fail. + +```ts +const fetchUserProfile = ow.defineWorkflow( + { name: "fetch-user-profile" }, + async ({ input, step }) => { + try { + // Try primary data source + const profile = await step.run({ name: "fetch-from-api" }, async () => { + return await primaryAPI.getUser(input.userId); + }); + return { profile, source: "primary" }; + } catch (error) { + // Fall back to cache + const cachedProfile = await step.run({ name: "fetch-from-cache" }, async () => { + return await cache.get(`user:${input.userId}`); + }); + + if (cachedProfile) { + return { profile: cachedProfile, source: "cache" }; + } + + // Fall back to database + const dbProfile = await step.run({ name: "fetch-from-db" }, async () => { + return await db.users.findOne({ id: input.userId }); + }); + + return { profile: dbProfile, source: "database" }; + } + } +); +``` + +## Testing Workflows + + +Test workflows at multiple levels: unit tests for individual steps, integration tests for complete workflows, and end-to-end tests for critical business flows. + + +### Example Test Structure + + + + + + + + + + + + + + + + + +### Unit Testing Steps + +Test individual workflow steps: + +```ts +import { describe, it, expect } from "vitest"; + +describe("sendWelcomeEmail workflow", () => { + it("should fetch user", async () => { + const user = await db.users.findOne({ id: "test-user" }); + expect(user).toBeDefined(); + expect(user.email).toBe("test@example.com"); + }); + + it("should send email", async () => { + const result = await emailService.send({ + to: "test@example.com", + subject: "Welcome", + template: "welcome", + }); + expect(result.success).toBe(true); + }); +}); +``` + +### Integration Testing + +Test complete workflows: + +```ts +import { describe, it, expect, beforeEach, afterEach } from "vitest"; + +describe("processOrder workflow", () => { + let backend, ow, worker; + + beforeEach(async () => { + backend = await BackendPostgres.connect(process.env.TEST_DATABASE_URL!); + ow = new OpenWorkflow({ backend }); + worker = ow.newWorker(); + await worker.start(); + }); + + afterEach(async () => { + await worker.stop(); + await backend.stop(); + }); + + it("should process order successfully", async () => { + const run = await processOrder.run({ + orderId: "test-order", + userId: "test-user", + items: [{ sku: "SKU-001", quantity: 1, price: 1000 }], + }); + + const result = await run.result(); + + expect(result.paymentId).toBeDefined(); + expect(result.shipmentId).toBeDefined(); + expect(result.total).toBe(1000); + }); +}); +``` + +## Next Steps + + + + + + + diff --git a/apps/docs/content/docs/en/getting-started.mdx b/apps/docs/content/docs/en/getting-started.mdx new file mode 100644 index 0000000..65180aa --- /dev/null +++ b/apps/docs/content/docs/en/getting-started.mdx @@ -0,0 +1,434 @@ +--- +title: Getting Started +description: Install OpenWorkflow and create your first durable workflow in minutes +icon: Rocket +--- + +# Getting Started + +This guide will walk you through installing OpenWorkflow, setting up a PostgreSQL backend, and creating your first durable workflow. + +## Prerequisites + +Before you begin, ensure you have: + +- **Node.js**: Version 20 or higher +- **PostgreSQL**: A running PostgreSQL instance (local or remote) + +## Installation + +Install the core OpenWorkflow package and the PostgreSQL backend: + + + + ```bash + npm install openworkflow @openworkflow/backend-postgres + ``` + + + ```bash + pnpm add openworkflow @openworkflow/backend-postgres + ``` + + + ```bash + yarn add openworkflow @openworkflow/backend-postgres + ``` + + + ```bash + bun add openworkflow @openworkflow/backend-postgres + ``` + + + +## Database Setup + + +OpenWorkflow requires a PostgreSQL database to store workflow state. All workflow runs and step attempts are persisted to ensure durability across crashes. + + +If you don't have PostgreSQL installed, you can use Docker: + +```bash +docker run -d \ + --name openworkflow-postgres \ + -e POSTGRES_PASSWORD=postgres \ + -p 5432:5432 \ + postgres:16 +``` + +### Connection String + +You'll need a PostgreSQL connection URL in this format: + +``` +postgresql://username:password@hostname:port/database +``` + +Example for local development: + +``` +postgresql://postgres:postgres@localhost:5432/postgres +``` + +Store this in an environment variable: + +```bash +export DATABASE_URL="postgresql://postgres:postgres@localhost:5432/postgres" +``` + +## Create Your First Workflow + + + + + +### Connect to the Backend + +Create a new file called `workflow.ts`: + + + + +```ts +import { BackendPostgres } from "@openworkflow/backend-postgres"; +import { OpenWorkflow } from "openworkflow"; + +const databaseUrl = process.env.DATABASE_URL!; +const backend = await BackendPostgres.connect(databaseUrl); +const ow = new OpenWorkflow({ backend }); +``` + + + + + +The backend will automatically create the necessary database tables (`workflow_runs` and `step_attempts`) on first connection. + + + + + + +### Define a Workflow + +A workflow is a durable function that orchestrates multiple steps: + + + + +```ts +const sendWelcomeEmail = ow.defineWorkflow( + { name: "send-welcome-email" }, + async ({ input, step }) => { + // Step 1: Fetch user from database + const user = await step.run({ name: "fetch-user" }, async () => { + return await db.users.findOne({ id: input.userId }); + }); + + // Step 2: Send email + await step.run({ name: "send-email" }, async () => { + return await emailService.send({ + to: user.email, + subject: "Welcome!", + html: "

Welcome to our app!

", + }); + }); + + // Step 3: Mark email as sent + await step.run({ name: "mark-sent" }, async () => { + await db.users.update(input.userId, { welcomeEmailSent: true }); + }); + + return { success: true, userId: input.userId }; + }, +); +``` + +
+
+ +Each `step.run()` creates a checkpoint. If the workflow crashes, it will resume from the last completed step. + +
+ + + +### Start a Worker + +Workers are background processes that execute workflows. Start one in the same file or a separate process: + + + + +```ts +const worker = ow.newWorker(); +await worker.start(); + +console.log("Worker started. Waiting for workflows..."); +``` + + + + + + + + +### Run the Workflow + +Trigger the workflow from your application code: + + + + +```ts +// Trigger the workflow asynchronously +const runHandle = await sendWelcomeEmail.run({ userId: "user_123" }); + +console.log(`Workflow started with ID: ${runHandle.workflowRun.id}`); + +// Optional: Wait for the result +const result = await runHandle.result(); +console.log("Workflow completed:", result); +``` + + + + + + +
+ +## Complete Example + +Here's the full code: + + + + +```ts title="workflow.ts" +import { BackendPostgres } from "@openworkflow/backend-postgres"; +import { OpenWorkflow } from "openworkflow"; + +// Connect to backend +const backend = await BackendPostgres.connect(process.env.DATABASE_URL!); +const ow = new OpenWorkflow({ backend }); + +// Define workflow +const greetUser = ow.defineWorkflow( + { name: "greet-user" }, + async ({ input, step }) => { + const greeting = await step.run({ name: "generate-greeting" }, async () => { + return `Hello, ${input.name}!`; + }); + + const timestamp = await step.run({ name: "get-timestamp" }, async () => { + return new Date().toISOString(); + }); + + return { greeting, timestamp }; + }, +); + +// Start worker +const worker = ow.newWorker({ concurrency: 10 }); +await worker.start(); + +// Run workflow +const run = await greetUser.run({ name: "Alice" }); +const result = await run.result(); + +console.log(result); // { greeting: "Hello, Alice!", timestamp: "..." } + +// Graceful shutdown +await worker.stop(); +await backend.stop(); +``` + + + + +## Run Your Workflow + +Execute the script: + +```bash +node workflow.ts +``` + +You should see: + +``` +Worker started. Waiting for workflows... +{ greeting: "Hello, Alice!", timestamp: "2024-01-15T10:30:00.000Z" } +``` + +## What Happens Under the Hood + +1. **Workflow Creation**: A row is inserted into the `workflow_runs` table with status `pending` +2. **Worker Claims**: The worker polls the database and claims the workflow +3. **Step Execution**: Each step is executed and recorded in `step_attempts` +4. **Completion**: The workflow status is updated to `succeeded` + +If the worker crashes during execution, another worker will pick up the workflow and resume from the last completed step. + +## Next Steps + + + + + + + + +## Project Structure + +Here's a recommended project structure for OpenWorkflow: + + + + + + + + + + + + + + + +## Common Patterns + +### Pattern 1: API Route Handler + +Trigger workflows from your API: + + + + +```ts +app.post("/users/:id/welcome", async (req, res) => { + const run = await sendWelcomeEmail.run({ userId: req.params.id }); + res.json({ workflowRunId: run.workflowRun.id }); +}); +``` + + + + +### Pattern 2: Separate Worker Process + +Run workers in a dedicated process: + + + + +```ts title="worker.ts" +import { BackendPostgres } from "@openworkflow/backend-postgres"; +import { OpenWorkflow } from "openworkflow"; + +const backend = await BackendPostgres.connect(process.env.DATABASE_URL!); +const ow = new OpenWorkflow({ backend }); + +// Import all workflow definitions +import "./workflows/welcome-email.js"; +import "./workflows/order-processing.js"; + +const worker = ow.newWorker({ concurrency: 20 }); +await worker.start(); + +process.on("SIGTERM", async () => { + await worker.stop(); + await backend.stop(); + process.exit(0); +}); +``` + + + + +### Pattern 3: With TypeScript Types + +Add type safety to your workflows: + + + + +```ts +interface SendEmailInput { + userId: string; + emailType: "welcome" | "confirmation"; +} + +interface SendEmailOutput { + success: boolean; + emailId: string; +} + +const sendEmail = ow.defineWorkflow( + { name: "send-email" }, + async ({ input, step }) => { + // input is typed as SendEmailInput + // return must match SendEmailOutput + }, +); +``` + + + + +## Troubleshooting + + +Most issues are related to database connectivity or worker configuration. Check the solutions below. + + +### Database Connection Errors + +If you see connection errors: + +1. Verify PostgreSQL is running: `psql -U postgres -h localhost` +2. Check your connection string format +3. Ensure the database exists + +### Worker Not Picking Up Workflows + +If workflows aren't executing: + +1. Ensure the worker is started: `await worker.start()` +2. Check workflow names match between definition and run +3. Verify the database connection is active + +### Steps Not Memoizing + +If steps re-execute on retry: + +1. Ensure step names are unique within a workflow +2. Don't use dynamic step names (they must be deterministic) +3. Check that the backend connection is stable + +## Learn More + +- [Core Concepts](/en/docs/core-concepts) - Deep dive into workflows, steps, and workers +- [Architecture](/en/docs/architecture) - Understand the execution model +- [API Reference](/en/docs/api-reference) - Complete API documentation \ No newline at end of file diff --git a/apps/docs/content/docs/en/index.mdx b/apps/docs/content/docs/en/index.mdx new file mode 100644 index 0000000..1569c7f --- /dev/null +++ b/apps/docs/content/docs/en/index.mdx @@ -0,0 +1,124 @@ +--- +title: Introduction +description: OpenWorkflow is a TypeScript framework for building durable, resumable workflows that survive crashes and deploys. +icon: Rocket +--- + +# OpenWorkflow + +OpenWorkflow is a TypeScript framework for building durable, resumable workflows that can pause for seconds or months, survive crashes and deploys, and resume exactly where they left off - all without extra servers to manage. + +## What is OpenWorkflow? + +OpenWorkflow allows developers to write **durable functions**, called workflows, that can survive process crashes, server restarts, and code deploys. It achieves this through a **worker-driven architecture** where stateless workers communicate with a durable backend (like PostgreSQL) to manage workflow state. + +## Key Features + +- **Durable Execution**: Workflows resume automatically after crashes or restarts +- **Step Memoization**: Each step executes exactly once and its result is cached +- **Worker-Driven**: No separate orchestrator server needed - just workers and a database +- **Type-Safe**: Full TypeScript support with generics for input and output types +- **Parallel Execution**: Run multiple steps concurrently with `Promise.all` +- **Automatic Retries**: Built-in retry logic with exponential backoff +- **Graceful Shutdown**: Workers wait for in-flight workflows before stopping +- **Scalable**: Run multiple workers for high availability + +## When to Use OpenWorkflow + +OpenWorkflow is ideal for: + +- **Long-running processes**: Multi-step workflows that take minutes, hours, or days +- **Mission-critical operations**: Payment processing, order fulfillment, data pipelines +- **API orchestration**: Coordinating multiple external API calls with retries +- **Background jobs**: Tasks that need to be reliable and resumable +- **Event-driven workflows**: Complex business processes triggered by events + +## Quick Example + + + + +```ts +import { BackendPostgres } from "@openworkflow/backend-postgres"; +import { OpenWorkflow } from "openworkflow"; + +const backend = await BackendPostgres.connect(process.env.DATABASE_URL); +const ow = new OpenWorkflow({ backend }); + +const sendWelcomeEmail = ow.defineWorkflow( + { name: "send-welcome-email" }, + async ({ input, step }) => { + const user = await step.run({ name: "fetch-user" }, async () => { + return await db.users.findOne({ id: input.userId }); + }); + + await step.run({ name: "send-email" }, async () => { + return await email.send({ to: user.email, subject: "Welcome!" }); + }); + + return { user }; + }, +); + +// Start a worker +const worker = ow.newWorker(); +await worker.start(); + +// Run the workflow +await sendWelcomeEmail.run({ userId: "123" }); +``` + + + + +## How It Works + +1. **Define workflows** with steps that represent checkpoints +2. **Start a worker** that polls your database for pending workflows +3. **Trigger workflows** from your application code +4. **Workers execute** the workflow, memoizing each step +5. **If a worker crashes**, another worker picks up and resumes from the last completed step + +## Architecture Overview + +OpenWorkflow uses a unique **worker-driven model**: + +- **No central orchestrator**: Workers are the execution engine +- **Database as queue**: Your PostgreSQL database serves as both queue and state store +- **Stateless workers**: Workers can be started, stopped, and deployed independently +- **Deterministic replay**: Workflows execute from the beginning on each run, but completed steps return cached results instantly + + + + + + + + +## Current Status + +OpenWorkflow is in **active development** (v0.1). The core features are stable and production-ready: + +- ✅ PostgreSQL backend +- ✅ Worker with concurrency control +- ✅ Step memoization & retries +- ✅ Graceful shutdown +- ✅ Parallel step execution + +Coming soon: CLI, Dashboard UI, workflow versioning, additional backends (Redis, SQLite), and more. diff --git a/apps/docs/content/docs/en/meta.json b/apps/docs/content/docs/en/meta.json new file mode 100644 index 0000000..bfe5c74 --- /dev/null +++ b/apps/docs/content/docs/en/meta.json @@ -0,0 +1,15 @@ +{ + "title": "Documentation", + "pages": [ + "index", + "getting-started", + "core-concepts", + "architecture", + "api-reference", + "advanced-features", + "backend-postgres", + "production-guide", + "examples", + "roadmap" + ] +} diff --git a/apps/docs/content/docs/en/production-guide.mdx b/apps/docs/content/docs/en/production-guide.mdx new file mode 100644 index 0000000..8fbca87 --- /dev/null +++ b/apps/docs/content/docs/en/production-guide.mdx @@ -0,0 +1,806 @@ +--- +title: Production Guide +description: Best practices for deploying OpenWorkflow to production +icon: Rocket +--- + +# Production Guide + +This guide covers best practices for deploying OpenWorkflow to production, including infrastructure setup, monitoring, scaling, and operational considerations. + +## Production Checklist + + +Before deploying to production, ensure you have all items below configured. Missing any of these can lead to data loss, downtime, or performance issues. + + +Ensure you have: + +- ✅ **Production PostgreSQL database** with backups +- ✅ **At least one worker process** running +- ✅ **Graceful shutdown handlers** for clean deploys +- ✅ **Monitoring and alerting** for failed workflows +- ✅ **Connection pooling** configured +- ✅ **Namespace isolation** for environments +- ✅ **Cleanup strategy** for old workflow data +- ✅ **Error tracking** (e.g., Sentry, Datadog) +- ✅ **Performance tuning** (concurrency, indexes) + +## Database Setup + +### Production PostgreSQL + +Use a managed PostgreSQL service for production: + +- **AWS RDS**: Fully managed, automatic backups +- **Google Cloud SQL**: High availability, point-in-time recovery +- **Azure Database**: Built-in monitoring and scaling +- **Neon**: Serverless Postgres with autoscaling +- **Supabase**: Postgres with REST API + +### Configuration + + + + +```ts +const backend = await BackendPostgres.connect( + process.env.DATABASE_URL!, + { + namespaceId: process.env.NODE_ENV || "production", + } +); +``` + + + + +### Connection String Format + +```bash +# Use SSL in production +export DATABASE_URL="postgresql://user:pass@db.example.com:5432/prod?sslmode=require" +``` + +### Backups + +Implement regular backups: + +- **Automated backups**: Use your cloud provider's backup service +- **Point-in-time recovery**: Enable WAL archiving +- **Test restores**: Regularly verify backup integrity + +### Security + +1. **Use SSL/TLS**: Add `?sslmode=require` to connection string +2. **Restrict access**: Whitelist only necessary IP addresses +3. **Rotate credentials**: Use secrets management (AWS Secrets Manager, Vault) +4. **Least privilege**: Grant only necessary database permissions + +```sql +-- Create a dedicated user with limited permissions +CREATE USER openworkflow_app WITH PASSWORD 'secure_password'; +GRANT SELECT, INSERT, UPDATE, DELETE ON workflow_runs TO openworkflow_app; +GRANT SELECT, INSERT, UPDATE, DELETE ON step_attempts TO openworkflow_app; +``` + +## Worker Deployment + +### Production Project Structure + + + + + + + + + + + + + + + + + + + + + + + +### Standalone Worker Process + +Run workers as separate processes from your application: + + + + +```ts title="worker.ts" +import { BackendPostgres } from "@openworkflow/backend-postgres"; +import { OpenWorkflow } from "openworkflow"; + +// Import all workflow definitions +import "./workflows/index.js"; + +const backend = await BackendPostgres.connect(process.env.DATABASE_URL!); +const ow = new OpenWorkflow({ backend }); + +const worker = ow.newWorker({ + concurrency: parseInt(process.env.WORKER_CONCURRENCY || "10", 10), +}); + +await worker.start(); +console.log("Worker started"); + +// Graceful shutdown +process.on("SIGTERM", async () => { + console.log("Received SIGTERM, shutting down..."); + await worker.stop(); + await backend.stop(); + process.exit(0); +}); + +process.on("SIGINT", async () => { + console.log("Received SIGINT, shutting down..."); + await worker.stop(); + await backend.stop(); + process.exit(0); +}); +``` + + + + +### Docker Deployment + +Create a Dockerfile for your worker: + +```dockerfile title="Dockerfile" +FROM node:20-alpine + +WORKDIR /app + +COPY package*.json ./ +RUN npm ci --production + +COPY . . + +CMD ["node", "worker.js"] +``` + +### Docker Compose + +```yaml title="docker-compose.yml" +version: "3.8" + +services: + postgres: + image: postgres:16 + environment: + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: openworkflow + volumes: + - postgres-data:/var/lib/postgresql/data + restart: always + + worker: + build: . + environment: + DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/openworkflow + WORKER_CONCURRENCY: 20 + NODE_ENV: production + depends_on: + - postgres + restart: always + deploy: + replicas: 3 # Run 3 worker instances + +volumes: + postgres-data: +``` + +### Kubernetes Deployment + +```yaml title="worker-deployment.yaml" +apiVersion: apps/v1 +kind: Deployment +metadata: + name: openworkflow-worker +spec: + replicas: 3 + selector: + matchLabels: + app: openworkflow-worker + template: + metadata: + labels: + app: openworkflow-worker + spec: + containers: + - name: worker + image: your-registry/openworkflow-worker:latest + env: + - name: DATABASE_URL + valueFrom: + secretKeyRef: + name: openworkflow-secrets + key: database-url + - name: WORKER_CONCURRENCY + value: "20" + - name: NODE_ENV + value: "production" + resources: + requests: + memory: "256Mi" + cpu: "250m" + limits: + memory: "512Mi" + cpu: "500m" + lifecycle: + preStop: + exec: + command: ["/bin/sh", "-c", "sleep 10"] # Allow graceful shutdown +``` + +## Concurrency Tuning + +### Choosing Concurrency + +Start with these guidelines and adjust based on monitoring: + + + + +```ts +// Low-latency, many short workflows (< 1 second each) +const worker = ow.newWorker({ concurrency: 100 }); + +// Medium-latency workflows (1-10 seconds each) +const worker = ow.newWorker({ concurrency: 20 }); + +// High-latency workflows (> 10 seconds each) +const worker = ow.newWorker({ concurrency: 10 }); +``` + + + + +### Monitoring Resource Usage + +Monitor CPU, memory, and database connections: + +```bash +# Check CPU usage +top + +# Check memory usage +free -h + +# Check database connections +psql -c "SELECT count(*) FROM pg_stat_activity;" +``` + +### Scaling Workers + +Scale horizontally by adding more worker processes: + +```bash +# Docker Compose +docker-compose up --scale worker=5 + +# Kubernetes +kubectl scale deployment openworkflow-worker --replicas=5 +``` + +Each worker operates independently. They coordinate through the database using atomic operations. + +## Graceful Shutdown + +### Importance + +Graceful shutdown ensures: + +- No workflow data loss during deploys +- In-flight workflows complete successfully +- Database connections close cleanly + +### Implementation + +```ts +const worker = ow.newWorker({ concurrency: 20 }); +await worker.start(); + +let isShuttingDown = false; + +async function shutdown(signal: string) { + if (isShuttingDown) return; + isShuttingDown = true; + + console.log(`Received ${signal}, starting graceful shutdown...`); + + try { + // Stop accepting new work + await worker.stop(); + console.log("Worker stopped"); + + // Close database connection + await backend.stop(); + console.log("Backend closed"); + + console.log("Shutdown complete"); + process.exit(0); + } catch (error) { + console.error("Error during shutdown:", error); + process.exit(1); + } +} + +process.on("SIGTERM", () => shutdown("SIGTERM")); +process.on("SIGINT", () => shutdown("SIGINT")); +``` + +### Kubernetes + +Configure Kubernetes for graceful shutdown: + +```yaml +spec: + terminationGracePeriodSeconds: 60 # Wait up to 60s for graceful shutdown + containers: + - name: worker + lifecycle: + preStop: + exec: + command: ["/bin/sh", "-c", "sleep 10"] +``` + +### Load Balancer Draining + +If workers are behind a load balancer: + +1. Remove worker from load balancer +2. Wait for in-flight requests to complete +3. Stop worker +4. Close database connection + +## Monitoring + +### Workflow Metrics + +Track key metrics: + +- **Workflow run count** (total, by status) +- **Workflow duration** (p50, p95, p99) +- **Step count per workflow** +- **Failed workflow rate** +- **Retry count** + +### Database Metrics + +Monitor PostgreSQL: + +- **Connection count** +- **Query duration** +- **Table size** (`workflow_runs`, `step_attempts`) +- **Index usage** +- **Lock contention** + +### Custom Monitoring + +Query workflow stats: + +```sql +-- Count workflows by status +SELECT status, COUNT(*) as count +FROM workflow_runs +GROUP BY status; + +-- Average workflow duration +SELECT + workflow_name, + AVG(EXTRACT(EPOCH FROM (completed_at - created_at))) as avg_duration_seconds +FROM workflow_runs +WHERE status = 'succeeded' +GROUP BY workflow_name; + +-- Failed workflows in last 24 hours +SELECT COUNT(*) +FROM workflow_runs +WHERE status = 'failed' + AND created_at > NOW() - INTERVAL '24 hours'; +``` + +### Integration with Monitoring Tools + +#### Prometheus + +Expose metrics endpoint: + +```ts +import { register, Counter, Histogram } from "prom-client"; + +const workflowCounter = new Counter({ + name: "openworkflow_runs_total", + help: "Total number of workflow runs", + labelNames: ["workflow_name", "status"], +}); + +const workflowDuration = new Histogram({ + name: "openworkflow_duration_seconds", + help: "Workflow execution duration", + labelNames: ["workflow_name"], +}); + +// In your workflow code +workflowCounter.inc({ workflow_name: "my-workflow", status: "succeeded" }); +``` + +#### Datadog + +```ts +import { StatsD } from "node-dogstatsd"; + +const statsd = new StatsD(); + +// Track workflow completion +statsd.increment("openworkflow.runs", 1, ["workflow:my-workflow", "status:succeeded"]); + +// Track workflow duration +statsd.timing("openworkflow.duration", duration, ["workflow:my-workflow"]); +``` + +## Alerting + +Set up alerts for critical issues: + +### Failed Workflows + +```sql +-- Alert if more than 10 failures in last hour +SELECT COUNT(*) > 10 as alert +FROM workflow_runs +WHERE status = 'failed' + AND created_at > NOW() - INTERVAL '1 hour'; +``` + +### Long-Running Workflows + +```sql +-- Alert if workflows running > 1 hour +SELECT COUNT(*) as long_running +FROM workflow_runs +WHERE status = 'running' + AND created_at < NOW() - INTERVAL '1 hour'; +``` + +### No Active Workers + +Monitor worker heartbeats: + +```sql +-- Alert if no workflows claimed in last 5 minutes +SELECT COUNT(*) = 0 as no_workers +FROM workflow_runs +WHERE worker_id IS NOT NULL + AND created_at > NOW() - INTERVAL '5 minutes'; +``` + +## Data Cleanup + +### Retention Policy + +Define a retention policy for old data: + +```ts +// Cleanup job (run daily) +async function cleanupOldWorkflows() { + const retentionDays = 30; + + await backend.query(` + DELETE FROM workflow_runs + WHERE status IN ('succeeded', 'failed') + AND completed_at < NOW() - INTERVAL '${retentionDays} days' + `); + + console.log(`Cleaned up workflows older than ${retentionDays} days`); +} + +// Run cleanup daily at 2 AM +import cron from "node-cron"; +cron.schedule("0 2 * * *", cleanupOldWorkflows); +``` + +### Archiving + +Archive old workflows to cold storage: + +```ts +async function archiveOldWorkflows() { + // Export to S3, BigQuery, etc. + const oldWorkflows = await backend.query(` + SELECT * FROM workflow_runs + WHERE status IN ('succeeded', 'failed') + AND completed_at < NOW() - INTERVAL '30 days' + `); + + await s3.upload("workflow-archive", JSON.stringify(oldWorkflows)); + + // Then delete from database + await backend.query(` + DELETE FROM workflow_runs + WHERE id IN (${oldWorkflows.map(w => w.id).join(',')}) + `); +} +``` + +## Performance Optimization + +### Database Indexes + +Ensure proper indexes exist: + +```sql +-- Check existing indexes +\d workflow_runs + +-- Add custom indexes if needed +CREATE INDEX idx_workflow_runs_created_at +ON workflow_runs (created_at DESC); + +CREATE INDEX idx_workflow_runs_name_status +ON workflow_runs (workflow_name, status); +``` + +### Connection Pooling + +Configure connection pool size: + +```ts +const backend = await BackendPostgres.connect( + `postgresql://user:pass@host:5432/db?pool_size=20` +); +``` + +Match pool size to concurrency: + +``` +Pool Size ≈ (Worker Concurrency * Number of Workers) + 10 +``` + +### Query Optimization + +Analyze slow queries: + +```sql +-- Enable query logging in postgresql.conf +log_min_duration_statement = 1000 # Log queries > 1 second + +-- Analyze query performance +EXPLAIN ANALYZE +SELECT * FROM workflow_runs +WHERE status = 'pending' + AND available_at <= NOW() +ORDER BY available_at ASC +LIMIT 1; +``` + +## Error Handling + +### Sentry Integration + +Track workflow errors: + +```ts +import * as Sentry from "@sentry/node"; + +Sentry.init({ + dsn: process.env.SENTRY_DSN, + environment: process.env.NODE_ENV, +}); + +const workflow = ow.defineWorkflow( + { name: "monitored-workflow" }, + async ({ input, step }) => { + try { + const result = await step.run({ name: "risky-step" }, async () => { + return await riskyOperation(); + }); + return result; + } catch (error) { + Sentry.captureException(error, { + tags: { workflow: "monitored-workflow" }, + extra: { input }, + }); + throw error; + } + } +); +``` + +### Custom Error Logging + +```ts +const workflow = ow.defineWorkflow( + { name: "logged-workflow" }, + async ({ input, step }) => { + try { + return await step.run({ name: "main" }, async () => { + return await mainOperation(); + }); + } catch (error) { + // Log to your logging service + await logger.error("Workflow failed", { + workflow: "logged-workflow", + input, + error: error.message, + stack: error.stack, + }); + throw error; + } + } +); +``` + +## High Availability + +### Multiple Workers + +Run multiple worker processes for redundancy: + +```yaml +# docker-compose.yml +worker: + deploy: + replicas: 3 +``` + +If one worker crashes, others continue processing workflows. + +### Database Failover + +Use managed PostgreSQL with automatic failover: + +- **AWS RDS**: Multi-AZ deployment +- **Google Cloud SQL**: High availability configuration +- **Azure Database**: Zone-redundant deployment + +### Health Checks + +Implement health check endpoints: + +```ts +import express from "express"; + +const app = express(); + +app.get("/health", (req, res) => { + if (worker.isRunning && backend.isConnected) { + res.status(200).json({ status: "healthy" }); + } else { + res.status(503).json({ status: "unhealthy" }); + } +}); + +app.listen(3000); +``` + +## Security + + +Never hardcode database passwords, API keys, or other secrets in your code. Always use environment variables and secrets management systems. + + +### Secrets Management + +```ts +// ❌ Don't do this +const backend = await BackendPostgres.connect( + "postgresql://user:password123@host:5432/db" +); + +// ✅ Do this +const backend = await BackendPostgres.connect(process.env.DATABASE_URL!); +``` + +Use secrets management: + +- **AWS Secrets Manager** +- **Google Cloud Secret Manager** +- **Azure Key Vault** +- **HashiCorp Vault** + +### Network Security + +- Use VPC/private networks +- Restrict database access to worker IPs only +- Enable SSL/TLS for all connections +- Use firewall rules + +## Troubleshooting + + +Click each section below to see symptoms, causes, and solutions for common production issues. + + + + + + +**Symptoms:** Workflows stay in `pending` status + +**Causes:** +1. No workers running +2. Worker crashed +3. Database connection lost +4. Query errors + +**Solutions:** +1. Check worker logs +2. Verify database connectivity +3. Check `workflow_runs` table for pending workflows +4. Restart workers + + + + + +**Symptoms:** Slow workflow execution, high CPU on database + +**Causes:** +1. Too many workers polling +2. Missing indexes +3. Large workflow/step payloads +4. No data cleanup + +**Solutions:** +1. Reduce worker concurrency +2. Add database indexes +3. Reduce input/output size +4. Implement cleanup strategy + + + + + +**Symptoms:** Worker memory usage grows over time + +**Causes:** +1. Unclosed connections +2. Large workflow payloads kept in memory +3. Event listener leaks + +**Solutions:** +1. Profile with `node --inspect` +2. Monitor with `process.memoryUsage()` +3. Restart workers periodically (e.g., daily) + + + + + +## Next Steps + + + + + + + diff --git a/apps/docs/content/docs/en/roadmap.mdx b/apps/docs/content/docs/en/roadmap.mdx new file mode 100644 index 0000000..2d2997a --- /dev/null +++ b/apps/docs/content/docs/en/roadmap.mdx @@ -0,0 +1,204 @@ +--- +title: Roadmap +description: OpenWorkflow development roadmap and upcoming features +icon: Map +--- + +# Roadmap + +OpenWorkflow is in active development and moving quickly. This page outlines what's been completed and what's coming next. + + +OpenWorkflow is currently in **v0.2** and under active development. The core features are stable and production-ready, but we're continuously adding new capabilities based on community feedback. + + +## Current Status + +The current release includes core functionality for building durable workflows: + +### Completed Features + +- **PostgreSQL Backend** - Full support for PostgreSQL as the state backend +- **Worker with Concurrency Control** - Run multiple workflows simultaneously with configurable concurrency +- **Step Memoization & Retries** - Automatic caching of completed steps and retry logic +- **Graceful Shutdown** - Workers wait for in-flight workflows before stopping +- **Parallel Step Execution** - Execute multiple steps concurrently with `Promise.all` +- **Type Safety** - Full TypeScript support with generic input/output types +- **Deterministic Replay** - Workflows resume from the last completed step after crashes +- **Sleeping (Pausing) Workflows** - Durable timers via `step.sleep` that free worker slots + +### Current Limitations + + +The v0.1 release doesn't yet include a dashboard UI or CLI. For now, you can inspect workflow and step state directly in PostgreSQL (`workflow_runs` and `step_attempts` tables). A CLI and dashboard are planned for an upcoming release to make debugging and monitoring much easier. + + +## Coming Soon + +### 🔧 Developer Tools + + + 💻}> + Command-line interface for managing workflows, inspecting runs, and debugging issues + + 📊}> + Web-based dashboard for monitoring workflows, viewing execution history, and managing workers + + + +**Use Cases:** +- View all workflow runs and their statuses +- Inspect step execution history +- Retry failed workflows +- Monitor worker health and performance +- Debug workflow issues visually + +### Workflow Management + +- **Workflow Versioning** - Deploy new workflow versions without breaking in-flight executions +- **Configurable Retry Policies** - Fine-grained control over retry behavior per workflow or step +- **Signals for External Events** - Send signals to running workflows to trigger actions +- **Workflow Cancellation** - Gracefully cancel running workflows +- **Scheduled Workflows** - Cron-like scheduling for recurring workflows +- **Workflow Timeouts** - Set execution time limits per workflow + +### Additional Backends + +Expand beyond PostgreSQL to support more infrastructure options: + +- **Redis Backend** - Lower latency for high-throughput workflows with built-in pub/sub +- **SQLite Backend** - Zero-configuration local development and embedded deployments +- **DynamoDB Backend** (Under Consideration) - Serverless-native workflow execution + +### Multi-Language SDKs + +Expand OpenWorkflow to more programming languages: + +- **Go SDK** - Planned for idiomatic Go workflow development +- **Python SDK** - Planned for Python developers and data science workflows +- **Rust SDK** (Under Consideration) - High-performance workflow execution + +### Enterprise Features + +- **Audit Logging** - Complete audit trail of all workflow executions +- **Role-Based Access Control** - Fine-grained permissions for workflows and workers +- **Encryption at Rest** - Encrypt sensitive workflow data in the database +- **Multi-Tenancy** - Isolate workflows by tenant/customer +- **Observability** - OpenTelemetry integration for tracing and metrics + +## How to Contribute + +We welcome contributions! Here's how you can help: + + + + + +### Check Existing Issues + +Browse [open issues](https://github.com/openworkflowdev/openworkflow/issues) on GitHub to see what's being worked on. + + + + + +### Propose New Features + +Have an idea? [Open a feature request](https://github.com/openworkflowdev/openworkflow/issues/new) to discuss it with the community. + + + + + +### Submit Pull Requests + +Found a bug or want to implement a feature? Submit a PR! Check out our [Contributing Guide](https://github.com/openworkflowdev/openworkflow/blob/main/CONTRIBUTING.md). + + + + + +## Stay Updated + + + + + + + +## Feedback + +Your feedback shapes the roadmap! If you have ideas for features or improvements: + +1. **Open an issue** on [GitHub](https://github.com/openworkflowdev/openworkflow/issues/new) +2. **Join discussions** about upcoming features +3. **Vote** on features you'd like to see prioritized + + +Feature prioritization is based on: +- **Community demand** - How many users request it +- **Impact** - How much value it provides +- **Complexity** - Implementation effort required +- **Alignment** - Fit with OpenWorkflow's core philosophy + + +## Version History + +### v0.2.0 (Current) + +Core features for building production-ready durable workflows, plus: +- Sleep workflows with `step.sleep(name, duration)` + +### v0.1.0 + +Initial release with core durable workflow features: +- PostgreSQL backend +- Worker-driven architecture +- Step memoization +- Graceful shutdown +- Parallel execution +- TypeScript support + +### Future Versions + +- **v0.3.x** - Workflow versioning and signals +- **v0.4.x** - CLI and Dashboard UI +- **v0.5.x** - Additional backends (Redis, SQLite) +- **v1.0.x** - Multi-language SDKs and enterprise features + +## Next Steps + + + + + + + diff --git a/apps/docs/package.json b/apps/docs/package.json new file mode 100644 index 0000000..e5af081 --- /dev/null +++ b/apps/docs/package.json @@ -0,0 +1,46 @@ +{ + "name": "docs", + "private": true, + "sideEffects": false, + "type": "module", + "scripts": { + "dev": "vite dev", + "build": "vite build", + "preview": "vite preview", + "serve": "node .output/server/index.mjs ", + "postinstall": "fumadocs-mdx" + }, + "dependencies": { + "@orama/orama": "^3.1.16", + "@radix-ui/react-accordion": "^1.2.12", + "@radix-ui/react-collapsible": "^1.1.12", + "@radix-ui/react-tabs": "^1.1.13", + "@tanstack/react-router": "^1.134.12", + "@tanstack/react-router-devtools": "^1.134.12", + "@tanstack/react-start": "^1.134.12", + "@tanstack/start-static-server-functions": "^1.134.12", + "class-variance-authority": "^0.7.1", + "fumadocs-core": "16.0.8", + "fumadocs-mdx": "13.0.5", + "fumadocs-ui": "16.0.8", + "lucide-react": "^0.553.0", + "lucide-static": "^0.552.0", + "nitro": "^3.0.1-alpha.1", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "tailwind-merge": "^3.3.1", + "vite": "^7.1.12" + }, + "devDependencies": { + "@tailwindcss/vite": "^4.1.16", + "@types/mdx": "^2.0.13", + "@types/node": "^24.10.0", + "@types/react": "^19.2.2", + "@types/react-dom": "^19.2.2", + "@vitejs/plugin-react": "^5.1.0", + "serve": "^14.2.5", + "tailwindcss": "^4.1.16", + "typescript": "^5.9.3", + "vite-tsconfig-paths": "^5.1.4" + } +} diff --git a/apps/docs/source.config.ts b/apps/docs/source.config.ts new file mode 100644 index 0000000..0564068 --- /dev/null +++ b/apps/docs/source.config.ts @@ -0,0 +1,7 @@ +import { defineConfig, defineDocs } from 'fumadocs-mdx/config'; + +export const docs = defineDocs({ + dir: 'content/docs', +}); + +export default defineConfig(); diff --git a/apps/docs/src/components/accordion.tsx b/apps/docs/src/components/accordion.tsx new file mode 100644 index 0000000..9b2fd84 --- /dev/null +++ b/apps/docs/src/components/accordion.tsx @@ -0,0 +1,136 @@ +'use client'; + +import type { + AccordionMultipleProps, + AccordionSingleProps, +} from '@radix-ui/react-accordion'; +import * as AccordionPrimitive from '@radix-ui/react-accordion'; +import { Check, ChevronRight, Link as LinkIcon } from 'lucide-react'; +import { + type ComponentPropsWithoutRef, + forwardRef, + type ReactNode, + useEffect, + useRef, + useState, +} from 'react'; +import { cn } from '../lib/cn'; +import { useCopyButton } from 'fumadocs-ui/utils/use-copy-button'; +import { buttonVariants } from './ui/button'; +import { mergeRefs } from '../lib/merge-refs'; + +export const Accordions = forwardRef< + HTMLDivElement, + | Omit + | Omit +>(({ type = 'single', className, defaultValue, ...props }, ref) => { + const rootRef = useRef(null); + const composedRef = mergeRefs(ref, rootRef); + const [value, setValue] = useState(() => + type === 'single' ? (defaultValue ?? '') : (defaultValue ?? []), + ); + + useEffect(() => { + const id = window.location.hash.substring(1); + const element = rootRef.current; + if (!element || id.length === 0) return; + + const selected = document.getElementById(id); + if (!selected || !element.contains(selected)) return; + const value = selected.getAttribute('data-accordion-value'); + + if (value) + setValue((prev) => (typeof prev === 'string' ? value : [value, ...prev])); + }, []); + + return ( + // @ts-expect-error -- Multiple types + + ); +}); + +Accordions.displayName = 'Accordions'; + +export const Accordion = forwardRef< + HTMLDivElement, + Omit< + ComponentPropsWithoutRef, + 'value' | 'title' + > & { + title: string | ReactNode; + value?: string; + } +>( + ( + { title, className, id, value = String(title), children, ...props }, + ref, + ) => { + return ( + + + + + {title} + + {id ? : null} + + +
+ {children} +
+
+
+ ); + }, +); + +function CopyButton({ id }: { id: string }) { + const [checked, onClick] = useCopyButton(() => { + const url = new URL(window.location.href); + url.hash = id; + + return navigator.clipboard.writeText(url.toString()); + }); + + return ( + + ); +} + +Accordion.displayName = 'Accordion'; diff --git a/apps/docs/src/components/codeblock.tsx b/apps/docs/src/components/codeblock.tsx new file mode 100644 index 0000000..d391093 --- /dev/null +++ b/apps/docs/src/components/codeblock.tsx @@ -0,0 +1,263 @@ +'use client'; +import { Check, Clipboard } from 'lucide-react'; +import { + type ComponentProps, + createContext, + type HTMLAttributes, + type ReactNode, + type RefObject, + use, + useMemo, + useRef, +} from 'react'; +import { cn } from '../lib/cn'; +import { useCopyButton } from 'fumadocs-ui/utils/use-copy-button'; +import { buttonVariants } from './ui/button'; +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from './tabs.unstyled'; +import { mergeRefs } from '../lib/merge-refs'; + +export interface CodeBlockProps extends ComponentProps<'figure'> { + /** + * Icon of code block + * + * When passed as a string, it assumes the value is the HTML of icon + */ + icon?: ReactNode; + + /** + * Allow to copy code with copy button + * + * @defaultValue true + */ + allowCopy?: boolean; + + /** + * Keep original background color generated by Shiki or Rehype Code + * + * @defaultValue false + */ + keepBackground?: boolean; + + viewportProps?: HTMLAttributes; + + /** + * show line numbers + */ + 'data-line-numbers'?: boolean; + + /** + * @defaultValue 1 + */ + 'data-line-numbers-start'?: number; + + Actions?: (props: { className?: string; children?: ReactNode }) => ReactNode; +} + +const TabsContext = createContext<{ + containerRef: RefObject; + nested: boolean; +} | null>(null); + +export function Pre(props: ComponentProps<'pre'>) { + return ( +
+      {props.children}
+    
+ ); +} + +export function CodeBlock({ + ref, + title, + allowCopy = true, + keepBackground = false, + icon, + viewportProps = {}, + children, + Actions = (props) => ( +
+ ), + ...props +}: CodeBlockProps) { + const inTab = use(TabsContext) !== null; + const areaRef = useRef(null); + + return ( +
+ {title ? ( +
+ {typeof icon === 'string' ? ( +
+ ) : ( + icon + )} +
{title}
+ {Actions({ + className: '-me-2', + children: allowCopy && , + })} +
+ ) : ( + Actions({ + className: + 'absolute top-2 right-2 z-2 backdrop-blur-lg rounded-lg text-fd-muted-foreground', + children: allowCopy && , + }) + )} +
+ {children} +
+
+ ); +} + +function CopyButton({ + className, + containerRef, + ...props +}: ComponentProps<'button'> & { + containerRef: RefObject; +}) { + const [checked, onClick] = useCopyButton(() => { + const pre = containerRef.current?.getElementsByTagName('pre').item(0); + if (!pre) return; + + const clone = pre.cloneNode(true) as HTMLElement; + clone.querySelectorAll('.nd-copy-ignore').forEach((node) => { + node.replaceWith('\n'); + }); + + void navigator.clipboard.writeText(clone.textContent ?? ''); + }); + + return ( + + ); +} + +export function CodeBlockTabs({ ref, ...props }: ComponentProps) { + const containerRef = useRef(null); + const nested = use(TabsContext) !== null; + + return ( + + ({ + containerRef, + nested, + }), + [nested], + )} + > + {props.children} + + + ); +} + +export function CodeBlockTabsList(props: ComponentProps) { + return ( + + {props.children} + + ); +} + +export function CodeBlockTabsTrigger({ + children, + ...props +}: ComponentProps) { + return ( + +
+ {children} + + ); +} + +export function CodeBlockTab(props: ComponentProps) { + return ; +} diff --git a/apps/docs/src/components/files.tsx b/apps/docs/src/components/files.tsx new file mode 100644 index 0000000..ee3f73f --- /dev/null +++ b/apps/docs/src/components/files.tsx @@ -0,0 +1,85 @@ +'use client'; + +import { cva } from 'class-variance-authority'; +import { + File as FileIcon, + Folder as FolderIcon, + FolderOpen, +} from 'lucide-react'; +import { type HTMLAttributes, type ReactNode, useState } from 'react'; +import { cn } from '../lib/cn'; +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from './ui/collapsible'; + +const itemVariants = cva( + 'flex flex-row items-center gap-2 rounded-md px-2 py-1.5 text-sm hover:bg-fd-accent hover:text-fd-accent-foreground [&_svg]:size-4', +); + +export function Files({ + className, + ...props +}: HTMLAttributes): React.ReactElement { + return ( +
+ {props.children} +
+ ); +} + +export interface FileProps extends HTMLAttributes { + name: string; + icon?: ReactNode; +} + +export interface FolderProps extends HTMLAttributes { + name: string; + + disabled?: boolean; + + /** + * Open folder by default + * + * @defaultValue false + */ + defaultOpen?: boolean; +} + +export function File({ + name, + icon = , + className, + ...rest +}: FileProps): React.ReactElement { + return ( +
+ {icon} + {name} +
+ ); +} + +export function Folder({ + name, + defaultOpen = false, + ...props +}: FolderProps): React.ReactElement { + const [open, setOpen] = useState(defaultOpen); + + return ( + + + {open ? : } + {name} + + +
{props.children}
+
+
+ ); +} diff --git a/apps/docs/src/components/github-info.tsx b/apps/docs/src/components/github-info.tsx new file mode 100644 index 0000000..7726528 --- /dev/null +++ b/apps/docs/src/components/github-info.tsx @@ -0,0 +1,107 @@ +import { cn } from '../lib/cn'; +import { Star } from 'lucide-react'; +import { type AnchorHTMLAttributes } from 'react'; + +async function getRepoStarsAndForks( + owner: string, + repo: string, + token?: string, + baseUrl: string = 'https://api.github.com', +): Promise<{ + stars: number; + forks: number; +}> { + const endpoint = `${baseUrl}/repos/${owner}/${repo}`; + const headers = new Headers({ + 'Content-Type': 'application/json', + }); + + if (token) headers.set('Authorization', `Bearer ${token}`); + + const response = await fetch(endpoint, { + headers, + next: { + revalidate: 60, + }, + } as RequestInit); + + if (!response.ok) { + const message = await response.text(); + + throw new Error(`Failed to fetch repository data: ${message}`); + } + + const data = await response.json(); + return { + stars: data.stargazers_count, + forks: data.forks_count, + }; +} + +export async function GithubInfo({ + repo, + owner, + token, + baseUrl, + ...props +}: AnchorHTMLAttributes & { + owner: string; + repo: string; + token?: string; + baseUrl?: string; +}) { + const { stars } = await getRepoStarsAndForks(owner, repo, token, baseUrl); + const humanizedStars = humanizeNumber(stars); + + return ( + +

+ + GitHub + + + {owner}/{repo} +

+

+ + {humanizedStars} +

+
+ ); +} + +/** + * Converts a number to a human-readable string with K suffix for thousands + * @example 1500 -> "1.5K", 1000000 -> "1000000" + */ +function humanizeNumber(num: number): string { + if (num < 1000) { + return num.toString(); + } + + if (num < 100000) { + // For numbers between 1,000 and 99,999, show with one decimal (e.g., 1.5K) + const value = (num / 1000).toFixed(1); + // Remove trailing .0 if present + const formattedValue = value.endsWith('.0') ? value.slice(0, -2) : value; + + return `${formattedValue}K`; + } + + if (num < 1000000) { + // For numbers between 10,000 and 999,999, show as whole K (e.g., 10K, 999K) + return `${Math.floor(num / 1000)}K`; + } + + // For 1,000,000 and above, just return the number + return num.toString(); +} diff --git a/apps/docs/src/components/mdx-components.tsx b/apps/docs/src/components/mdx-components.tsx new file mode 100644 index 0000000..2ed87f0 --- /dev/null +++ b/apps/docs/src/components/mdx-components.tsx @@ -0,0 +1,38 @@ +import defaultMdxComponents from 'fumadocs-ui/mdx'; +import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; +import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; +import { Callout } from 'fumadocs-ui/components/callout'; +import { Card, Cards } from 'fumadocs-ui/components/card'; +import { File, Files, Folder } from 'fumadocs-ui/components/files'; +import { Step, Steps } from 'fumadocs-ui/components/steps'; +import { TypeTable } from 'fumadocs-ui/components/type-table'; +import { CodeBlock, Pre } from 'fumadocs-ui/components/codeblock'; +import type { MDXComponents } from 'mdx/types'; + +export function getMDXComponents(components?: MDXComponents): MDXComponents { + return { + ...defaultMdxComponents, + Accordion, + Accordions, + Callout, + Card, + Cards, + File, + Files, + Folder, + Step, + Steps, + Tab, + Tabs, + TypeTable, + // HTML `ref` attribute conflicts with `forwardRef` + pre: ({ ref: _ref, ...props }) => ( + +
{props.children}
+
+ ), + ...components, + }; +} + +export { Tab, Tabs }; diff --git a/apps/docs/src/components/not-found.tsx b/apps/docs/src/components/not-found.tsx new file mode 100644 index 0000000..8ddf7f5 --- /dev/null +++ b/apps/docs/src/components/not-found.tsx @@ -0,0 +1,28 @@ +import { Link } from '@tanstack/react-router'; +import { HomeLayout } from 'fumadocs-ui/layouts/home'; + +export function NotFound() { + return ( + +
+

404

+

Page Not Found

+

+ The page you are looking for might have been removed, had its name + changed, or is temporarily unavailable. +

+ + Back to Home + +
+
+ ); +} diff --git a/apps/docs/src/components/search.tsx b/apps/docs/src/components/search.tsx new file mode 100644 index 0000000..d4da747 --- /dev/null +++ b/apps/docs/src/components/search.tsx @@ -0,0 +1,51 @@ +'use client'; +import { + SearchDialog, + SearchDialogClose, + SearchDialogContent, + SearchDialogHeader, + SearchDialogIcon, + SearchDialogInput, + SearchDialogList, + SearchDialogOverlay, + type SharedProps, +} from 'fumadocs-ui/components/dialog/search'; +import { useDocsSearch } from 'fumadocs-core/search/client'; +import { create } from '@orama/orama'; +import { useI18n } from 'fumadocs-ui/contexts/i18n'; + +function initOrama() { + return create({ + schema: { _: 'string' }, + // https://docs.orama.com/docs/orama-js/supported-languages + language: 'english', + }); +} + +export default function DefaultSearchDialog(props: SharedProps) { + const { locale } = useI18n(); // (optional) for i18n + const { search, setSearch, query } = useDocsSearch({ + type: 'static', + initOrama, + locale, + }); + + return ( + + + + + + + + + + + + ); +} diff --git a/apps/docs/src/components/tabs.tsx b/apps/docs/src/components/tabs.tsx new file mode 100644 index 0000000..54c41a3 --- /dev/null +++ b/apps/docs/src/components/tabs.tsx @@ -0,0 +1,202 @@ +'use client'; + +import * as React from 'react'; +import { + type ComponentProps, + createContext, + type ReactNode, + useContext, + useEffect, + useId, + useMemo, + useState, +} from 'react'; +import { cn } from '../lib/cn'; +import * as Unstyled from './tabs.unstyled'; + +type CollectionKey = string | symbol; + +export interface TabsProps + extends Omit< + ComponentProps, + 'value' | 'onValueChange' + > { + /** + * Use simple mode instead of advanced usage as documented in https://radix-ui.com/primitives/docs/components/tabs. + */ + items?: string[]; + + /** + * Shortcut for `defaultValue` when `items` is provided. + * + * @defaultValue 0 + */ + defaultIndex?: number; + + /** + * Additional label in tabs list when `items` is provided. + */ + label?: ReactNode; +} + +const TabsContext = createContext<{ + items?: string[]; + collection: CollectionKey[]; +} | null>(null); + +function useTabContext() { + const ctx = useContext(TabsContext); + if (!ctx) throw new Error('You must wrap your component in '); + return ctx; +} + +export const TabsList = React.forwardRef< + React.ComponentRef, + React.ComponentPropsWithoutRef +>((props, ref) => ( + +)); +TabsList.displayName = 'TabsList'; + +export const TabsTrigger = React.forwardRef< + React.ComponentRef, + React.ComponentPropsWithoutRef +>((props, ref) => ( + +)); +TabsTrigger.displayName = 'TabsTrigger'; + +export function Tabs({ + ref, + className, + items, + label, + defaultIndex = 0, + defaultValue = items ? escapeValue(items[defaultIndex]) : undefined, + ...props +}: TabsProps) { + const [value, setValue] = useState(defaultValue); + const collection = useMemo(() => [], []); + + return ( + { + if (items && !items.some((item) => escapeValue(item) === v)) return; + setValue(v); + }} + {...props} + > + {items && ( + + {label && ( + {label} + )} + {items.map((item) => ( + + {item} + + ))} + + )} + ({ items, collection }), [collection, items])} + > + {props.children} + + + ); +} + +export interface TabProps + extends Omit, 'value'> { + /** + * Value of tab, detect from index if unspecified. + */ + value?: string; +} + +export function Tab({ value, ...props }: TabProps) { + const { items } = useTabContext(); + const resolved = + value ?? + // eslint-disable-next-line react-hooks/rules-of-hooks -- `value` is not supposed to change + items?.at(useCollectionIndex()); + if (!resolved) + throw new Error( + 'Failed to resolve tab `value`, please pass a `value` prop to the Tab component.', + ); + + return ( + + {props.children} + + ); +} + +export function TabsContent({ + value, + className, + ...props +}: ComponentProps) { + return ( + figure:only-child]:-m-4 [&>figure:only-child]:border-none', + className, + )} + {...props} + > + {props.children} + + ); +} + +/** + * Inspired by Headless UI. + * + * Return the index of children, this is made possible by registering the order of render from children using React context. + * This is supposed by work with pre-rendering & pure client-side rendering. + */ +function useCollectionIndex() { + const key = useId(); + const { collection } = useTabContext(); + + useEffect(() => { + return () => { + const idx = collection.indexOf(key); + if (idx !== -1) collection.splice(idx, 1); + }; + }, [key, collection]); + + if (!collection.includes(key)) collection.push(key); + return collection.indexOf(key); +} + +/** + * only escape whitespaces in values in simple mode + */ +function escapeValue(v: string): string { + return v.toLowerCase().replace(/\s/, '-'); +} diff --git a/apps/docs/src/components/tabs.unstyled.tsx b/apps/docs/src/components/tabs.unstyled.tsx new file mode 100644 index 0000000..920c04e --- /dev/null +++ b/apps/docs/src/components/tabs.unstyled.tsx @@ -0,0 +1,163 @@ +'use client'; + +import { + type ComponentProps, + createContext, + useContext, + useEffectEvent, + useLayoutEffect, + useMemo, + useRef, + useState, +} from 'react'; +import * as Primitive from '@radix-ui/react-tabs'; +import { mergeRefs } from '../lib/merge-refs'; + +type ChangeListener = (v: string) => void; +const listeners = new Map(); + +function addChangeListener(id: string, listener: ChangeListener): void { + const list = listeners.get(id) ?? []; + list.push(listener); + listeners.set(id, list); +} + +function removeChangeListener(id: string, listener: ChangeListener): void { + const list = listeners.get(id) ?? []; + listeners.set( + id, + list.filter((item) => item !== listener), + ); +} + +export interface TabsProps extends ComponentProps { + /** + * Identifier for Sharing value of tabs + */ + groupId?: string; + + /** + * Enable persistent + */ + persist?: boolean; + + /** + * If true, updates the URL hash based on the tab's id + */ + updateAnchor?: boolean; +} + +const TabsContext = createContext<{ + valueToIdMap: Map; +} | null>(null); + +function useTabContext() { + const ctx = useContext(TabsContext); + if (!ctx) throw new Error('You must wrap your component in '); + return ctx; +} + +export const TabsList = Primitive.TabsList; + +export const TabsTrigger = Primitive.TabsTrigger; + +/** + * @internal You better not use it + */ +export function Tabs({ + ref, + groupId, + persist = false, + updateAnchor = false, + defaultValue, + value: _value, + onValueChange: _onValueChange, + ...props +}: TabsProps) { + const tabsRef = useRef(null); + const [value, setValue] = + _value === undefined + ? // eslint-disable-next-line react-hooks/rules-of-hooks -- not supposed to change controlled/uncontrolled + useState(defaultValue) + : [_value, _onValueChange ?? (() => undefined)]; + + const onChange = useEffectEvent((v: string) => setValue(v)); + const valueToIdMap = useMemo(() => new Map(), []); + + useLayoutEffect(() => { + if (!groupId) return; + const previous = persist + ? localStorage.getItem(groupId) + : sessionStorage.getItem(groupId); + + if (previous) onChange(previous); + addChangeListener(groupId, onChange); + return () => { + removeChangeListener(groupId, onChange); + }; + }, [groupId, persist]); + + useLayoutEffect(() => { + const hash = window.location.hash.slice(1); + if (!hash) return; + + for (const [value, id] of valueToIdMap.entries()) { + if (id === hash) { + onChange(value); + tabsRef.current?.scrollIntoView(); + break; + } + } + }, [valueToIdMap]); + + return ( + { + if (updateAnchor) { + const id = valueToIdMap.get(v); + + if (id) { + window.history.replaceState(null, '', `#${id}`); + } + } + + if (groupId) { + listeners.get(groupId)?.forEach((item) => { + item(v); + }); + + if (persist) localStorage.setItem(groupId, v); + else sessionStorage.setItem(groupId, v); + } else { + setValue(v); + } + }} + {...props} + > + ({ valueToIdMap }), [valueToIdMap])} + > + {props.children} + + + ); +} + +export function TabsContent({ + value, + ...props +}: ComponentProps) { + const { valueToIdMap } = useTabContext(); + + if (props.id) { + valueToIdMap.set(value, props.id); + } + + return ( + + {props.children} + + ); +} diff --git a/apps/docs/src/components/ui/button.tsx b/apps/docs/src/components/ui/button.tsx new file mode 100644 index 0000000..b427d4e --- /dev/null +++ b/apps/docs/src/components/ui/button.tsx @@ -0,0 +1,28 @@ +import { cva, type VariantProps } from 'class-variance-authority'; + +const variants = { + primary: 'bg-fd-primary text-fd-primary-foreground hover:bg-fd-primary/80', + outline: 'border hover:bg-fd-accent hover:text-fd-accent-foreground', + ghost: 'hover:bg-fd-accent hover:text-fd-accent-foreground', + secondary: + 'border bg-fd-secondary text-fd-secondary-foreground hover:bg-fd-accent hover:text-fd-accent-foreground', +} as const; + +export const buttonVariants = cva( + 'inline-flex items-center justify-center rounded-md p-2 text-sm font-medium transition-colors duration-100 disabled:pointer-events-none disabled:opacity-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fd-ring', + { + variants: { + variant: variants, + // fumadocs use `color` instead of `variant` + color: variants, + size: { + sm: 'gap-1 px-2 py-1.5 text-xs', + icon: 'p-1.5 [&_svg]:size-5', + 'icon-sm': 'p-1.5 [&_svg]:size-4.5', + 'icon-xs': 'p-1 [&_svg]:size-4', + }, + }, + }, +); + +export type ButtonProps = VariantProps; diff --git a/apps/docs/src/components/ui/collapsible.tsx b/apps/docs/src/components/ui/collapsible.tsx new file mode 100644 index 0000000..dbcf3f0 --- /dev/null +++ b/apps/docs/src/components/ui/collapsible.tsx @@ -0,0 +1,39 @@ +'use client'; +import * as CollapsiblePrimitive from '@radix-ui/react-collapsible'; +import { forwardRef, useEffect, useState } from 'react'; +import { cn } from '../../lib/cn'; + +const Collapsible = CollapsiblePrimitive.Root; + +const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger; + +const CollapsibleContent = forwardRef< + HTMLDivElement, + React.ComponentPropsWithoutRef +>(({ children, ...props }, ref) => { + const [mounted, setMounted] = useState(false); + + useEffect(() => { + setMounted(true); + }, []); + + return ( + + {children} + + ); +}); + +CollapsibleContent.displayName = + CollapsiblePrimitive.CollapsibleContent.displayName; + +export { Collapsible, CollapsibleTrigger, CollapsibleContent }; diff --git a/apps/docs/src/lib/cn.ts b/apps/docs/src/lib/cn.ts new file mode 100644 index 0000000..ba66fd2 --- /dev/null +++ b/apps/docs/src/lib/cn.ts @@ -0,0 +1 @@ +export { twMerge as cn } from 'tailwind-merge'; diff --git a/apps/docs/src/lib/i18n.ts b/apps/docs/src/lib/i18n.ts new file mode 100644 index 0000000..f3a74ca --- /dev/null +++ b/apps/docs/src/lib/i18n.ts @@ -0,0 +1,10 @@ +import { defineI18n } from 'fumadocs-core/i18n'; + +export const i18n = defineI18n({ + defaultLanguage: 'en', + languages: ['en'], + parser: 'dir', + // Future languages: 'es', 'zh', 'pt', etc. +}); + +export type Locale = (typeof i18n.languages)[number]; diff --git a/apps/docs/src/lib/layout.shared.tsx b/apps/docs/src/lib/layout.shared.tsx new file mode 100644 index 0000000..1825eb5 --- /dev/null +++ b/apps/docs/src/lib/layout.shared.tsx @@ -0,0 +1,17 @@ +import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared'; +import { i18n, type Locale } from './i18n'; +import { getTranslation } from './translations'; + +export function baseOptions(locale?: Locale): BaseLayoutProps { + const currentLocale = locale || i18n.defaultLanguage; + const t = getTranslation(currentLocale); + + return { + i18n, + nav: { + title: t.nav.title, + url: `/${currentLocale}`, + }, + githubUrl: 'https://github.com/openworkflowdev/openworkflow', + }; +} diff --git a/apps/docs/src/lib/merge-refs.ts b/apps/docs/src/lib/merge-refs.ts new file mode 100644 index 0000000..7d05f74 --- /dev/null +++ b/apps/docs/src/lib/merge-refs.ts @@ -0,0 +1,15 @@ +import type * as React from 'react'; + +export function mergeRefs( + ...refs: (React.Ref | undefined)[] +): React.RefCallback { + return (value) => { + refs.forEach((ref) => { + if (typeof ref === 'function') { + ref(value); + } else if (ref) { + ref.current = value; + } + }); + }; +} diff --git a/apps/docs/src/lib/source.ts b/apps/docs/src/lib/source.ts new file mode 100644 index 0000000..e045fde --- /dev/null +++ b/apps/docs/src/lib/source.ts @@ -0,0 +1,17 @@ +import { loader } from 'fumadocs-core/source'; +import * as icons from 'lucide-static'; +import { create, docs } from '@/.source'; +import { i18n } from './i18n'; + +export const source = loader({ + source: await create.sourceAsync(docs.doc, docs.meta), + baseUrl: '/docs', + i18n, + icon(icon) { + if (!icon) { + return; + } + + if (icon in icons) return icons[icon as keyof typeof icons]; + }, +}); diff --git a/apps/docs/src/lib/translations/en.ts b/apps/docs/src/lib/translations/en.ts new file mode 100644 index 0000000..00fb094 --- /dev/null +++ b/apps/docs/src/lib/translations/en.ts @@ -0,0 +1,131 @@ +export const en = { + // Navigation + nav: { + title: 'OpenWorkflow', + docs: 'Documentation', + issues: 'Issues', + }, + + // Landing Page + landing: { + badge: 'v0.1 - Active Development', + hero: { + title: 'Durable Workflows,', + titleHighlight: 'Without the Complexity', + subtitle: + 'OpenWorkflow is a TypeScript framework for building reliable, long-running applications that survive crashes and deploys—all without extra servers to manage.', + getStarted: 'Get Started', + viewGithub: 'View on GitHub', + install: 'npm install openworkflow @openworkflow/backend-postgres', + }, + features: { + title: 'Why OpenWorkflow?', + subtitle: + 'Build reliable workflows with automatic retries, crash recovery, and zero operational overhead.', + durableExecution: { + title: 'Durable Execution', + description: + 'Workflows survive crashes, restarts, and deploys. Resume exactly where they left off.', + }, + stepMemoization: { + title: 'Step Memoization', + description: + 'Each step executes exactly once. Results are cached and reused on retry.', + }, + workerDriven: { + title: 'Worker-Driven', + description: + 'No separate orchestrator. Just workers and a database. Simple to operate.', + }, + typeSafe: { + title: 'Type-Safe', + description: + 'Full TypeScript support with generics. Catch errors at compile-time.', + }, + parallelExecution: { + title: 'Parallel Execution', + description: + 'Run steps concurrently with Promise.all. Maximize throughput.', + }, + productionReady: { + title: 'Production Ready', + description: + 'Graceful shutdown, monitoring, and battle-tested PostgreSQL backend.', + }, + }, + howItWorks: { + title: 'How It Works', + subtitle: 'Simple architecture, powerful guarantees', + steps: [ + { + title: 'Define', + description: 'Write workflows with steps as checkpoints', + }, + { + title: 'Start', + description: 'Workers poll database for pending workflows', + }, + { + title: 'Execute', + description: 'Steps run and results are cached', + }, + { + title: 'Resume', + description: 'Crashes? Another worker picks up instantly', + }, + ], + }, + useCases: { + title: 'Built for Real Applications', + subtitle: 'From simple tasks to complex business processes', + cases: [ + { + title: '💳 Payment Processing', + description: + 'Charge cards, update inventory, send receipts—all with automatic retry and rollback support.', + }, + { + title: '📧 Email Campaigns', + description: + 'Send personalized emails at scale with progress tracking and delivery guarantees.', + }, + { + title: '🔄 Data Pipelines', + description: + 'Extract, transform, and load data with checkpointing and automatic recovery.', + }, + { + title: '🛒 Order Fulfillment', + description: + 'Coordinate inventory, shipping, and notifications in one reliable workflow.', + }, + ], + }, + cta: { + title: 'Ready to build reliable workflows?', + subtitle: + 'Get started in minutes with our comprehensive documentation and examples.', + readDocs: 'Read the Docs', + viewExamples: 'View Examples', + }, + footer: { + copyright: '© 2024 OpenWorkflow. Apache 2.0 License.', + }, + }, + + // Common + common: { + close: 'Close', + copy: 'Copy', + copied: 'Copied!', + search: 'Search...', + searchPlaceholder: 'Search...', + theme: { + light: 'Light', + dark: 'Dark', + system: 'System', + }, + }, +} as const; + +export type Translation = typeof en; diff --git a/apps/docs/src/lib/translations/index.ts b/apps/docs/src/lib/translations/index.ts new file mode 100644 index 0000000..86d4ac9 --- /dev/null +++ b/apps/docs/src/lib/translations/index.ts @@ -0,0 +1,20 @@ +import type { Locale } from '../i18n'; +import { en, type Translation } from './en'; + +const translations: Record = { + en, + // Future translations: + // es: () => import('./es').then(m => m.es), + // zh: () => import('./zh').then(m => m.zh), +}; + +export function getTranslation(locale: Locale): Translation { + return translations[locale] || translations.en; +} + +export function useTranslation(locale: Locale) { + const t = getTranslation(locale); + return { t }; +} + +export type { Translation }; diff --git a/apps/docs/src/router.tsx b/apps/docs/src/router.tsx new file mode 100644 index 0000000..d6f335d --- /dev/null +++ b/apps/docs/src/router.tsx @@ -0,0 +1,12 @@ +import { createRouter as createTanStackRouter } from '@tanstack/react-router'; +import { routeTree } from './routeTree.gen'; +import { NotFound } from '@/components/not-found'; + +export function getRouter() { + return createTanStackRouter({ + routeTree, + defaultPreload: 'intent', + scrollRestoration: true, + defaultNotFoundComponent: NotFound, + }); +} diff --git a/apps/docs/src/routes/$lang/docs/$.tsx b/apps/docs/src/routes/$lang/docs/$.tsx new file mode 100644 index 0000000..00200d9 --- /dev/null +++ b/apps/docs/src/routes/$lang/docs/$.tsx @@ -0,0 +1,109 @@ +import { createFileRoute, notFound } from '@tanstack/react-router'; +import { DocsLayout } from 'fumadocs-ui/layouts/docs'; +import { createServerFn } from '@tanstack/react-start'; +import { source } from '@/lib/source'; +import type * as PageTree from 'fumadocs-core/page-tree'; +import { useMemo } from 'react'; +import { docs } from '@/.source'; +import { + DocsBody, + DocsDescription, + DocsPage, + DocsTitle, +} from 'fumadocs-ui/page'; +import { getMDXComponents } from '@/components/mdx-components'; +import { createClientLoader } from 'fumadocs-mdx/runtime/vite'; +import { baseOptions } from '@/lib/layout.shared'; +import { staticFunctionMiddleware } from '@tanstack/start-static-server-functions'; +import type { Locale } from '@/lib/i18n'; + +export const Route = createFileRoute('/$lang/docs/$')({ + component: Page, + loader: async ({ params }) => { + const slugs = params._splat?.split('/') ?? []; + const lang = params.lang; + const data = await loader({ data: { slugs, lang } }); + await clientLoader.preload(data.path); + return data; + }, +}); + +const loader = createServerFn({ + method: 'GET', +}) + .inputValidator((params: { slugs: string[]; lang?: string }) => params) + .middleware([staticFunctionMiddleware]) + .handler(async ({ data: { slugs, lang } }) => { + const page = source.getPage(slugs, lang); + if (!page) throw notFound(); + + return { + tree: source.getPageTree(lang) as object, + path: page.path, + lang, + }; + }); + +const clientLoader = createClientLoader(docs.doc, { + id: 'docs', + component({ toc, frontmatter, default: MDX }) { + return ( + + {frontmatter.title} + {frontmatter.description} + + + + + ); + }, +}); + +function Page() { + const data = Route.useLoaderData(); + const { lang } = Route.useParams(); + const Content = clientLoader.getComponent(data.path); + const tree = useMemo( + () => transformPageTree(data.tree as PageTree.Folder), + [data.tree], + ); + + return ( + + + + ); +} + +function transformPageTree(root: PageTree.Root): PageTree.Root { + function mapNode(item: T): T { + if (typeof item.icon === 'string') { + item = { + ...item, + icon: ( + + ), + }; + } + + if (item.type === 'folder') { + return { + ...item, + index: item.index ? mapNode(item.index) : undefined, + children: item.children.map(mapNode), + }; + } + + return item; + } + + return { + ...root, + children: root.children.map(mapNode), + fallback: root.fallback ? transformPageTree(root.fallback) : undefined, + }; +} diff --git a/apps/docs/src/routes/$lang/index.tsx b/apps/docs/src/routes/$lang/index.tsx new file mode 100644 index 0000000..6190ff4 --- /dev/null +++ b/apps/docs/src/routes/$lang/index.tsx @@ -0,0 +1,261 @@ +import { createFileRoute, Link } from '@tanstack/react-router'; +import { HomeLayout } from 'fumadocs-ui/layouts/home'; +import { baseOptions } from '@/lib/layout.shared'; +import { useTranslation } from '@/lib/translations'; +import type { Locale } from '@/lib/i18n'; +import { CodeBlock, Pre } from 'fumadocs-ui/components/codeblock'; + +export const Route = createFileRoute('/$lang/')({ + component: Home, +}); + +function Home() { + const { lang } = Route.useParams(); + const { t } = useTranslation(lang as Locale); + + return ( + +
+ {/* Hero Section */} +
+
+ {/* Badge */} +
+ 🚀 + {t.landing.badge} +
+ + {/* Heading */} +

+ {t.landing.hero.title}{' '} + + {t.landing.hero.titleHighlight} + +

+ + {/* Subheading */} +

+ {t.landing.hero.subtitle} +

+ + {/* CTA Buttons */} +
+ + {t.landing.hero.getStarted} + + + {t.landing.hero.viewGithub} + +
+ + {/* Install Command */} +
+
+ $ + {t.landing.hero.install} +
+
+
+
+ + + {/* Features Grid */} +
+
+
+

+ {t.landing.features.title} +

+

+ {t.landing.features.subtitle} +

+
+ +
+ {/* Feature 1 */} +
+
+ 💪 +
+

+ {t.landing.features.durableExecution.title} +

+

+ {t.landing.features.durableExecution.description} +

+
+ + {/* Feature 2 */} +
+
+ 🔄 +
+

+ {t.landing.features.stepMemoization.title} +

+

+ {t.landing.features.stepMemoization.description} +

+
+ + {/* Feature 3 */} +
+
+ 🗄️ +
+

+ {t.landing.features.workerDriven.title} +

+

+ {t.landing.features.workerDriven.description} +

+
+ + {/* Feature 4 */} +
+
+ +
+

+ {t.landing.features.typeSafe.title} +

+

+ {t.landing.features.typeSafe.description} +

+
+ + {/* Feature 5 */} +
+
+ 🚀 +
+

+ {t.landing.features.parallelExecution.title} +

+

+ {t.landing.features.parallelExecution.description} +

+
+ + {/* Feature 6 */} +
+
+ 🔒 +
+

+ {t.landing.features.productionReady.title} +

+

+ {t.landing.features.productionReady.description} +

+
+
+
+
+ + + {/* Use Cases */} +
+
+
+

+ {t.landing.useCases.title} +

+

+ {t.landing.useCases.subtitle} +

+
+ +
+ {t.landing.useCases.cases.map((useCase, i) => ( +
+

{useCase.title}

+

+ {useCase.description} +

+
+ ))} +
+
+
+ + {/* CTA Section */} +
+
+

+ {t.landing.cta.title} +

+

+ {t.landing.cta.subtitle} +

+
+ + {t.landing.cta.readDocs} + + + {t.landing.cta.viewExamples} + +
+
+
+ + {/* Footer */} + +
+
+ ); +} diff --git a/apps/docs/src/routes/__root.tsx b/apps/docs/src/routes/__root.tsx new file mode 100644 index 0000000..3936368 --- /dev/null +++ b/apps/docs/src/routes/__root.tsx @@ -0,0 +1,78 @@ +import { + createRootRoute, + HeadContent, + Outlet, + Scripts, + useParams, +} from '@tanstack/react-router'; +import * as React from 'react'; +import appCss from '@/styles/app.css?url'; +import { RootProvider } from 'fumadocs-ui/provider/tanstack'; +import SearchDialog from '@/components/search'; +import { defineI18nUI } from 'fumadocs-ui/i18n'; +import { i18n } from '@/lib/i18n'; +import { getTranslation } from '@/lib/translations'; + +const { provider } = defineI18nUI(i18n, { + translations: { + en: { + displayName: 'English', + search: getTranslation('en').common.search, + searchPlaceholder: getTranslation('en').common.searchPlaceholder, + toc: 'On this page', + lastUpdate: 'Last updated on', + }, + // Future translations can be added here + }, +}); + +export const Route = createRootRoute({ + head: () => ({ + meta: [ + { + charSet: 'utf-8', + }, + { + name: 'viewport', + content: 'width=device-width, initial-scale=1', + }, + { + title: 'OpenWorkflow - Durable Workflows Without the Complexity', + }, + { + name: 'description', + content: + 'OpenWorkflow is a TypeScript framework for building reliable, long-running applications that survive crashes and deploys—all without extra servers to manage.', + }, + ], + links: [{ rel: 'stylesheet', href: appCss }], + }), + component: RootComponent, +}); + +function RootComponent() { + return ( + + + + ); +} + +function RootDocument({ children }: { children: React.ReactNode }) { + const params = useParams({ strict: false }); + const lang = ('lang' in params ? params.lang : i18n.defaultLanguage) as string; + + return ( + + + + + + + {children} + + + + + ); +} diff --git a/apps/docs/src/routes/api/search.ts b/apps/docs/src/routes/api/search.ts new file mode 100644 index 0000000..93b07fb --- /dev/null +++ b/apps/docs/src/routes/api/search.ts @@ -0,0 +1,16 @@ +import { createFileRoute } from '@tanstack/react-router'; +import { source } from '@/lib/source'; +import { createFromSource } from 'fumadocs-core/search/server'; + +const server = createFromSource(source, { + // https://docs.orama.com/docs/orama-js/supported-languages + language: 'english', +}); + +export const Route = createFileRoute('/api/search')({ + server: { + handlers: { + GET: () => server.staticGET(), + }, + }, +}); diff --git a/apps/docs/src/routes/index.tsx b/apps/docs/src/routes/index.tsx new file mode 100644 index 0000000..3b37537 --- /dev/null +++ b/apps/docs/src/routes/index.tsx @@ -0,0 +1,11 @@ +import { createFileRoute, redirect } from '@tanstack/react-router'; +import { i18n } from '@/lib/i18n'; + +export const Route = createFileRoute('/')({ + beforeLoad: () => { + throw redirect({ + to: '/$lang', + params: { lang: i18n.defaultLanguage }, + }); + }, +}); diff --git a/apps/docs/src/styles/app.css b/apps/docs/src/styles/app.css new file mode 100644 index 0000000..50b3bc2 --- /dev/null +++ b/apps/docs/src/styles/app.css @@ -0,0 +1,3 @@ +@import 'tailwindcss'; +@import 'fumadocs-ui/css/neutral.css'; +@import 'fumadocs-ui/css/preset.css'; diff --git a/apps/docs/tsconfig.json b/apps/docs/tsconfig.json new file mode 100644 index 0000000..32543bc --- /dev/null +++ b/apps/docs/tsconfig.json @@ -0,0 +1,24 @@ +{ + "include": ["**/*.ts", "**/*.tsx"], + "compilerOptions": { + "strict": true, + "esModuleInterop": true, + "jsx": "react-jsx", + "module": "ESNext", + "moduleResolution": "Bundler", + "lib": ["DOM", "DOM.Iterable", "ES2022"], + "types": ["vite/client"], + "isolatedModules": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "target": "ES2022", + "allowJs": true, + "forceConsistentCasingInFileNames": true, + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"], + "@/.source": [".source"] + }, + "noEmit": true + } +} diff --git a/apps/docs/vite.config.ts b/apps/docs/vite.config.ts new file mode 100644 index 0000000..67b4090 --- /dev/null +++ b/apps/docs/vite.config.ts @@ -0,0 +1,48 @@ +import react from '@vitejs/plugin-react'; +import { tanstackStart } from '@tanstack/react-start/plugin/vite'; +import { defineConfig } from 'vite'; +import tsConfigPaths from 'vite-tsconfig-paths'; +import tailwindcss from '@tailwindcss/vite'; +import { nitro } from 'nitro/vite' +import mdx from 'fumadocs-mdx/vite'; + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + mdx(await import('./source.config')), + tailwindcss(), + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart({ + spa: { + enabled: true, + prerender: { + enabled: true, + crawlLinks: true, + }, + }, + pages: [ + { + path: '/en/docs', + }, + { + path: '/api/search', + }, + ], + }), + nitro({ + publicAssets: [ + // this is a temporary fix to https://github.com/TanStack/router/issues/5368 + { + dir: "dist/client/__tsr", + baseURL: "/__tsr", + }, + ], + }), + + react(), + ], +}); diff --git a/package-lock.json b/package-lock.json index df5b539..6ebb4c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,8 @@ "": { "name": "openworkflow-project", "workspaces": [ - "packages/*" + "packages/*", + "apps/*" ], "devDependencies": { "@eslint/js": "^9.39.1", @@ -28,9 +29,44 @@ "vitest": "^4.0.7" } }, + "apps/docs": { + "hasInstallScript": true, + "dependencies": { + "@orama/orama": "^3.1.16", + "@radix-ui/react-accordion": "^1.2.12", + "@radix-ui/react-collapsible": "^1.1.12", + "@radix-ui/react-tabs": "^1.1.13", + "@tanstack/react-router": "^1.134.12", + "@tanstack/react-router-devtools": "^1.134.12", + "@tanstack/react-start": "^1.134.12", + "@tanstack/start-static-server-functions": "^1.134.12", + "class-variance-authority": "^0.7.1", + "fumadocs-core": "16.0.8", + "fumadocs-mdx": "13.0.5", + "fumadocs-ui": "16.0.8", + "lucide-react": "^0.553.0", + "lucide-static": "^0.552.0", + "nitro": "^3.0.1-alpha.1", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "tailwind-merge": "^3.3.1", + "vite": "^7.1.12" + }, + "devDependencies": { + "@tailwindcss/vite": "^4.1.16", + "@types/mdx": "^2.0.13", + "@types/node": "^24.10.0", + "@types/react": "^19.2.2", + "@types/react-dom": "^19.2.2", + "@vitejs/plugin-react": "^5.1.0", + "serve": "^14.2.5", + "tailwindcss": "^4.1.16", + "typescript": "^5.9.3", + "vite-tsconfig-paths": "^5.1.4" + } + }, "node_modules/@babel/code-frame": { "version": "7.27.1", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", @@ -41,9 +77,51 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/compat-data": { + "version": "7.28.5", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.5", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/generator": { "version": "7.28.5", - "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.28.5", @@ -56,17 +134,152 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.28.5", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-member-expression-to-functions": "^7.28.5", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.28.5", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/helper-globals": { "version": "7.28.0", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.28.5", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.27.1", + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-string-parser": { "version": "7.27.1", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -74,15 +287,31 @@ }, "node_modules/@babel/helper-validator-identifier": { "version": "7.28.5", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/parser": { "version": "7.28.5", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.28.5" @@ -94,9 +323,110 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.27.1", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.27.1", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.28.5", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.28.5", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-typescript": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/template": { "version": "7.27.2", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -109,7 +439,6 @@ }, "node_modules/@babel/traverse": { "version": "7.28.5", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -126,7 +455,6 @@ }, "node_modules/@babel/types": { "version": "7.28.5", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -138,2746 +466,6422 @@ }, "node_modules/@bcoe/v8-coverage": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", - "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", "dev": true, "license": "MIT", "engines": { "node": ">=18" } }, - "node_modules/@esbuild/aix-ppc64": { + "node_modules/@esbuild/darwin-arm64": { "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", - "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", "cpu": [ - "ppc64" + "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "aix" + "darwin" ], "engines": { "node": ">=18" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", - "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", - "cpu": [ - "arm" - ], + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.0", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", - "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", - "cpu": [ - "arm64" - ], + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", - "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", - "cpu": [ - "x64" - ], + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], "engines": { - "node": ">=18" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint/config-array": { + "version": "0.21.1", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", - "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.12", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", - "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=18" + "node": "*" } }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", - "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", - "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", - "cpu": [ - "arm" - ], + "node_modules/@eslint/core": { + "version": "0.17.0", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", - "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", - "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", - "cpu": [ - "ia32" - ], + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.12", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", - "cpu": [ - "loong64" - ], + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=18" + "node": "*" } }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", - "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", - "cpu": [ - "mips64el" - ], + "node_modules/@eslint/js": { + "version": "9.39.1", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", - "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", - "cpu": [ - "ppc64" - ], + "node_modules/@eslint/object-schema": { + "version": "2.1.7", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", - "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", - "cpu": [ - "riscv64" - ], + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", - "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", - "cpu": [ - "s390x" - ], - "dev": true, + "node_modules/@floating-ui/core": { + "version": "1.7.3", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@floating-ui/utils": "^0.2.10" } }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", - "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/@floating-ui/dom": { + "version": "1.7.4", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" } }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", - "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.6", "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@floating-ui/dom": "^1.7.4" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" } }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", - "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "license": "MIT" + }, + "node_modules/@formatjs/intl-localematcher": { + "version": "0.6.2", "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" + "dependencies": { + "tslib": "^2.8.0" } }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", - "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", - "cpu": [ - "arm64" - ], + "node_modules/@humanfs/core": { + "version": "0.19.1", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], + "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": ">=18.18.0" } }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", - "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", - "cpu": [ - "x64" - ], + "node_modules/@humanfs/node": { + "version": "0.16.7", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, "engines": { - "node": ">=18" + "node": ">=18.18.0" } }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", - "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", - "cpu": [ - "arm64" - ], + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], + "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", - "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", - "cpu": [ - "x64" - ], + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], + "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", - "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", - "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", - "cpu": [ - "ia32" - ], - "dev": true, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", "license": "MIT", - "optional": true, - "os": [ - "win32" - ], "engines": { - "node": ">=18" + "node": ">=6.0.0" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.0", - "dev": true, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mdx-js/mdx": { + "version": "3.1.1", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdx": "^2.0.0", + "acorn": "^8.0.0", + "collapse-white-space": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-util-scope": "^1.0.0", + "estree-walker": "^3.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "markdown-extensions": "^2.0.0", + "recma-build-jsx": "^1.0.0", + "recma-jsx": "^1.0.0", + "recma-stringify": "^1.0.0", + "rehype-recma": "^1.0.0", + "remark-mdx": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "source-map": "^0.7.0", + "unified": "^11.0.0", + "unist-util-position-from-estree": "^2.0.0", + "unist-util-stringify-position": "^4.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "engines": { + "node": ">= 8" } }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", "dev": true, "license": "MIT", "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "node": ">= 8" } }, - "node_modules/@eslint/config-array": { - "version": "0.21.1", + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@eslint/object-schema": "^2.1.7", - "debug": "^4.3.1", - "minimatch": "^3.1.2" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">= 8" } }, - "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.12", - "dev": true, + "node_modules/@oozcitak/dom": { + "version": "1.15.10", "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@oozcitak/infra": "1.0.8", + "@oozcitak/url": "1.0.4", + "@oozcitak/util": "8.3.8" + }, + "engines": { + "node": ">=8.0" } }, - "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "license": "ISC", + "node_modules/@oozcitak/infra": { + "version": "1.0.8", + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" + "@oozcitak/util": "8.3.8" }, "engines": { - "node": "*" + "node": ">=6.0" } }, - "node_modules/@eslint/config-helpers": { - "version": "0.4.2", - "dev": true, - "license": "Apache-2.0", + "node_modules/@oozcitak/url": { + "version": "1.0.4", + "license": "MIT", "dependencies": { - "@eslint/core": "^0.17.0" + "@oozcitak/infra": "1.0.8", + "@oozcitak/util": "8.3.8" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=8.0" } }, - "node_modules/@eslint/core": { - "version": "0.17.0", - "dev": true, + "node_modules/@openworkflow/backend-postgres": { + "resolved": "packages/backend-postgres", + "link": true + }, + "node_modules/@orama/orama": { + "version": "3.1.16", "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">= 20.0.0" } }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.1", + "node_modules/@oxc-transform/binding-linux-arm-musleabihf": { + "optional": true + }, + "node_modules/@oxc-transform/binding-linux-arm64-gnu": { + "optional": true + }, + "node_modules/@oxc-transform/binding-linux-arm64-musl": { + "optional": true + }, + "node_modules/@oxc-transform/binding-linux-riscv64-gnu": { + "optional": true + }, + "node_modules/@oxc-transform/binding-linux-s390x-gnu": { + "optional": true + }, + "node_modules/@oxc-transform/binding-linux-x64-gnu": { + "optional": true + }, + "node_modules/@oxc-transform/binding-linux-x64-musl": { + "optional": true + }, + "node_modules/@oxc-transform/binding-wasm32-wasi": { + "optional": true + }, + "node_modules/@oxc-transform/binding-win32-arm64-msvc": { + "optional": true + }, + "node_modules/@oxc-transform/binding-win32-x64-msvc": { + "optional": true + }, + "node_modules/@pkgr/core": { + "version": "0.2.9", "dev": true, "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://opencollective.com/pkgr" } }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.12", - "dev": true, + "node_modules/@radix-ui/number": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "license": "MIT" + }, + "node_modules/@radix-ui/react-accordion": { + "version": "1.2.12", "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collapsible": "1.1.12", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "5.3.2", - "dev": true, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "@radix-ui/react-primitive": "2.1.3" }, - "engines": { - "node": "*" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@eslint/js": { - "version": "9.39.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", - "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", - "dev": true, + "node_modules/@radix-ui/react-collapsible": { + "version": "1.1.12", "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1" }, - "funding": { - "url": "https://eslint.org/donate" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.7", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@eslint/plugin-kit": { - "version": "0.4.1", - "dev": true, - "license": "Apache-2.0", + "node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "license": "MIT", "dependencies": { - "@eslint/core": "^0.17.0", - "levn": "^0.4.1" + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@humanfs/node": { - "version": "0.16.7", - "dev": true, - "license": "Apache-2.0", + "node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "license": "MIT", "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.4.0" + "@radix-ui/react-use-layout-effect": "1.1.1" }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" + "node_modules/@radix-ui/react-navigation-menu": { + "version": "1.2.14", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "dev": true, + "node_modules/@radix-ui/react-popover": { + "version": "1.1.15", "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "dev": true, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", "license": "MIT", - "engines": { - "node": ">=6.0.0" + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "dev": true, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.8", "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "dev": true, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.9", "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" }, - "engines": { - "node": ">= 8" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "dev": true, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.5", "license": "MIT", - "engines": { - "node": ">= 8" + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "dev": true, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", "license": "MIT", "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "@radix-ui/react-slot": "1.2.3" }, - "engines": { - "node": ">= 8" - } + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.11", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area": { + "version": "1.2.10", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.2.4", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.13", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.40", + "license": "MIT" + }, + "node_modules/@shikijs/core": { + "version": "3.15.0", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.15.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.5" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "3.15.0", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.15.0", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^4.3.3" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "3.15.0", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.15.0", + "@shikijs/vscode-textmate": "^10.0.2" + } + }, + "node_modules/@shikijs/langs": { + "version": "3.15.0", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.15.0" + } + }, + "node_modules/@shikijs/rehype": { + "version": "3.15.0", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.15.0", + "@types/hast": "^3.0.4", + "hast-util-to-string": "^3.0.1", + "shiki": "3.15.0", + "unified": "^11.0.5", + "unist-util-visit": "^5.0.0" + } + }, + "node_modules/@shikijs/themes": { + "version": "3.15.0", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.15.0" + } + }, + "node_modules/@shikijs/transformers": { + "version": "3.15.0", + "license": "MIT", + "dependencies": { + "@shikijs/core": "3.15.0", + "@shikijs/types": "3.15.0" + } + }, + "node_modules/@shikijs/types": { + "version": "3.15.0", + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.17", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "enhanced-resolve": "^5.18.3", + "jiti": "^2.6.1", + "lightningcss": "1.30.2", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.17" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.17", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.17", + "@tailwindcss/oxide-darwin-arm64": "4.1.17", + "@tailwindcss/oxide-darwin-x64": "4.1.17", + "@tailwindcss/oxide-freebsd-x64": "4.1.17", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.17", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.17", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.17", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.17", + "@tailwindcss/oxide-linux-x64-musl": "4.1.17", + "@tailwindcss/oxide-wasm32-wasi": "4.1.17", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.17", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.17" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "dev": true, + "optional": true + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.17", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "dev": true, + "optional": true + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "dev": true, + "optional": true + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "dev": true, + "optional": true + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "dev": true, + "optional": true + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "dev": true, + "optional": true + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "dev": true, + "optional": true + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "dev": true, + "optional": true + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "dev": true, + "optional": true + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "dev": true, + "optional": true + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "dev": true, + "optional": true + }, + "node_modules/@tailwindcss/vite": { + "version": "4.1.17", + "dev": true, + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.1.17", + "@tailwindcss/oxide": "4.1.17", + "tailwindcss": "4.1.17" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7" + } + }, + "node_modules/@tanstack/directive-functions-plugin": { + "version": "1.134.5", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "7.27.1", + "@babel/core": "^7.27.7", + "@babel/traverse": "^7.27.7", + "@babel/types": "^7.27.7", + "@tanstack/router-utils": "1.133.19", + "babel-dead-code-elimination": "^1.0.10", + "pathe": "^2.0.3", + "tiny-invariant": "^1.3.3" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "vite": ">=6.0.0 || >=7.0.0" + } + }, + "node_modules/@tanstack/history": { + "version": "1.133.28", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-router": { + "version": "1.135.0", + "license": "MIT", + "peer": true, + "dependencies": { + "@tanstack/history": "1.133.28", + "@tanstack/react-store": "^0.8.0", + "@tanstack/router-core": "1.134.20", + "isbot": "^5.1.22", + "tiny-invariant": "^1.3.3", + "tiny-warning": "^1.0.3" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=18.0.0 || >=19.0.0", + "react-dom": ">=18.0.0 || >=19.0.0" + } + }, + "node_modules/@tanstack/react-router-devtools": { + "version": "1.135.0", + "license": "MIT", + "dependencies": { + "@tanstack/router-devtools-core": "1.134.20", + "vite": "^7.1.7" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/react-router": "^1.135.0", + "react": ">=18.0.0 || >=19.0.0", + "react-dom": ">=18.0.0 || >=19.0.0" + } + }, + "node_modules/@tanstack/react-start": { + "version": "1.135.0", + "license": "MIT", + "peer": true, + "dependencies": { + "@tanstack/react-router": "1.135.0", + "@tanstack/react-start-client": "1.135.0", + "@tanstack/react-start-server": "1.135.0", + "@tanstack/router-utils": "^1.133.19", + "@tanstack/start-client-core": "1.134.20", + "@tanstack/start-plugin-core": "1.135.0", + "@tanstack/start-server-core": "1.134.20", + "pathe": "^2.0.3" + }, + "engines": { + "node": ">=22.12.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=18.0.0 || >=19.0.0", + "react-dom": ">=18.0.0 || >=19.0.0", + "vite": ">=7.0.0" + } + }, + "node_modules/@tanstack/react-start-client": { + "version": "1.135.0", + "license": "MIT", + "dependencies": { + "@tanstack/react-router": "1.135.0", + "@tanstack/router-core": "1.134.20", + "@tanstack/start-client-core": "1.134.20", + "tiny-invariant": "^1.3.3", + "tiny-warning": "^1.0.3" + }, + "engines": { + "node": ">=22.12.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=18.0.0 || >=19.0.0", + "react-dom": ">=18.0.0 || >=19.0.0" + } + }, + "node_modules/@tanstack/react-start-server": { + "version": "1.135.0", + "license": "MIT", + "dependencies": { + "@tanstack/history": "1.133.28", + "@tanstack/react-router": "1.135.0", + "@tanstack/router-core": "1.134.20", + "@tanstack/start-client-core": "1.134.20", + "@tanstack/start-server-core": "1.134.20" + }, + "engines": { + "node": ">=22.12.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=18.0.0 || >=19.0.0", + "react-dom": ">=18.0.0 || >=19.0.0" + } + }, + "node_modules/@tanstack/react-store": { + "version": "0.8.0", + "license": "MIT", + "dependencies": { + "@tanstack/store": "0.8.0", + "use-sync-external-store": "^1.6.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@tanstack/router-core": { + "version": "1.134.20", + "license": "MIT", + "peer": true, + "dependencies": { + "@tanstack/history": "1.133.28", + "@tanstack/store": "^0.8.0", + "cookie-es": "^2.0.0", + "seroval": "^1.3.2", + "seroval-plugins": "^1.3.2", + "tiny-invariant": "^1.3.3", + "tiny-warning": "^1.0.3" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/router-devtools-core": { + "version": "1.134.20", + "license": "MIT", + "dependencies": { + "clsx": "^2.1.1", + "goober": "^2.1.16", + "vite": "^7.1.7" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/router-core": "^1.134.20", + "csstype": "^3.0.10", + "solid-js": ">=1.9.5", + "tiny-invariant": "^1.3.3" + }, + "peerDependenciesMeta": { + "csstype": { + "optional": true + } + } + }, + "node_modules/@tanstack/router-generator": { + "version": "1.134.20", + "license": "MIT", + "dependencies": { + "@tanstack/router-core": "1.134.20", + "@tanstack/router-utils": "1.133.19", + "@tanstack/virtual-file-routes": "1.133.19", + "prettier": "^3.5.0", + "recast": "^0.23.11", + "source-map": "^0.7.4", + "tsx": "^4.19.2", + "zod": "^3.24.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/router-plugin": { + "version": "1.135.0", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.7", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.27.7", + "@babel/types": "^7.27.7", + "@tanstack/router-core": "1.134.20", + "@tanstack/router-generator": "1.134.20", + "@tanstack/router-utils": "1.133.19", + "@tanstack/virtual-file-routes": "1.133.19", + "babel-dead-code-elimination": "^1.0.10", + "chokidar": "^3.6.0", + "unplugin": "^2.1.2", + "zod": "^3.24.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@rsbuild/core": ">=1.0.2", + "@tanstack/react-router": "^1.135.0", + "vite": ">=5.0.0 || >=6.0.0 || >=7.0.0", + "vite-plugin-solid": "^2.11.10", + "webpack": ">=5.92.0" + }, + "peerDependenciesMeta": { + "@rsbuild/core": { + "optional": true + }, + "@tanstack/react-router": { + "optional": true + }, + "vite": { + "optional": true + }, + "vite-plugin-solid": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/@tanstack/router-utils": { + "version": "1.133.19", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@babel/generator": "^7.27.5", + "@babel/parser": "^7.27.5", + "@babel/preset-typescript": "^7.27.1", + "ansis": "^4.1.0", + "diff": "^8.0.2", + "pathe": "^2.0.3", + "tinyglobby": "^0.2.15" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/server-functions-plugin": { + "version": "1.134.5", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "7.27.1", + "@babel/core": "^7.27.7", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.27.7", + "@babel/types": "^7.27.7", + "@tanstack/directive-functions-plugin": "1.134.5", + "babel-dead-code-elimination": "^1.0.9", + "tiny-invariant": "^1.3.3" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/start-client-core": { + "version": "1.134.20", + "license": "MIT", + "dependencies": { + "@tanstack/router-core": "1.134.20", + "@tanstack/start-storage-context": "1.134.20", + "seroval": "^1.3.2", + "tiny-invariant": "^1.3.3", + "tiny-warning": "^1.0.3" + }, + "engines": { + "node": ">=22.12.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/start-plugin-core": { + "version": "1.135.0", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "7.26.2", + "@babel/core": "^7.26.8", + "@babel/types": "^7.26.8", + "@rolldown/pluginutils": "1.0.0-beta.40", + "@tanstack/router-core": "1.134.20", + "@tanstack/router-generator": "1.134.20", + "@tanstack/router-plugin": "1.135.0", + "@tanstack/router-utils": "1.133.19", + "@tanstack/server-functions-plugin": "1.134.5", + "@tanstack/start-client-core": "1.134.20", + "@tanstack/start-server-core": "1.134.20", + "babel-dead-code-elimination": "^1.0.9", + "cheerio": "^1.0.0", + "exsolve": "^1.0.7", + "pathe": "^2.0.3", + "srvx": "^0.8.2", + "tinyglobby": "^0.2.15", + "ufo": "^1.5.4", + "vitefu": "^1.1.1", + "xmlbuilder2": "^3.1.1", + "zod": "^3.24.2" + }, + "engines": { + "node": ">=22.12.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "vite": ">=7.0.0" + } + }, + "node_modules/@tanstack/start-plugin-core/node_modules/@babel/code-frame": { + "version": "7.26.2", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@tanstack/start-server-core": { + "version": "1.134.20", + "license": "MIT", + "dependencies": { + "@tanstack/history": "1.133.28", + "@tanstack/router-core": "1.134.20", + "@tanstack/start-client-core": "1.134.20", + "@tanstack/start-storage-context": "1.134.20", + "h3-v2": "npm:h3@2.0.0-beta.4", + "seroval": "^1.3.2", + "tiny-invariant": "^1.3.3" + }, + "engines": { + "node": ">=22.12.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/start-static-server-functions": { + "version": "1.135.0", + "license": "MIT", + "dependencies": { + "@tanstack/start-client-core": "1.134.20", + "seroval": "^1.3.2" + }, + "engines": { + "node": ">=22.12.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/react-start": "1.135.0", + "@tanstack/solid-start": "1.135.0" + }, + "peerDependenciesMeta": { + "@tanstack/react-start": { + "optional": true + }, + "@tanstack/solid-start": { + "optional": true + } + } + }, + "node_modules/@tanstack/start-storage-context": { + "version": "1.134.20", + "license": "MIT", + "dependencies": { + "@tanstack/router-core": "1.134.20" + }, + "engines": { + "node": ">=22.12.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/store": { + "version": "0.8.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/virtual-file-routes": { + "version": "1.133.19", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@trivago/prettier-plugin-sort-imports": { + "version": "6.0.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@babel/generator": "^7.28.0", + "@babel/parser": "^7.28.0", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.0", + "javascript-natural-sort": "^0.7.1", + "lodash-es": "^4.17.21", + "minimatch": "^9.0.0", + "parse-imports-exports": "^0.2.4" + }, + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@vue/compiler-sfc": "3.x", + "prettier": "2.x - 3.x", + "prettier-plugin-ember-template-tag": ">= 2.0.0", + "prettier-plugin-svelte": "3.x", + "svelte": "4.x || 5.x" + }, + "peerDependenciesMeta": { + "@vue/compiler-sfc": { + "optional": true + }, + "prettier-plugin-ember-template-tag": { + "optional": true + }, + "prettier-plugin-svelte": { + "optional": true + }, + "svelte": { + "optional": true + } + } + }, + "node_modules/@tsconfig/node22": { + "version": "22.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/strictest": { + "version": "2.0.7", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdx": { + "version": "2.0.13", + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.10.0", + "devOptional": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.2", + "devOptional": true, + "license": "MIT", + "peer": true, + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.2", + "devOptional": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.46.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.46.3", + "@typescript-eslint/type-utils": "8.46.3", + "@typescript-eslint/utils": "8.46.3", + "@typescript-eslint/visitor-keys": "8.46.3", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.46.3", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.46.3", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@typescript-eslint/scope-manager": "8.46.3", + "@typescript-eslint/types": "8.46.3", + "@typescript-eslint/typescript-estree": "8.46.3", + "@typescript-eslint/visitor-keys": "8.46.3", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.46.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.46.3", + "@typescript-eslint/types": "^8.46.3", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.46.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.46.3", + "@typescript-eslint/visitor-keys": "8.46.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.46.3", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.46.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.46.3", + "@typescript-eslint/typescript-estree": "8.46.3", + "@typescript-eslint/utils": "8.46.3", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.46.3", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.46.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.46.3", + "@typescript-eslint/tsconfig-utils": "8.46.3", + "@typescript-eslint/types": "8.46.3", + "@typescript-eslint/visitor-keys": "8.46.3", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.46.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.46.3", + "@typescript-eslint/types": "8.46.3", + "@typescript-eslint/typescript-estree": "8.46.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.46.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.46.3", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "license": "ISC" + }, + "node_modules/@vitejs/plugin-react": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.4", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.43", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.18.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/@vitejs/plugin-react/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.43", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitest/coverage-v8": { + "version": "4.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^1.0.2", + "@vitest/utils": "4.0.8", + "ast-v8-to-istanbul": "^0.3.8", + "debug": "^4.4.3", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-lib-source-maps": "^5.0.6", + "istanbul-reports": "^3.2.0", + "magicast": "^0.5.1", + "std-env": "^3.10.0", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "4.0.8", + "vitest": "4.0.8" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, + "node_modules/@vitest/coverage-v8/node_modules/magicast": { + "version": "0.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vitest/expect": { + "version": "4.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.0.8", + "@vitest/utils": "4.0.8", + "chai": "^6.2.0", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.0.8", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.0.8", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.8", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.0.8", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.8", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@zeit/schemas": { + "version": "2.36.0", + "dev": true, + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.15.0", + "license": "MIT", + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-align/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-align/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/ansi-align/node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-align/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ansis": { + "version": "4.2.0", + "license": "ISC", + "engines": { + "node": ">=14" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/arch": { + "version": "2.2.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/arg": { + "version": "5.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "license": "Python-2.0" + }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/ast-types": { + "version": "0.16.1", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ast-v8-to-istanbul": { + "version": "0.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "estree-walker": "^3.0.3", + "js-tokens": "^9.0.1" + } + }, + "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": { + "version": "9.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/astring": { + "version": "1.9.0", + "license": "MIT", + "bin": { + "astring": "bin/astring" + } + }, + "node_modules/babel-dead-code-elimination": { + "version": "1.0.10", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.23.7", + "@babel/parser": "^7.23.6", + "@babel/traverse": "^7.23.7", + "@babel/types": "^7.23.6" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.25", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "license": "ISC" + }, + "node_modules/boxen": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^7.0.0", + "chalk": "^5.0.1", + "cli-boxes": "^3.0.0", + "string-width": "^5.1.2", + "type-fest": "^2.13.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.0.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/chalk": { + "version": "5.6.2", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.27.0", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "baseline-browser-mapping": "^2.8.19", + "caniuse-lite": "^1.0.30001751", + "electron-to-chromium": "^1.5.238", + "node-releases": "^2.0.26", + "update-browserslist-db": "^1.1.4" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "7.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001754", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chai": { + "version": "6.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk-template": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/chalk-template?sponsor=1" + } + }, + "node_modules/change-case": { + "version": "5.4.4", + "dev": true, + "license": "MIT" + }, + "node_modules/character-entities": { + "version": "2.0.2", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/cheerio": { + "version": "1.1.2", + "license": "MIT", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "encoding-sniffer": "^0.2.1", + "htmlparser2": "^10.0.0", + "parse5": "^7.3.0", + "parse5-htmlparser2-tree-adapter": "^7.1.0", + "parse5-parser-stream": "^7.1.2", + "undici": "^7.12.0", + "whatwg-mimetype": "^4.0.0" + }, + "engines": { + "node": ">=20.18.1" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ci-info": { + "version": "4.3.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, + "node_modules/clean-regexp": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/clean-regexp/node_modules/escape-string-regexp": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clipboardy": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "arch": "^2.2.0", + "execa": "^5.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/collapse-white-space": { + "version": "2.1.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/compression/node_modules/negotiator": { + "version": "0.6.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compute-scroll-into-view": { + "version": "3.1.1", + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.4.2", + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/content-disposition": { + "version": "0.5.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/cookie-es": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/core-js-compat": { + "version": "3.46.0", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.26.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crossws": { + "version": "0.4.1", + "license": "MIT", + "peer": true, + "peerDependencies": { + "srvx": ">=0.7.1" + }, + "peerDependenciesMeta": { + "srvx": { + "optional": true + } + } + }, + "node_modules/css-select": { + "version": "5.2.2", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "license": "MIT", + "peer": true + }, + "node_modules/db0": { + "version": "0.3.4", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@electric-sql/pglite": "*", + "@libsql/client": "*", + "better-sqlite3": "*", + "drizzle-orm": "*", + "mysql2": "*", + "sqlite3": "*" + }, + "peerDependenciesMeta": { + "@electric-sql/pglite": { + "optional": true + }, + "@libsql/client": { + "optional": true + }, + "better-sqlite3": { + "optional": true + }, + "drizzle-orm": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "sqlite3": { + "optional": true + } + } + }, + "node_modules/debug": { + "version": "4.4.3", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.2.0", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/dequal": { + "version": "2.0.3", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-indent": { + "version": "7.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "devOptional": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-newline": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/diff": { + "version": "8.0.2", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/docs": { + "resolved": "apps/docs", + "link": true + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.249", + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "dev": true, + "license": "MIT" + }, + "node_modules/encoding-sniffer": { + "version": "0.2.1", + "license": "MIT", + "dependencies": { + "iconv-lite": "^0.6.3", + "whatwg-encoding": "^3.1.1" + }, + "funding": { + "url": "https://github.com/fb55/encoding-sniffer?sponsor=1" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.18.3", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "dev": true, + "license": "MIT" + }, + "node_modules/esast-util-from-estree": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esast-util-from-js": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "acorn": "^8.0.0", + "esast-util-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esbuild": { + "version": "0.25.12", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/@openworkflow/backend-postgres": { - "resolved": "packages/backend-postgres", - "link": true + "node_modules/esbuild/node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.1", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.1", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-prettier": { + "version": "10.1.8", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-sonarjs": { + "version": "3.0.5", + "dev": true, + "license": "LGPL-3.0-only", + "dependencies": { + "@eslint-community/regexpp": "4.12.1", + "builtin-modules": "3.3.0", + "bytes": "3.1.2", + "functional-red-black-tree": "1.0.1", + "jsx-ast-utils-x": "0.1.0", + "lodash.merge": "4.6.2", + "minimatch": "9.0.5", + "scslre": "0.3.0", + "semver": "7.7.2", + "typescript": ">=5" + }, + "peerDependencies": { + "eslint": "^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-sonarjs/node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/eslint-plugin-unicorn": { + "version": "62.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "@eslint-community/eslint-utils": "^4.9.0", + "@eslint/plugin-kit": "^0.4.0", + "change-case": "^5.4.4", + "ci-info": "^4.3.1", + "clean-regexp": "^1.0.0", + "core-js-compat": "^3.46.0", + "esquery": "^1.6.0", + "find-up-simple": "^1.0.1", + "globals": "^16.4.0", + "indent-string": "^5.0.0", + "is-builtin-module": "^5.0.0", + "jsesc": "^3.1.0", + "pluralize": "^8.0.0", + "regexp-tree": "^0.1.27", + "regjsparser": "^0.13.0", + "semver": "^7.7.3", + "strip-indent": "^4.1.1" + }, + "engines": { + "node": "^20.10.0 || >=21.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" + }, + "peerDependencies": { + "eslint": ">=9.38.0" + } }, - "node_modules/@pkgr/core": { - "version": "0.2.9", + "node_modules/eslint-plugin-unicorn/node_modules/globals": { + "version": "16.5.0", "dev": true, "license": "MIT", "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + "node": ">=18" }, "funding": { - "url": "https://opencollective.com/pkgr" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.53.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.1.tgz", - "integrity": "sha512-bxZtughE4VNVJlL1RdoSE545kc4JxL7op57KKoi59/gwuU5rV6jLWFXXc8jwgFoT6vtj+ZjO+Z2C5nrY0Cl6wA==", - "cpu": [ - "arm" - ], + "node_modules/eslint-plugin-unicorn/node_modules/semver": { + "version": "7.7.3", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.53.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.1.tgz", - "integrity": "sha512-44a1hreb02cAAfAKmZfXVercPFaDjqXCK+iKeVOlJ9ltvnO6QqsBHgKVPTu+MJHSLLeMEUbeG2qiDYgbFPU48g==", - "cpu": [ - "arm64" - ], + "node_modules/eslint-scope": { + "version": "8.4.0", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.53.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.1.tgz", - "integrity": "sha512-usmzIgD0rf1syoOZ2WZvy8YpXK5G1V3btm3QZddoGSa6mOgfXWkkv+642bfUUldomgrbiLQGrPryb7DXLovPWQ==", - "cpu": [ - "arm64" - ], + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.53.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.1.tgz", - "integrity": "sha512-is3r/k4vig2Gt8mKtTlzzyaSQ+hd87kDxiN3uDSDwggJLUV56Umli6OoL+/YZa/KvtdrdyNfMKHzL/P4siOOmg==", - "cpu": [ - "x64" - ], + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.12", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.53.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.1.tgz", - "integrity": "sha512-QJ1ksgp/bDJkZB4daldVmHaEQkG4r8PUXitCOC2WRmRaSaHx5RwPoI3DHVfXKwDkB+Sk6auFI/+JHacTekPRSw==", - "cpu": [ - "arm64" - ], + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.53.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.1.tgz", - "integrity": "sha512-J6ma5xgAzvqsnU6a0+jgGX/gvoGokqpkx6zY4cWizRrm0ffhHDpJKQgC8dtDb3+MqfZDIqs64REbfHDMzxLMqQ==", - "cpu": [ - "x64" - ], + "node_modules/espree": { + "version": "10.4.0", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.53.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.1.tgz", - "integrity": "sha512-JzWRR41o2U3/KMNKRuZNsDUAcAVUYhsPuMlx5RUldw0E4lvSIXFUwejtYz1HJXohUmqs/M6BBJAUBzKXZVddbg==", - "cpu": [ - "arm" - ], + "node_modules/esprima": { + "version": "4.0.1", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.6.0", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.53.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.1.tgz", - "integrity": "sha512-L8kRIrnfMrEoHLHtHn+4uYA52fiLDEDyezgxZtGUTiII/yb04Krq+vk3P2Try+Vya9LeCE9ZHU8CXD6J9EhzHQ==", - "cpu": [ - "arm" - ], + "node_modules/esrecurse": { + "version": "4.3.0", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.53.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.1.tgz", - "integrity": "sha512-ysAc0MFRV+WtQ8li8hi3EoFi7us6d1UzaS/+Dp7FYZfg3NdDljGMoVyiIp6Ucz7uhlYDBZ/zt6XI0YEZbUO11Q==", - "cpu": [ - "arm64" - ], + "node_modules/estraverse": { + "version": "5.3.0", "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-util-attach-comments": { + "version": "3.0.0", "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-build-jsx": { + "version": "3.0.1", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-walker": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-scope": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-to-js": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "astring": "^1.8.0", + "source-map": "^0.7.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-value-to-estree": { + "version": "3.5.0", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/remcohaszing" + } + }, + "node_modules/estree-util-visit": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.53.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.1.tgz", - "integrity": "sha512-UV6l9MJpDbDZZ/fJvqNcvO1PcivGEf1AvKuTcHoLjVZVFeAMygnamCTDikCVMRnA+qJe+B3pSbgX2+lBMqgBhA==", - "cpu": [ - "arm64" - ], + "node_modules/execa": { + "version": "5.1.1", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.53.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.1.tgz", - "integrity": "sha512-UDUtelEprkA85g95Q+nj3Xf0M4hHa4DiJ+3P3h4BuGliY4NReYYqwlc0Y8ICLjN4+uIgCEvaygYlpf0hUj90Yg==", - "cpu": [ - "loong64" - ], + "node_modules/expect-type": { + "version": "1.2.2", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.53.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.1.tgz", - "integrity": "sha512-vrRn+BYhEtNOte/zbc2wAUQReJXxEx2URfTol6OEfY2zFEUK92pkFBSXRylDM7aHi+YqEPJt9/ABYzmcrS4SgQ==", - "cpu": [ - "ppc64" - ], + "node_modules/exsolve": { + "version": "1.0.8", + "license": "MIT" + }, + "node_modules/extend": { + "version": "3.0.2", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "license": "MIT" }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.53.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.1.tgz", - "integrity": "sha512-gto/1CxHyi4A7YqZZNznQYrVlPSaodOBPKM+6xcDSCMVZN/Fzb4K+AIkNz/1yAYz9h3Ng+e2fY9H6bgawVq17w==", - "cpu": [ - "riscv64" - ], + "node_modules/fast-glob": { + "version": "3.3.3", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.53.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.1.tgz", - "integrity": "sha512-KZ6Vx7jAw3aLNjFR8eYVcQVdFa/cvBzDNRFM3z7XhNNunWjA03eUrEwJYPk0G8V7Gs08IThFKcAPS4WY/ybIrQ==", - "cpu": [ - "riscv64" - ], + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.53.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.1.tgz", - "integrity": "sha512-HvEixy2s/rWNgpwyKpXJcHmE7om1M89hxBTBi9Fs6zVuLU4gOrEMQNbNsN/tBVIMbLyysz/iwNiGtMOpLAOlvA==", - "cpu": [ - "s390x" - ], + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "license": "MIT" }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.53.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.1.tgz", - "integrity": "sha512-E/n8x2MSjAQgjj9IixO4UeEUeqXLtiA7pyoXCFYLuXpBA/t2hnbIdxHfA7kK9BFsYAoNU4st1rHYdldl8dTqGA==", - "cpu": [ - "x64" - ], + "node_modules/fast-levenshtein": { + "version": "2.0.6", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "license": "MIT" }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.53.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.1.tgz", - "integrity": "sha512-IhJ087PbLOQXCN6Ui/3FUkI9pWNZe/Z7rEIVOzMsOs1/HSAECCvSZ7PkIbkNqL/AZn6WbZvnoVZw/qwqYMo4/w==", - "cpu": [ - "x64" - ], + "node_modules/fastq": { + "version": "1.19.1", "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fdir": { + "version": "6.5.0", "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.53.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.1.tgz", - "integrity": "sha512-0++oPNgLJHBblreu0SFM7b3mAsBJBTY0Ksrmu9N6ZVrPiTkRgda52mWR7TKhHAsUb9noCjFvAw9l6ZO1yzaVbA==", - "cpu": [ - "arm64" - ], + "node_modules/fetchdts": { + "version": "0.1.7", + "license": "MIT" + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.53.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.1.tgz", - "integrity": "sha512-VJXivz61c5uVdbmitLkDlbcTk9Or43YC2QVLRkqp86QoeFSqI81bNgjhttqhKNMKnQMWnecOCm7lZz4s+WLGpQ==", - "cpu": [ - "arm64" - ], + "node_modules/fill-range": { + "version": "7.1.1", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.53.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.1.tgz", - "integrity": "sha512-NmZPVTUOitCXUH6erJDzTQ/jotYw4CnkMDjCYRxNHVD9bNyfrGoIse684F9okwzKCV4AIHRbUkeTBc9F2OOH5Q==", - "cpu": [ - "ia32" - ], + "node_modules/find-up-simple": { + "version": "1.0.1", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.53.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.1.tgz", - "integrity": "sha512-2SNj7COIdAf6yliSpLdLG8BEsp5lgzRehgfkP0Av8zKfQFKku6JcvbobvHASPJu4f3BFxej5g+HuQPvqPhHvpQ==", - "cpu": [ - "x64" - ], + "node_modules/flat-cache": { + "version": "4.0.1", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.53.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.1.tgz", - "integrity": "sha512-rLarc1Ofcs3DHtgSzFO31pZsCh8g05R2azN1q3fF+H423Co87My0R+tazOEvYVKXSLh8C4LerMK41/K7wlklcg==", - "cpu": [ - "x64" - ], + "node_modules/flatted": { + "version": "3.3.3", "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", "license": "MIT", "optional": true, "os": [ - "win32" - ] - }, - "node_modules/@standard-schema/spec": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", - "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", - "dev": true, - "license": "MIT" + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } }, - "node_modules/@trivago/prettier-plugin-sort-imports": { - "version": "6.0.0", - "dev": true, - "license": "Apache-2.0", + "node_modules/fumadocs-core": { + "version": "16.0.8", + "license": "MIT", + "peer": true, "dependencies": { - "@babel/generator": "^7.28.0", - "@babel/parser": "^7.28.0", - "@babel/traverse": "^7.28.0", - "@babel/types": "^7.28.0", - "javascript-natural-sort": "^0.7.1", - "lodash-es": "^4.17.21", - "minimatch": "^9.0.0", - "parse-imports-exports": "^0.2.4" - }, - "engines": { - "node": ">= 20" + "@formatjs/intl-localematcher": "^0.6.2", + "@orama/orama": "^3.1.16", + "@shikijs/rehype": "^3.14.0", + "@shikijs/transformers": "^3.14.0", + "estree-util-value-to-estree": "^3.5.0", + "github-slugger": "^2.0.0", + "hast-util-to-estree": "^3.1.3", + "hast-util-to-jsx-runtime": "^2.3.6", + "image-size": "^2.0.2", + "negotiator": "^1.0.0", + "npm-to-yarn": "^3.0.1", + "path-to-regexp": "^8.3.0", + "remark": "^15.0.1", + "remark-gfm": "^4.0.1", + "remark-rehype": "^11.1.2", + "scroll-into-view-if-needed": "^3.1.0", + "shiki": "^3.14.0", + "unist-util-visit": "^5.0.0" }, "peerDependencies": { - "@vue/compiler-sfc": "3.x", - "prettier": "2.x - 3.x", - "prettier-plugin-ember-template-tag": ">= 2.0.0", - "prettier-plugin-svelte": "3.x", - "svelte": "4.x || 5.x" + "@mixedbread/sdk": "^0.19.0", + "@orama/core": "1.x.x", + "@tanstack/react-router": "1.x.x", + "@types/react": "*", + "algoliasearch": "5.x.x", + "lucide-react": "*", + "next": "16.x.x", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "react-router": "7.x.x", + "waku": "^0.26.0" }, "peerDependenciesMeta": { - "@vue/compiler-sfc": { + "@mixedbread/sdk": { "optional": true }, - "prettier-plugin-ember-template-tag": { + "@orama/core": { "optional": true }, - "prettier-plugin-svelte": { + "@tanstack/react-router": { "optional": true }, - "svelte": { + "@types/react": { + "optional": true + }, + "algoliasearch": { + "optional": true + }, + "lucide-react": { + "optional": true + }, + "next": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-router": { + "optional": true + }, + "waku": { "optional": true } } }, - "node_modules/@tsconfig/node22": { - "version": "22.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/strictest": { - "version": "2.0.7", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/chai": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", - "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/deep-eql": "*", - "assertion-error": "^2.0.1" - } - }, - "node_modules/@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "24.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz", - "integrity": "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==", - "dev": true, + "node_modules/fumadocs-mdx": { + "version": "13.0.5", "license": "MIT", "dependencies": { - "undici-types": "~7.16.0" + "@mdx-js/mdx": "^3.1.1", + "@standard-schema/spec": "^1.0.0", + "chokidar": "^4.0.3", + "esbuild": "^0.25.11", + "estree-util-value-to-estree": "^3.5.0", + "js-yaml": "^4.1.0", + "lru-cache": "^11.2.2", + "mdast-util-to-markdown": "^2.1.2", + "picocolors": "^1.1.1", + "picomatch": "^4.0.3", + "remark-mdx": "^3.1.1", + "tinyexec": "^1.0.1", + "tinyglobby": "^0.2.15", + "unified": "^11.0.5", + "unist-util-remove-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "zod": "^4.1.12" + }, + "bin": { + "fumadocs-mdx": "dist/bin.js" + }, + "peerDependencies": { + "@fumadocs/mdx-remote": "^1.4.0", + "fumadocs-core": "^15.0.0 || ^16.0.0", + "next": "^15.3.0 || ^16.0.0", + "react": "*", + "vite": "6.x.x || 7.x.x" + }, + "peerDependenciesMeta": { + "@fumadocs/mdx-remote": { + "optional": true + }, + "next": { + "optional": true + }, + "react": { + "optional": true + }, + "vite": { + "optional": true + } } }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.46.2", - "dev": true, + "node_modules/fumadocs-mdx/node_modules/chokidar": { + "version": "4.0.3", "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.46.2", - "@typescript-eslint/type-utils": "8.46.2", - "@typescript-eslint/utils": "8.46.2", - "@typescript-eslint/visitor-keys": "8.46.2", - "graphemer": "^1.4.0", - "ignore": "^7.0.0", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.1.0" + "readdirp": "^4.0.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">= 14.16.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.46.2", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" + "url": "https://paulmillr.com/funding/" } }, - "node_modules/@typescript-eslint/parser": { - "version": "8.46.2", - "dev": true, + "node_modules/fumadocs-mdx/node_modules/lru-cache": { + "version": "11.2.2", + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/fumadocs-mdx/node_modules/readdirp": { + "version": "4.1.2", "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.46.2", - "@typescript-eslint/types": "8.46.2", - "@typescript-eslint/typescript-estree": "8.46.2", - "@typescript-eslint/visitor-keys": "8.46.2", - "debug": "^4.3.4" - }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">= 14.18.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.46.2", - "dev": true, + "node_modules/fumadocs-mdx/node_modules/tinyexec": { + "version": "1.0.2", "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.46.2", - "@typescript-eslint/types": "^8.46.2", - "debug": "^4.3.4" - }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, + "node": ">=18" + } + }, + "node_modules/fumadocs-mdx/node_modules/zod": { + "version": "4.1.12", + "license": "MIT", "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "url": "https://github.com/sponsors/colinhacks" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.46.2", - "dev": true, + "node_modules/fumadocs-ui": { + "version": "16.0.8", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.46.2", - "@typescript-eslint/visitor-keys": "8.46.2" + "@radix-ui/react-accordion": "^1.2.12", + "@radix-ui/react-collapsible": "^1.1.12", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-direction": "^1.1.1", + "@radix-ui/react-navigation-menu": "^1.2.14", + "@radix-ui/react-popover": "^1.1.15", + "@radix-ui/react-presence": "^1.1.5", + "@radix-ui/react-scroll-area": "^1.2.10", + "@radix-ui/react-slot": "^1.2.4", + "@radix-ui/react-tabs": "^1.1.13", + "class-variance-authority": "^0.7.1", + "fumadocs-core": "16.0.8", + "lodash.merge": "^4.6.2", + "next-themes": "^0.4.6", + "postcss-selector-parser": "^7.1.0", + "react-medium-image-zoom": "^5.4.0", + "scroll-into-view-if-needed": "^3.1.0", + "tailwind-merge": "^3.3.1" }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "peerDependencies": { + "@types/react": "*", + "next": "16.x.x", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "tailwindcss": "^4.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "next": { + "optional": true + }, + "tailwindcss": { + "optional": true + } } }, - "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.46.2", + "node_modules/functional-red-black-tree": { + "version": "1.0.1", "dev": true, + "license": "MIT" + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "node": ">=6.9.0" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.46.2", - "dev": true, + "node_modules/get-nonce": { + "version": "1.0.1", "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.46.2", - "@typescript-eslint/typescript-estree": "8.46.2", - "@typescript-eslint/utils": "8.46.2", - "debug": "^4.3.4", - "ts-api-utils": "^2.1.0" - }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" + "node": ">=6" } }, - "node_modules/@typescript-eslint/types": { - "version": "8.46.2", + "node_modules/get-stream": { + "version": "6.0.1", "dev": true, "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.46.2", - "dev": true, + "node_modules/get-tsconfig": { + "version": "4.13.0", "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.46.2", - "@typescript-eslint/tsconfig-utils": "8.46.2", - "@typescript-eslint/types": "8.46.2", - "@typescript-eslint/visitor-keys": "8.46.2", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^2.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "resolve-pkg-maps": "^1.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, - "node_modules/@typescript-eslint/utils": { - "version": "8.46.2", + "node_modules/git-hooks-list": { + "version": "4.1.1", "dev": true, "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.46.2", - "@typescript-eslint/types": "8.46.2", - "@typescript-eslint/typescript-estree": "8.46.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" + "url": "https://github.com/fisker/git-hooks-list?sponsor=1" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.46.2", + "node_modules/github-slugger": { + "version": "2.0.0", + "license": "ISC" + }, + "node_modules/glob-parent": { + "version": "6.0.2", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@typescript-eslint/types": "8.46.2", - "eslint-visitor-keys": "^4.2.1" + "is-glob": "^4.0.3" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=10.13.0" } }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "4.2.1", + "node_modules/globals": { + "version": "14.0.0", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@vitest/coverage-v8": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.0.8.tgz", - "integrity": "sha512-wQgmtW6FtPNn4lWUXi8ZSYLpOIb92j3QCujxX3sQ81NTfQ/ORnE0HtK7Kqf2+7J9jeveMGyGyc4NWc5qy3rC4A==", + "node_modules/globrex": { + "version": "0.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/goober": { + "version": "2.1.18", + "license": "MIT", + "peerDependencies": { + "csstype": "^3.0.10" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "dev": true, + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", "dev": true, + "license": "MIT" + }, + "node_modules/h3-v2": { + "name": "h3", + "version": "2.0.0-beta.4", "license": "MIT", "dependencies": { - "@bcoe/v8-coverage": "^1.0.2", - "@vitest/utils": "4.0.8", - "ast-v8-to-istanbul": "^0.3.8", - "debug": "^4.4.3", - "istanbul-lib-coverage": "^3.2.2", - "istanbul-lib-report": "^3.0.1", - "istanbul-lib-source-maps": "^5.0.6", - "istanbul-reports": "^3.2.0", - "magicast": "^0.5.1", - "std-env": "^3.10.0", - "tinyrainbow": "^3.0.3" + "cookie-es": "^2.0.0", + "fetchdts": "^0.1.6", + "rou3": "^0.7.3", + "srvx": "^0.8.7" }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": ">=20.11.1" }, "peerDependencies": { - "@vitest/browser": "4.0.8", - "vitest": "4.0.8" + "crossws": "^0.4.1" }, "peerDependenciesMeta": { - "@vitest/browser": { + "crossws": { "optional": true } } }, - "node_modules/@vitest/expect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.8.tgz", - "integrity": "sha512-Rv0eabdP/xjAHQGr8cjBm+NnLHNoL268lMDK85w2aAGLFoVKLd8QGnVon5lLtkXQCoYaNL0wg04EGnyKkkKhPA==", + "node_modules/has-flag": { + "version": "4.0.0", "dev": true, "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hast-util-to-estree": { + "version": "3.1.3", + "license": "MIT", "dependencies": { - "@standard-schema/spec": "^1.0.0", - "@types/chai": "^5.2.2", - "@vitest/spy": "4.0.8", - "@vitest/utils": "4.0.8", - "chai": "^6.2.0", - "tinyrainbow": "^3.0.3" + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-attach-comments": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "zwitch": "^2.0.0" }, "funding": { - "url": "https://opencollective.com/vitest" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/@vitest/mocker": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.8.tgz", - "integrity": "sha512-9FRM3MZCedXH3+pIh+ME5Up2NBBHDq0wqwhOKkN4VnvCiKbVxddqH9mSGPZeawjd12pCOGnl+lo/ZGHt0/dQSg==", - "dev": true, + "node_modules/hast-util-to-html": { + "version": "9.0.5", "license": "MIT", "dependencies": { - "@vitest/spy": "4.0.8", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.21" + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" }, "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0-0" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/@vitest/pretty-format": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.8.tgz", - "integrity": "sha512-qRrjdRkINi9DaZHAimV+8ia9Gq6LeGz2CgIEmMLz3sBDYV53EsnLZbJMR1q84z1HZCMsf7s0orDgZn7ScXsZKg==", - "dev": true, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.6", "license": "MIT", "dependencies": { - "tinyrainbow": "^3.0.3" + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" }, "funding": { - "url": "https://opencollective.com/vitest" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/@vitest/runner": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.8.tgz", - "integrity": "sha512-mdY8Sf1gsM8hKJUQfiPT3pn1n8RF4QBcJYFslgWh41JTfrK1cbqY8whpGCFzBl45LN028g0njLCYm0d7XxSaQQ==", - "dev": true, + "node_modules/hast-util-to-string": { + "version": "3.0.1", "license": "MIT", "dependencies": { - "@vitest/utils": "4.0.8", - "pathe": "^2.0.3" + "@types/hast": "^3.0.0" }, "funding": { - "url": "https://opencollective.com/vitest" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/@vitest/snapshot": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.8.tgz", - "integrity": "sha512-Nar9OTU03KGiubrIOFhcfHg8FYaRaNT+bh5VUlNz8stFhCZPNrJvmZkhsr1jtaYvuefYFwK2Hwrq026u4uPWCw==", - "dev": true, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.0.8", - "magic-string": "^0.30.21", - "pathe": "^2.0.3" + "@types/hast": "^3.0.0" }, "funding": { - "url": "https://opencollective.com/vitest" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/@vitest/spy": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.8.tgz", - "integrity": "sha512-nvGVqUunyCgZH7kmo+Ord4WgZ7lN0sOULYXUOYuHr55dvg9YvMz3izfB189Pgp28w0vWFbEEfNc/c3VTrqrXeA==", + "node_modules/html-escaper": { + "version": "2.0.2", "dev": true, + "license": "MIT" + }, + "node_modules/html-void-elements": { + "version": "3.0.0", "license": "MIT", "funding": { - "url": "https://opencollective.com/vitest" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/@vitest/utils": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.8.tgz", - "integrity": "sha512-pdk2phO5NDvEFfUTxcTP8RFYjVj/kfLSPIN5ebP2Mu9kcIMeAQTbknqcFEyBcC4z2pJlJI9aS5UQjcYfhmKAow==", - "dev": true, + "node_modules/htmlparser2": { + "version": "10.0.0", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.0.8", - "tinyrainbow": "^3.0.3" + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.1", + "entities": "^6.0.0" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "6.0.1", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" }, "funding": { - "url": "https://opencollective.com/vitest" + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/acorn": { - "version": "8.15.0", + "node_modules/human-signals": { + "version": "2.1.0", "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", "license": "MIT", - "bin": { - "acorn": "bin/acorn" + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { - "node": ">=0.4.0" + "node": ">=0.10.0" } }, - "node_modules/acorn-jsx": { + "node_modules/ignore": { "version": "5.3.2", "dev": true, "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "engines": { + "node": ">= 4" } }, - "node_modules/ajv": { - "version": "6.12.6", - "dev": true, + "node_modules/image-size": { + "version": "2.0.2", "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "bin": { + "image-size": "bin/image-size.js" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "engines": { + "node": ">=16.x" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", + "node_modules/import-fresh": { + "version": "3.3.1", "dev": true, "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=6" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/argparse": { - "version": "2.0.1", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "node_modules/imurmurhash": { + "version": "0.1.4", "dev": true, "license": "MIT", "engines": { - "node": ">=12" + "node": ">=0.8.19" } }, - "node_modules/ast-v8-to-istanbul": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.8.tgz", - "integrity": "sha512-szgSZqUxI5T8mLKvS7WTjF9is+MVbOeLADU73IseOcrqhxr/VAvy6wfoVE39KnKzA7JRhjF5eUagNlHwvZPlKQ==", + "node_modules/indent-string": { + "version": "5.0.0", "dev": true, "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.31", - "estree-walker": "^3.0.3", - "js-tokens": "^9.0.1" + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", - "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "node_modules/ini": { + "version": "1.3.8", "dev": true, - "license": "MIT" + "license": "ISC" }, - "node_modules/balanced-match": { - "version": "1.0.2", - "dev": true, + "node_modules/inline-style-parser": { + "version": "0.2.6", "license": "MIT" }, - "node_modules/baseline-browser-mapping": { - "version": "2.8.20", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.js" + "node_modules/is-alphabetical": { + "version": "2.0.1", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/brace-expansion": { - "version": "2.0.2", - "dev": true, + "node_modules/is-alphanumerical": { + "version": "2.0.1", "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/braces": { - "version": "3.0.3", - "dev": true, + "node_modules/is-binary-path": { + "version": "2.1.0", "license": "MIT", "dependencies": { - "fill-range": "^7.1.1" + "binary-extensions": "^2.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/browserslist": { - "version": "4.27.0", + "node_modules/is-builtin-module": { + "version": "5.0.0", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.8.19", - "caniuse-lite": "^1.0.30001751", - "electron-to-chromium": "^1.5.238", - "node-releases": "^2.0.26", - "update-browserslist-db": "^1.1.4" + "builtin-modules": "^5.0.0" }, - "bin": { - "browserslist": "cli.js" + "engines": { + "node": ">=18.20" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-builtin-module/node_modules/builtin-modules": { + "version": "5.0.0", + "dev": true, + "license": "MIT", "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + "node": ">=18.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/builtin-modules": { - "version": "3.3.0", + "node_modules/is-decimal": { + "version": "2.0.1", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", "dev": true, "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, "engines": { - "node": ">=6" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/bytes": { - "version": "3.1.2", - "dev": true, + "node_modules/is-extglob": { + "version": "2.1.1", "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">=0.10.0" } }, - "node_modules/callsites": { - "version": "3.1.0", + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001751", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/chai": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.0.tgz", - "integrity": "sha512-aUTnJc/JipRzJrNADXVvpVqi6CO0dn3nx4EVPxijri+fj3LUUDyZQOgVeW54Ob3Y1Xh9Iz8f+CgaCl8v0mn9bA==", - "dev": true, + "node_modules/is-glob": { + "version": "4.0.3", "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, "engines": { - "node": ">=18" + "node": ">=0.10.0" } }, - "node_modules/chalk": { - "version": "4.1.2", - "dev": true, + "node_modules/is-hexadecimal": { + "version": "2.0.1", "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/change-case": { - "version": "5.4.4", - "dev": true, - "license": "MIT" + "node_modules/is-number": { + "version": "7.0.0", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } }, - "node_modules/ci-info": { - "version": "4.3.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], + "node_modules/is-plain-obj": { + "version": "4.1.0", "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/clean-regexp": { - "version": "1.0.0", + "node_modules/is-port-reachable": { + "version": "4.0.0", "dev": true, "license": "MIT", - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, "engines": { - "node": ">=4" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/clean-regexp/node_modules/escape-string-regexp": { - "version": "1.0.5", + "node_modules/is-stream": { + "version": "2.0.1", "dev": true, "license": "MIT", "engines": { - "node": ">=0.8.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/color-convert": { - "version": "2.0.1", + "node_modules/is-wsl": { + "version": "2.2.0", "dev": true, "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "is-docker": "^2.0.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=8" } }, - "node_modules/color-name": { - "version": "1.1.4", + "node_modules/isbot": { + "version": "5.1.32", + "license": "Unlicense", + "engines": { + "node": ">=18" + } + }, + "node_modules/isexe": { + "version": "2.0.0", "dev": true, - "license": "MIT" + "license": "ISC" }, - "node_modules/concat-map": { - "version": "0.0.1", + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", "dev": true, - "license": "MIT" + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } }, - "node_modules/core-js-compat": { - "version": "3.46.0", + "node_modules/istanbul-lib-report": { + "version": "3.0.1", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "dependencies": { - "browserslist": "^4.26.3" + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" + "engines": { + "node": ">=10" } }, - "node_modules/cross-spawn": { - "version": "7.0.6", + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" }, "engines": { - "node": ">= 8" + "node": ">=10" } }, - "node_modules/debug": { - "version": "4.4.3", + "node_modules/istanbul-reports": { + "version": "3.2.0", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "dependencies": { - "ms": "^2.1.3" + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=8" } }, - "node_modules/deep-is": { - "version": "0.1.4", + "node_modules/javascript-natural-sort": { + "version": "0.7.1", "dev": true, "license": "MIT" }, - "node_modules/detect-indent": { - "version": "7.0.2", - "dev": true, + "node_modules/jiti": { + "version": "2.6.1", "license": "MIT", - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "bin": { + "jiti": "lib/jiti-cli.mjs" } }, - "node_modules/detect-newline": { - "version": "4.0.1", - "dev": true, + "node_modules/js-tokens": { + "version": "4.0.0", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "dependencies": { + "argparse": "^2.0.1" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/electron-to-chromium": { - "version": "1.5.241", - "dev": true, - "license": "ISC" - }, - "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", - "dev": true, - "license": "MIT" - }, - "node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", - "dev": true, - "hasInstallScript": true, + "node_modules/jsesc": { + "version": "3.1.0", "license": "MIT", "bin": { - "esbuild": "bin/esbuild" + "jsesc": "bin/jsesc" }, "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.12", - "@esbuild/android-arm": "0.25.12", - "@esbuild/android-arm64": "0.25.12", - "@esbuild/android-x64": "0.25.12", - "@esbuild/darwin-arm64": "0.25.12", - "@esbuild/darwin-x64": "0.25.12", - "@esbuild/freebsd-arm64": "0.25.12", - "@esbuild/freebsd-x64": "0.25.12", - "@esbuild/linux-arm": "0.25.12", - "@esbuild/linux-arm64": "0.25.12", - "@esbuild/linux-ia32": "0.25.12", - "@esbuild/linux-loong64": "0.25.12", - "@esbuild/linux-mips64el": "0.25.12", - "@esbuild/linux-ppc64": "0.25.12", - "@esbuild/linux-riscv64": "0.25.12", - "@esbuild/linux-s390x": "0.25.12", - "@esbuild/linux-x64": "0.25.12", - "@esbuild/netbsd-arm64": "0.25.12", - "@esbuild/netbsd-x64": "0.25.12", - "@esbuild/openbsd-arm64": "0.25.12", - "@esbuild/openbsd-x64": "0.25.12", - "@esbuild/openharmony-arm64": "0.25.12", - "@esbuild/sunos-x64": "0.25.12", - "@esbuild/win32-arm64": "0.25.12", - "@esbuild/win32-ia32": "0.25.12", - "@esbuild/win32-x64": "0.25.12" + "node": ">=6" } }, - "node_modules/escalade": { - "version": "3.2.0", + "node_modules/json-buffer": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, "engines": { "node": ">=6" } }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", + "node_modules/jsx-ast-utils-x": { + "version": "0.1.0", "dev": true, "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/eslint": { - "version": "9.39.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", - "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", + "node_modules/keyv": { + "version": "4.5.4", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.1", - "@eslint/config-helpers": "^0.4.2", - "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.1", - "@eslint/plugin-kit": "^0.4.1", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" }, - "bin": { - "eslint": "bin/eslint.js" + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.30.2", + "devOptional": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">= 12.0.0" }, "funding": { - "url": "https://eslint.org/donate" + "type": "opencollective", + "url": "https://opencollective.com/parcel" }, - "peerDependencies": { - "jiti": "*" + "optionalDependencies": { + "lightningcss-android-arm64": "1.30.2", + "lightningcss-darwin-arm64": "1.30.2", + "lightningcss-darwin-x64": "1.30.2", + "lightningcss-freebsd-x64": "1.30.2", + "lightningcss-linux-arm-gnueabihf": "1.30.2", + "lightningcss-linux-arm64-gnu": "1.30.2", + "lightningcss-linux-arm64-musl": "1.30.2", + "lightningcss-linux-x64-gnu": "1.30.2", + "lightningcss-linux-x64-musl": "1.30.2", + "lightningcss-win32-arm64-msvc": "1.30.2", + "lightningcss-win32-x64-msvc": "1.30.2" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.2", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/eslint-config-prettier": { - "version": "10.1.8", - "dev": true, - "license": "MIT", - "bin": { - "eslint-config-prettier": "bin/cli.js" + "node_modules/lightningcss/node_modules/lightningcss-android-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz", + "integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" }, "funding": { - "url": "https://opencollective.com/eslint-config-prettier" - }, - "peerDependencies": { - "eslint": ">=7.0.0" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/eslint-plugin-sonarjs": { - "version": "3.0.5", - "dev": true, - "license": "LGPL-3.0-only", - "dependencies": { - "@eslint-community/regexpp": "4.12.1", - "builtin-modules": "3.3.0", - "bytes": "3.1.2", - "functional-red-black-tree": "1.0.1", - "jsx-ast-utils-x": "0.1.0", - "lodash.merge": "4.6.2", - "minimatch": "9.0.5", - "scslre": "0.3.0", - "semver": "7.7.2", - "typescript": ">=5" + "node_modules/lightningcss/node_modules/lightningcss-darwin-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz", + "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" }, - "peerDependencies": { - "eslint": "^8.0.0 || ^9.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/eslint-plugin-sonarjs/node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "dev": true, - "license": "MIT", + "node_modules/lightningcss/node_modules/lightningcss-freebsd-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz", + "integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/eslint-plugin-sonarjs/node_modules/semver": { - "version": "7.7.2", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "node_modules/lightningcss/node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz", + "integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss/node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz", + "integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=10" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/eslint-plugin-unicorn": { - "version": "62.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", - "@eslint-community/eslint-utils": "^4.9.0", - "@eslint/plugin-kit": "^0.4.0", - "change-case": "^5.4.4", - "ci-info": "^4.3.1", - "clean-regexp": "^1.0.0", - "core-js-compat": "^3.46.0", - "esquery": "^1.6.0", - "find-up-simple": "^1.0.1", - "globals": "^16.4.0", - "indent-string": "^5.0.0", - "is-builtin-module": "^5.0.0", - "jsesc": "^3.1.0", - "pluralize": "^8.0.0", - "regexp-tree": "^0.1.27", - "regjsparser": "^0.13.0", - "semver": "^7.7.3", - "strip-indent": "^4.1.1" + "node_modules/lightningcss/node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz", + "integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss/node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz", + "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^20.10.0 || >=21.0.0" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss/node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz", + "integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" }, - "peerDependencies": { - "eslint": ">=9.38.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/eslint-plugin-unicorn/node_modules/globals": { - "version": "16.4.0", - "dev": true, - "license": "MIT", + "node_modules/lightningcss/node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz", + "integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss/node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz", + "integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=18" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/eslint-scope": { - "version": "8.4.0", + "node_modules/locate-path": { + "version": "6.0.0", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "p-locate": "^5.0.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=10" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", + "node_modules/lodash-es": { + "version": "4.17.21", "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "license": "MIT" + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "license": "MIT", "funding": { - "url": "https://opencollective.com/eslint" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.12", - "dev": true, - "license": "MIT", + "node_modules/lru-cache": { + "version": "5.1.1", + "license": "ISC", + "peer": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "yallist": "^3.0.2" } }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node_modules/lucide-react": { + "version": "0.553.0", + "license": "ISC", + "peer": true, + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/eslint/node_modules/ignore": { - "version": "5.3.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } + "node_modules/lucide-static": { + "version": "0.552.0", + "license": "ISC" }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", + "node_modules/magic-string": { + "version": "0.30.21", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/espree": { - "version": "10.4.0", + "node_modules/make-dir": { + "version": "4.0.0", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" + "semver": "^7.5.3" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=10" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "dev": true, - "license": "Apache-2.0", + "node_modules/markdown-extensions": { + "version": "2.0.0", + "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=16" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/esquery": { - "version": "1.6.0", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" + "node_modules/markdown-table": { + "version": "3.0.4", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/esrecurse": { - "version": "4.3.0", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.2", + "license": "MIT", "dependencies": { - "estraverse": "^5.2.0" + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" }, - "engines": { - "node": ">=4.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/estraverse": { - "version": "5.3.0", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "license": "MIT", "engines": { - "node": ">=4.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.2", "license": "MIT", "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expect-type": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", - "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.0.0" + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "dev": true, + "node_modules/mdast-util-gfm": { + "version": "3.1.0", "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, - "engines": { - "node": ">=8.6.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "dev": true, - "license": "ISC", + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "license": "MIT", "dependencies": { - "is-glob": "^4.0.1" + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" }, - "engines": { - "node": ">= 6" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/fast-json-stable-stringify": { + "node_modules/mdast-util-gfm-footnote": { "version": "2.1.0", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "dev": true, - "license": "MIT" - }, - "node_modules/fastq": { - "version": "1.19.1", - "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "reusify": "^1.0.4" + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/fdir": { - "version": "6.5.0", - "dev": true, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "dev": true, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", "license": "MIT", "dependencies": { - "flat-cache": "^4.0.0" + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, - "engines": { - "node": ">=16.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/fill-range": { - "version": "7.1.1", - "dev": true, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", "license": "MIT", "dependencies": { - "to-regex-range": "^5.0.1" + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, - "engines": { - "node": ">=8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/find-up": { - "version": "5.0.0", - "dev": true, + "node_modules/mdast-util-mdx": { + "version": "3.0.0", "license": "MIT", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/find-up-simple": { - "version": "1.0.1", - "dev": true, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", "license": "MIT", - "engines": { - "node": ">=18" + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/flat-cache": { - "version": "4.0.1", - "dev": true, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", "license": "MIT", "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" }, - "engines": { - "node": ">=16" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/flatted": { - "version": "3.3.3", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/get-tsconfig": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", - "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", - "dev": true, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", "license": "MIT", "dependencies": { - "resolve-pkg-maps": "^1.0.0" + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" }, "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/git-hooks-list": { - "version": "4.1.1", - "dev": true, + "node_modules/mdast-util-to-hast": { + "version": "13.2.0", "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, "funding": { - "url": "https://github.com/fisker/git-hooks-list?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/glob-parent": { - "version": "6.0.2", - "dev": true, - "license": "ISC", + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "license": "MIT", "dependencies": { - "is-glob": "^4.0.3" + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" }, - "engines": { - "node": ">=10.13.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/globals": { - "version": "14.0.0", - "dev": true, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", "license": "MIT", - "engines": { - "node": ">=18" + "dependencies": { + "@types/mdast": "^4.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/graphemer": { - "version": "1.4.0", + "node_modules/merge-stream": { + "version": "2.0.0", "dev": true, "license": "MIT" }, - "node_modules/has-flag": { - "version": "4.0.0", + "node_modules/merge2": { + "version": "1.4.1", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 8" } }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true, - "license": "MIT" - }, - "node_modules/ignore": { - "version": "7.0.5", - "dev": true, + "node_modules/micromark": { + "version": "4.0.2", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">= 4" + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/import-fresh": { - "version": "3.3.1", - "dev": true, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", "license": "MIT", "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "dev": true, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", "license": "MIT", - "engines": { - "node": ">=0.8.19" + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/indent-string": { - "version": "5.0.0", - "dev": true, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/is-builtin-module": { - "version": "5.0.0", - "dev": true, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", "license": "MIT", "dependencies": { - "builtin-modules": "^5.0.0" + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, - "engines": { - "node": ">=18.20" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/is-builtin-module/node_modules/builtin-modules": { - "version": "5.0.0", - "dev": true, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", "license": "MIT", - "engines": { - "node": ">=18.20" + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "dev": true, + "node_modules/micromark-extension-mdx-expression": { + "version": "3.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">=0.10.0" + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "dev": true, + "node_modules/micromark-extension-mdx-jsx": { + "version": "3.0.2", "license": "MIT", "dependencies": { - "is-extglob": "^2.1.1" + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/is-number": { - "version": "7.0.0", - "dev": true, + "node_modules/micromark-extension-mdx-md": { + "version": "2.0.0", "license": "MIT", - "engines": { - "node": ">=0.12.0" + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/is-plain-obj": { - "version": "4.1.0", - "dev": true, + "node_modules/micromark-extension-mdxjs": { + "version": "3.0.0", "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^3.0.0", + "micromark-extension-mdx-jsx": "^3.0.0", + "micromark-extension-mdx-md": "^2.0.0", + "micromark-extension-mdxjs-esm": "^3.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/isexe": { - "version": "2.0.0", - "dev": true, - "license": "ISC" + "node_modules/micromark-extension-mdxjs-esm": { + "version": "3.0.0", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=8" + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression": { + "version": "2.0.3", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/istanbul-lib-source-maps": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", - "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.23", - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0" - }, - "engines": { - "node": ">=10" + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/istanbul-reports": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", - "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/javascript-natural-sort": { - "version": "0.7.1", - "dev": true, - "license": "MIT" - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "dev": true, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/jsesc": { - "version": "3.1.0", - "dev": true, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" + "dependencies": { + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/jsx-ast-utils-x": { - "version": "0.1.0", - "dev": true, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/keyv": { - "version": "4.5.4", - "dev": true, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "json-buffer": "3.0.1" + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/levn": { - "version": "0.4.1", - "dev": true, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/locate-path": { - "version": "6.0.0", - "dev": true, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/lodash-es": { - "version": "4.17.21", - "dev": true, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT" }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "dev": true, + "node_modules/micromark-util-events-to-acorn": { + "version": "2.0.3", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT" }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/magicast": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.1.tgz", - "integrity": "sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw==", - "dev": true, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", - "source-map-js": "^1.2.1" + "micromark-util-types": "^2.0.0" } }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/merge2": { - "version": "1.4.1", - "dev": true, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">= 8" + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, "node_modules/micromatch": { "version": "4.0.8", "dev": true, @@ -2901,6 +6905,41 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/mime-db": { + "version": "1.54.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.18", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "~1.33.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types/node_modules/mime-db": { + "version": "1.33.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/minimatch": { "version": "9.0.5", "dev": true, @@ -2915,16 +6954,20 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/minimist": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/ms": { "version": "2.1.3", - "dev": true, "license": "MIT" }, "node_modules/nanoid": { "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, "funding": [ { "type": "github", @@ -2944,10 +6987,207 @@ "dev": true, "license": "MIT" }, + "node_modules/negotiator": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/next-themes": { + "version": "0.4.6", + "license": "MIT", + "peerDependencies": { + "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" + } + }, + "node_modules/nf3": { + "version": "0.1.10", + "license": "MIT" + }, + "node_modules/nitro": { + "version": "3.0.1-alpha.1", + "license": "MIT", + "dependencies": { + "consola": "^3.4.2", + "crossws": "^0.4.1", + "db0": "^0.3.4", + "h3": "2.0.1-rc.5", + "jiti": "^2.6.1", + "nf3": "^0.1.10", + "ofetch": "^2.0.0-alpha.3", + "ohash": "^2.0.11", + "oxc-minify": "^0.96.0", + "oxc-transform": "^0.96.0", + "srvx": "^0.9.5", + "undici": "^7.16.0", + "unenv": "^2.0.0-rc.24", + "unstorage": "^2.0.0-alpha.4" + }, + "bin": { + "nitro": "dist/cli/index.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "rolldown": "*", + "rollup": "^4", + "vite": "^7", + "xml2js": "^0.6.2" + }, + "peerDependenciesMeta": { + "rolldown": { + "optional": true + }, + "rollup": { + "optional": true + }, + "vite": { + "optional": true + }, + "xml2js": { + "optional": true + } + } + }, + "node_modules/nitro/node_modules/h3": { + "version": "2.0.1-rc.5", + "license": "MIT", + "dependencies": { + "rou3": "^0.7.9", + "srvx": "^0.9.1" + }, + "engines": { + "node": ">=20.11.1" + }, + "peerDependencies": { + "crossws": "^0.4.1" + }, + "peerDependenciesMeta": { + "crossws": { + "optional": true + } + } + }, + "node_modules/nitro/node_modules/ofetch": { + "version": "2.0.0-alpha.3", + "license": "MIT", + "peer": true + }, + "node_modules/nitro/node_modules/srvx": { + "version": "0.9.5", + "license": "MIT", + "bin": { + "srvx": "bin/srvx.mjs" + }, + "engines": { + "node": ">=20.16.0" + } + }, + "node_modules/nitro/node_modules/unstorage": { + "version": "2.0.0-alpha.4", + "license": "MIT", + "peerDependencies": { + "@azure/app-configuration": "^1.8.0", + "@azure/cosmos": "^4.2.0", + "@azure/data-tables": "^13.3.0", + "@azure/identity": "^4.6.0", + "@azure/keyvault-secrets": "^4.9.0", + "@azure/storage-blob": "^12.26.0", + "@capacitor/preferences": "^6.0.3 || ^7.0.0", + "@deno/kv": ">=0.9.0", + "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", + "@planetscale/database": "^1.19.0", + "@upstash/redis": "^1.34.3", + "@vercel/blob": ">=0.27.1", + "@vercel/functions": "^2.2.12 || ^3.0.0", + "@vercel/kv": "^1.0.1", + "aws4fetch": "^1.0.20", + "chokidar": "^4.0.3", + "db0": ">=0.2.1", + "idb-keyval": "^6.2.1", + "ioredis": "^5.4.2", + "lru-cache": "^11.2.2", + "mongodb": "^6.20.0", + "ofetch": "*", + "uploadthing": "^7.4.4" + }, + "peerDependenciesMeta": { + "@azure/app-configuration": { + "optional": true + }, + "@azure/cosmos": { + "optional": true + }, + "@azure/data-tables": { + "optional": true + }, + "@azure/identity": { + "optional": true + }, + "@azure/keyvault-secrets": { + "optional": true + }, + "@azure/storage-blob": { + "optional": true + }, + "@capacitor/preferences": { + "optional": true + }, + "@deno/kv": { + "optional": true + }, + "@netlify/blobs": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@vercel/blob": { + "optional": true + }, + "@vercel/functions": { + "optional": true + }, + "@vercel/kv": { + "optional": true + }, + "aws4fetch": { + "optional": true + }, + "chokidar": { + "optional": true + }, + "db0": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "lru-cache": { + "optional": true + }, + "mongodb": { + "optional": true + }, + "ofetch": { + "optional": true + }, + "uploadthing": { + "optional": true + } + } + }, "node_modules/node-fetch": { "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2966,10 +7206,86 @@ } }, "node_modules/node-releases": { - "version": "2.0.26", + "version": "2.0.27", + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm-to-yarn": { + "version": "3.0.1", + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/nebrelbug/npm-to-yarn?sponsor=1" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/ohash": { + "version": "2.0.11", + "license": "MIT" + }, + "node_modules/on-headers": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/onetime": { + "version": "5.1.2", "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/oniguruma-parser": { + "version": "0.12.1", "license": "MIT" }, + "node_modules/oniguruma-to-es": { + "version": "4.3.3", + "license": "MIT", + "dependencies": { + "oniguruma-parser": "^0.12.1", + "regex": "^6.0.1", + "regex-recursion": "^6.0.2" + } + }, "node_modules/openworkflow": { "resolved": "packages/openworkflow", "link": true @@ -2990,6 +7306,60 @@ "node": ">= 0.8.0" } }, + "node_modules/oxc-minify": { + "version": "0.96.0", + "license": "MIT", + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxc-minify/binding-android-arm64": "0.96.0", + "@oxc-minify/binding-darwin-arm64": "0.96.0", + "@oxc-minify/binding-darwin-x64": "0.96.0", + "@oxc-minify/binding-freebsd-x64": "0.96.0", + "@oxc-minify/binding-linux-arm-gnueabihf": "0.96.0", + "@oxc-minify/binding-linux-arm-musleabihf": "0.96.0", + "@oxc-minify/binding-linux-arm64-gnu": "0.96.0", + "@oxc-minify/binding-linux-arm64-musl": "0.96.0", + "@oxc-minify/binding-linux-riscv64-gnu": "0.96.0", + "@oxc-minify/binding-linux-s390x-gnu": "0.96.0", + "@oxc-minify/binding-linux-x64-gnu": "0.96.0", + "@oxc-minify/binding-linux-x64-musl": "0.96.0", + "@oxc-minify/binding-wasm32-wasi": "0.96.0", + "@oxc-minify/binding-win32-arm64-msvc": "0.96.0", + "@oxc-minify/binding-win32-x64-msvc": "0.96.0" + } + }, + "node_modules/oxc-transform": { + "version": "0.96.0", + "license": "MIT", + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxc-transform/binding-android-arm64": "0.96.0", + "@oxc-transform/binding-darwin-arm64": "0.96.0", + "@oxc-transform/binding-darwin-x64": "0.96.0", + "@oxc-transform/binding-freebsd-x64": "0.96.0", + "@oxc-transform/binding-linux-arm-gnueabihf": "0.96.0", + "@oxc-transform/binding-linux-arm-musleabihf": "0.96.0", + "@oxc-transform/binding-linux-arm64-gnu": "0.96.0", + "@oxc-transform/binding-linux-arm64-musl": "0.96.0", + "@oxc-transform/binding-linux-riscv64-gnu": "0.96.0", + "@oxc-transform/binding-linux-s390x-gnu": "0.96.0", + "@oxc-transform/binding-linux-x64-gnu": "0.96.0", + "@oxc-transform/binding-linux-x64-musl": "0.96.0", + "@oxc-transform/binding-wasm32-wasi": "0.96.0", + "@oxc-transform/binding-win32-arm64-msvc": "0.96.0", + "@oxc-transform/binding-win32-x64-msvc": "0.96.0" + } + }, "node_modules/p-limit": { "version": "3.1.0", "dev": true, @@ -3029,6 +7399,27 @@ "node": ">=6" } }, + "node_modules/parse-entities": { + "version": "4.0.2", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "license": "MIT" + }, "node_modules/parse-imports-exports": { "version": "0.2.4", "dev": true, @@ -3042,6 +7433,47 @@ "dev": true, "license": "MIT" }, + "node_modules/parse5": { + "version": "7.3.0", + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.1.0", + "license": "MIT", + "dependencies": { + "domhandler": "^5.0.3", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-parser-stream": { + "version": "7.1.2", + "license": "MIT", + "dependencies": { + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "6.0.1", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/path-exists": { "version": "4.0.0", "dev": true, @@ -3050,6 +7482,11 @@ "node": ">=8" } }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "dev": true, + "license": "(WTFPL OR MIT)" + }, "node_modules/path-key": { "version": "3.1.1", "dev": true, @@ -3058,21 +7495,24 @@ "node": ">=8" } }, + "node_modules/path-to-regexp": { + "version": "8.3.0", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/pathe": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, "license": "MIT" }, "node_modules/picocolors": { "version": "1.1.1", - "dev": true, "license": "ISC" }, "node_modules/picomatch": { "version": "4.0.3", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -3091,9 +7531,6 @@ }, "node_modules/postcss": { "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, "funding": [ { "type": "opencollective", @@ -3118,10 +7555,19 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-selector-parser": { + "version": "7.1.0", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/postgres": { "version": "3.4.7", - "resolved": "https://registry.npmjs.org/postgres/-/postgres-3.4.7.tgz", - "integrity": "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw==", "license": "Unlicense", "engines": { "node": ">=12" @@ -3141,8 +7587,8 @@ }, "node_modules/prettier": { "version": "3.6.2", - "dev": true, "license": "MIT", + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -3170,6 +7616,14 @@ } } }, + "node_modules/property-information": { + "version": "7.1.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/punycode": { "version": "2.3.1", "dev": true, @@ -3197,6 +7651,240 @@ ], "license": "MIT" }, + "node_modules/range-parser": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react": { + "version": "19.2.0", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.0", + "license": "MIT", + "peer": true, + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.0" + } + }, + "node_modules/react-medium-image-zoom": { + "version": "5.4.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/rpearce" + } + ], + "license": "BSD-3-Clause", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-refresh": { + "version": "0.18.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-remove-scroll": { + "version": "2.7.1", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/recast": { + "version": "0.23.11", + "license": "MIT", + "dependencies": { + "ast-types": "^0.16.1", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tiny-invariant": "^1.3.3", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/recast/node_modules/source-map": { + "version": "0.6.1", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/recma-build-jsx": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-build-jsx": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-jsx": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "acorn-jsx": "^5.0.0", + "estree-util-to-js": "^2.0.0", + "recma-parse": "^1.0.0", + "recma-stringify": "^1.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/recma-parse": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "esast-util-from-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-stringify": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-to-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/refa": { "version": "0.12.1", "dev": true, @@ -3208,6 +7896,24 @@ "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/regex": { + "version": "6.0.1", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "6.0.2", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-utilities": { + "version": "2.3.0", + "license": "MIT" + }, "node_modules/regexp-ast-analysis": { "version": "0.7.1", "dev": true, @@ -3220,23 +7926,148 @@ "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/regexp-tree": { - "version": "0.1.27", - "dev": true, + "node_modules/regexp-tree": { + "version": "0.1.27", + "dev": true, + "license": "MIT", + "bin": { + "regexp-tree": "bin/regexp-tree" + } + }, + "node_modules/registry-auth-token": { + "version": "3.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/registry-url": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "rc": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regjsparser": { + "version": "0.13.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.1.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/rehype-recma": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "hast-util-to-estree": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark": { + "version": "15.0.1", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.1", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-mdx": { + "version": "3.1.1", + "license": "MIT", + "dependencies": { + "mdast-util-mdx": "^3.0.0", + "micromark-extension-mdxjs": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.2", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", "license": "MIT", - "bin": { - "regexp-tree": "bin/regexp-tree" + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/regjsparser": { - "version": "0.13.0", + "node_modules/require-from-string": { + "version": "2.0.2", "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "jsesc": "~3.1.0" - }, - "bin": { - "regjsparser": "bin/parser" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, "node_modules/resolve-from": { @@ -3249,9 +8080,6 @@ }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" @@ -3268,10 +8096,8 @@ }, "node_modules/rollup": { "version": "4.53.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.1.tgz", - "integrity": "sha512-n2I0V0lN3E9cxxMqBCT3opWOiQBzRN7UG60z/WDKqdX2zHUS/39lezBcsckZFsV6fUTSnfqI7kHf60jDAPGKug==", - "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -3308,6 +8134,84 @@ "fsevents": "~2.3.2" } }, + "node_modules/rollup/node_modules/@rollup/rollup-android-arm-eabi": { + "optional": true + }, + "node_modules/rollup/node_modules/@rollup/rollup-android-arm64": { + "optional": true + }, + "node_modules/rollup/node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.53.1", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/rollup/node_modules/@rollup/rollup-darwin-x64": { + "optional": true + }, + "node_modules/rollup/node_modules/@rollup/rollup-freebsd-arm64": { + "optional": true + }, + "node_modules/rollup/node_modules/@rollup/rollup-freebsd-x64": { + "optional": true + }, + "node_modules/rollup/node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "optional": true + }, + "node_modules/rollup/node_modules/@rollup/rollup-linux-arm-musleabihf": { + "optional": true + }, + "node_modules/rollup/node_modules/@rollup/rollup-linux-arm64-gnu": { + "optional": true + }, + "node_modules/rollup/node_modules/@rollup/rollup-linux-arm64-musl": { + "optional": true + }, + "node_modules/rollup/node_modules/@rollup/rollup-linux-loong64-gnu": { + "optional": true + }, + "node_modules/rollup/node_modules/@rollup/rollup-linux-ppc64-gnu": { + "optional": true + }, + "node_modules/rollup/node_modules/@rollup/rollup-linux-riscv64-gnu": { + "optional": true + }, + "node_modules/rollup/node_modules/@rollup/rollup-linux-riscv64-musl": { + "optional": true + }, + "node_modules/rollup/node_modules/@rollup/rollup-linux-s390x-gnu": { + "optional": true + }, + "node_modules/rollup/node_modules/@rollup/rollup-linux-x64-gnu": { + "optional": true + }, + "node_modules/rollup/node_modules/@rollup/rollup-linux-x64-musl": { + "optional": true + }, + "node_modules/rollup/node_modules/@rollup/rollup-openharmony-arm64": { + "optional": true + }, + "node_modules/rollup/node_modules/@rollup/rollup-win32-arm64-msvc": { + "optional": true + }, + "node_modules/rollup/node_modules/@rollup/rollup-win32-ia32-msvc": { + "optional": true + }, + "node_modules/rollup/node_modules/@rollup/rollup-win32-x64-gnu": { + "optional": true + }, + "node_modules/rollup/node_modules/@rollup/rollup-win32-x64-msvc": { + "optional": true + }, + "node_modules/rou3": { + "version": "0.7.10", + "license": "MIT" + }, "node_modules/run-parallel": { "version": "1.2.0", "dev": true, @@ -3330,6 +8234,40 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.27.0", + "license": "MIT" + }, + "node_modules/scroll-into-view-if-needed": { + "version": "3.1.0", + "license": "MIT", + "dependencies": { + "compute-scroll-into-view": "^3.0.2" + } + }, "node_modules/scslre": { "version": "0.3.0", "dev": true, @@ -3344,7 +8282,7 @@ } }, "node_modules/semver": { - "version": "7.7.3", + "version": "7.7.2", "dev": true, "license": "ISC", "bin": { @@ -3354,6 +8292,126 @@ "node": ">=10" } }, + "node_modules/seroval": { + "version": "1.3.2", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/seroval-plugins": { + "version": "1.3.3", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "seroval": "^1.0" + } + }, + "node_modules/serve": { + "version": "14.2.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@zeit/schemas": "2.36.0", + "ajv": "8.12.0", + "arg": "5.0.2", + "boxen": "7.0.0", + "chalk": "5.0.1", + "chalk-template": "0.4.0", + "clipboardy": "3.0.0", + "compression": "1.8.1", + "is-port-reachable": "4.0.0", + "serve-handler": "6.1.6", + "update-check": "1.5.4" + }, + "bin": { + "serve": "build/main.js" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/serve-handler": { + "version": "6.1.6", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.0.0", + "content-disposition": "0.5.2", + "mime-types": "2.1.18", + "minimatch": "3.1.2", + "path-is-inside": "1.0.2", + "path-to-regexp": "3.3.0", + "range-parser": "1.2.0" + } + }, + "node_modules/serve-handler/node_modules/brace-expansion": { + "version": "1.1.12", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/serve-handler/node_modules/bytes": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serve-handler/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/serve-handler/node_modules/path-to-regexp": { + "version": "3.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/serve/node_modules/ajv": { + "version": "8.12.0", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/serve/node_modules/chalk": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/serve/node_modules/json-schema-traverse": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, "node_modules/shebang-command": { "version": "2.0.0", "dev": true, @@ -3373,13 +8431,40 @@ "node": ">=8" } }, + "node_modules/shiki": { + "version": "3.15.0", + "license": "MIT", + "dependencies": { + "@shikijs/core": "3.15.0", + "@shikijs/engine-javascript": "3.15.0", + "@shikijs/engine-oniguruma": "3.15.0", + "@shikijs/langs": "3.15.0", + "@shikijs/themes": "3.15.0", + "@shikijs/types": "3.15.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, "node_modules/siginfo": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", "dev": true, "license": "ISC" }, + "node_modules/signal-exit": { + "version": "3.0.7", + "dev": true, + "license": "ISC" + }, + "node_modules/solid-js": { + "version": "1.9.10", + "license": "MIT", + "peer": true, + "dependencies": { + "csstype": "^3.1.0", + "seroval": "~1.3.0", + "seroval-plugins": "~1.3.0" + } + }, "node_modules/sort-object-keys": { "version": "1.1.3", "dev": true, @@ -3405,20 +8490,34 @@ "node": ">=20" } }, + "node_modules/source-map": { + "version": "0.7.6", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, "node_modules/source-map-js": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "license": "BSD-3-Clause" + }, "node_modules/squawk-cli": { "version": "2.30.0", - "resolved": "https://registry.npmjs.org/squawk-cli/-/squawk-cli-2.30.0.tgz", - "integrity": "sha512-JZf+UZgxp1sQrvVlMm78WVp+VUcB5GCVb7AzFyAwzOckvNkjhcWPHJ6bKaenXpT56ghpKXuSHPEBIZME81xVQA==", "dev": true, "hasInstallScript": true, "license": "(Apache-2.0 OR MIT)", @@ -3429,20 +8528,76 @@ "squawk": "js/bin/squawk" } }, + "node_modules/srvx": { + "version": "0.8.16", + "license": "MIT", + "bin": { + "srvx": "bin/srvx.mjs" + }, + "engines": { + "node": ">=20.16.0" + } + }, "node_modules/stackback": { "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", "dev": true, "license": "MIT" }, "node_modules/std-env": { "version": "3.10.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", - "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", "dev": true, "license": "MIT" }, + "node_modules/string-width": { + "version": "5.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/strip-indent": { "version": "4.1.1", "dev": true, @@ -3465,6 +8620,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/style-to-js": { + "version": "1.1.19", + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.12" + } + }, + "node_modules/style-to-object": { + "version": "1.0.12", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.6" + } + }, "node_modules/supports-color": { "version": "7.2.0", "dev": true, @@ -3490,23 +8659,53 @@ "url": "https://opencollective.com/synckit" } }, + "node_modules/tailwind-merge": { + "version": "3.4.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "4.1.17", + "devOptional": true, + "license": "MIT", + "peer": true + }, + "node_modules/tapable": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "license": "MIT", + "peer": true + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "license": "MIT" + }, "node_modules/tinybench": { "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", "dev": true, "license": "MIT" }, "node_modules/tinyexec": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", - "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", "dev": true, "license": "MIT" }, "node_modules/tinyglobby": { "version": "0.2.15", - "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", @@ -3521,8 +8720,6 @@ }, "node_modules/tinyrainbow": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", - "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", "dev": true, "license": "MIT", "engines": { @@ -3531,7 +8728,6 @@ }, "node_modules/to-regex-range": { "version": "5.0.1", - "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -3542,11 +8738,25 @@ }, "node_modules/tr46": { "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "dev": true, "license": "MIT" }, + "node_modules/trim-lines": { + "version": "3.0.1", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/ts-api-utils": { "version": "2.1.0", "dev": true, @@ -3558,11 +8768,31 @@ "typescript": ">=4.8.4" } }, + "node_modules/tsconfck": { + "version": "3.1.6", + "dev": true, + "license": "MIT", + "bin": { + "tsconfck": "bin/tsconfck.js" + }, + "engines": { + "node": "^18 || >=20" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "license": "0BSD" + }, "node_modules/tsx": { "version": "4.20.6", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.6.tgz", - "integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==", - "dev": true, "license": "MIT", "dependencies": { "esbuild": "~0.25.0", @@ -3580,8 +8810,6 @@ }, "node_modules/turbo": { "version": "2.6.1", - "resolved": "https://registry.npmjs.org/turbo/-/turbo-2.6.1.tgz", - "integrity": "sha512-qBwXXuDT3rA53kbNafGbT5r++BrhRgx3sAo0cHoDAeG9g1ItTmUMgltz3Hy7Hazy1ODqNpR+C7QwqL6DYB52yA==", "dev": true, "license": "MIT", "bin": { @@ -3596,12 +8824,10 @@ "turbo-windows-arm64": "2.6.1" } }, - "node_modules/turbo-darwin-64": { + "node_modules/turbo-darwin-arm64": { "version": "2.6.1", - "resolved": "https://registry.npmjs.org/turbo-darwin-64/-/turbo-darwin-64-2.6.1.tgz", - "integrity": "sha512-Dm0HwhyZF4J0uLqkhUyCVJvKM9Rw7M03v3J9A7drHDQW0qAbIGBrUijQ8g4Q9Cciw/BXRRd8Uzkc3oue+qn+ZQ==", "cpu": [ - "x64" + "arm64" ], "dev": true, "license": "MIT", @@ -3610,12 +8836,12 @@ "darwin" ] }, - "node_modules/turbo-darwin-arm64": { + "node_modules/turbo/node_modules/turbo-darwin-64": { "version": "2.6.1", - "resolved": "https://registry.npmjs.org/turbo-darwin-arm64/-/turbo-darwin-arm64-2.6.1.tgz", - "integrity": "sha512-U0PIPTPyxdLsrC3jN7jaJUwgzX5sVUBsKLO7+6AL+OASaa1NbT1pPdiZoTkblBAALLP76FM0LlnsVQOnmjYhyw==", + "resolved": "https://registry.npmjs.org/turbo-darwin-64/-/turbo-darwin-64-2.6.1.tgz", + "integrity": "sha512-Dm0HwhyZF4J0uLqkhUyCVJvKM9Rw7M03v3J9A7drHDQW0qAbIGBrUijQ8g4Q9Cciw/BXRRd8Uzkc3oue+qn+ZQ==", "cpu": [ - "arm64" + "x64" ], "dev": true, "license": "MIT", @@ -3624,7 +8850,7 @@ "darwin" ] }, - "node_modules/turbo-linux-64": { + "node_modules/turbo/node_modules/turbo-linux-64": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/turbo-linux-64/-/turbo-linux-64-2.6.1.tgz", "integrity": "sha512-eM1uLWgzv89bxlK29qwQEr9xYWBhmO/EGiH22UGfq+uXr+QW1OvNKKMogSN65Ry8lElMH4LZh0aX2DEc7eC0Mw==", @@ -3638,7 +8864,7 @@ "linux" ] }, - "node_modules/turbo-linux-arm64": { + "node_modules/turbo/node_modules/turbo-linux-arm64": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/turbo-linux-arm64/-/turbo-linux-arm64-2.6.1.tgz", "integrity": "sha512-MFFh7AxAQAycXKuZDrbeutfWM5Ep0CEZ9u7zs4Hn2FvOViTCzIfEhmuJou3/a5+q5VX1zTxQrKGy+4Lf5cdpsA==", @@ -3652,7 +8878,7 @@ "linux" ] }, - "node_modules/turbo-windows-64": { + "node_modules/turbo/node_modules/turbo-windows-64": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/turbo-windows-64/-/turbo-windows-64-2.6.1.tgz", "integrity": "sha512-buq7/VAN7KOjMYi4tSZT5m+jpqyhbRU2EUTTvp6V0Ii8dAkY2tAAjQN1q5q2ByflYWKecbQNTqxmVploE0LVwQ==", @@ -3666,7 +8892,7 @@ "win32" ] }, - "node_modules/turbo-windows-arm64": { + "node_modules/turbo/node_modules/turbo-windows-arm64": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/turbo-windows-arm64/-/turbo-windows-arm64-2.6.1.tgz", "integrity": "sha512-7w+AD5vJp3R+FB0YOj1YJcNcOOvBior7bcHTodqp90S3x3bLgpr7tE6xOea1e8JkP7GK6ciKVUpQvV7psiwU5Q==", @@ -3691,10 +8917,22 @@ "node": ">= 0.8.0" } }, + "node_modules/type-fest": { + "version": "2.19.0", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/typescript": { "version": "5.9.3", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -3704,14 +8942,14 @@ } }, "node_modules/typescript-eslint": { - "version": "8.46.2", + "version": "8.46.3", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.46.2", - "@typescript-eslint/parser": "8.46.2", - "@typescript-eslint/typescript-estree": "8.46.2", - "@typescript-eslint/utils": "8.46.2" + "@typescript-eslint/eslint-plugin": "8.46.3", + "@typescript-eslint/parser": "8.46.3", + "@typescript-eslint/typescript-estree": "8.46.3", + "@typescript-eslint/utils": "8.46.3" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3725,14 +8963,142 @@ "typescript": ">=4.8.4 <6.0.0" } }, + "node_modules/ufo": { + "version": "1.6.1", + "license": "MIT" + }, + "node_modules/undici": { + "version": "7.16.0", + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, "node_modules/undici-types": { "version": "7.16.0", - "dev": true, + "devOptional": true, "license": "MIT" }, + "node_modules/unenv": { + "version": "2.0.0-rc.24", + "license": "MIT", + "dependencies": { + "pathe": "^2.0.3" + } + }, + "node_modules/unified": { + "version": "11.0.5", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position-from-estree": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove-position": { + "version": "5.0.0", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unplugin": { + "version": "2.3.10", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "acorn": "^8.15.0", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=18.12.0" + } + }, "node_modules/update-browserslist-db": { "version": "1.1.4", - "dev": true, "funding": [ { "type": "opencollective", @@ -3759,6 +9125,15 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/update-check": { + "version": "1.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "registry-auth-token": "3.3.2", + "registry-url": "3.1.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "dev": true, @@ -3767,12 +9142,34 @@ "punycode": "^2.1.0" } }, + "node_modules/vfile": { + "version": "6.0.3", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/vite": { "version": "7.2.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.2.tgz", - "integrity": "sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==", - "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -3842,12 +9239,46 @@ } } }, + "node_modules/vite-tsconfig-paths": { + "version": "5.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "globrex": "^0.1.2", + "tsconfck": "^3.0.3" + }, + "peerDependencies": { + "vite": "*" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/vitefu": { + "version": "1.1.1", + "license": "MIT", + "workspaces": [ + "tests/deps/*", + "tests/projects/*", + "tests/projects/workspace/packages/*" + ], + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, "node_modules/vitest": { "version": "4.0.8", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.8.tgz", - "integrity": "sha512-urzu3NCEV0Qa0Y2PwvBtRgmNtxhj5t5ULw7cuKhIHh3OrkKTLlut0lnBOv9qe5OvbkMH2g38G7KPDCTpIytBVg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@vitest/expect": "4.0.8", "@vitest/mocker": "4.0.8", @@ -3922,15 +9353,32 @@ }, "node_modules/webidl-conversions": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", "dev": true, "license": "BSD-2-Clause" }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "license": "MIT" + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/whatwg-url": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dev": true, "license": "MIT", "dependencies": { @@ -3954,8 +9402,6 @@ }, "node_modules/why-is-node-running": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dev": true, "license": "MIT", "dependencies": { @@ -3969,6 +9415,20 @@ "node": ">=8" } }, + "node_modules/widest-line": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "dev": true, @@ -3977,6 +9437,68 @@ "node": ">=0.10.0" } }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/xmlbuilder2": { + "version": "3.1.1", + "license": "MIT", + "dependencies": { + "@oozcitak/dom": "1.15.10", + "@oozcitak/infra": "1.0.8", + "@oozcitak/util": "8.3.8", + "js-yaml": "3.14.1" + }, + "engines": { + "node": ">=12.0" + } + }, + "node_modules/xmlbuilder2/node_modules/argparse": { + "version": "1.0.10", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/xmlbuilder2/node_modules/js-yaml": { + "version": "3.14.1", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "license": "ISC" + }, "node_modules/yocto-queue": { "version": "0.1.0", "dev": true, @@ -3988,6 +9510,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/zod": { + "version": "3.25.76", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "packages/backend-postgres": { "name": "@openworkflow/backend-postgres", "version": "0.2.0", diff --git a/package.json b/package.json index c51a206..b2edbda 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,8 @@ "private": true, "type": "module", "workspaces": [ - "packages/*" + "packages/*", + "apps/*" ], "scripts": { "build": "turbo build",