From 5f90a1cc934c6d92162df40ac5ecc671bd7fd342 Mon Sep 17 00:00:00 2001 From: skulidropek <66840575+skulidropek@users.noreply.github.com> Date: Sat, 21 Mar 2026 07:23:21 +0000 Subject: [PATCH] refactor(cli): rebuild on effect-template workspace --- .changeset/config.json | 16 + .github/actions/setup/action.yml | 22 + .github/workflows/check.yml | 26 + .gitignore | 5 + README.md | 36 +- package.json | 37 +- packages/app/package.json | 13 + packages/app/src/app/main.ts | 8 + packages/app/src/app/program.ts | 27 + packages/app/src/core/bootstrap.ts | 175 ++ packages/app/src/shell/bootstrap.ts | 252 ++ src/args.mjs => packages/app/src/shell/cli.ts | 58 +- packages/app/tests/bootstrap.test.ts | 55 + packages/app/tests/cli.test.ts | 50 + packages/app/tsconfig.build.json | 5 + packages/app/tsconfig.json | 14 + packages/app/vitest.config.ts | 8 + pnpm-lock.yaml | 2086 +++++++++++++++++ pnpm-workspace.yaml | 2 + src/index.mjs | 3 - src/main.mjs | 4 - src/run.mjs | 58 - src/template.mjs | 287 --- template-nextjs-overlay/README.md | 24 - template-nextjs-overlay/next.config.ts | 35 - .../public/locales/en.json | 6 - .../public/locales/ru.json | 6 - .../public/tonconnect-manifest.json | 5 - template-nextjs-overlay/spawndock.config.json | 12 - template-nextjs-overlay/spawndock/config.mjs | 14 - template-nextjs-overlay/spawndock/dev.mjs | 48 - template-nextjs-overlay/spawndock/next.mjs | 76 - template-nextjs-overlay/spawndock/tunnel.mjs | 16 - tests/args.test.mjs | 133 -- tsconfig.base.json | 28 + tsconfig.json | 5 + 36 files changed, 2884 insertions(+), 771 deletions(-) create mode 100644 .changeset/config.json create mode 100644 .github/actions/setup/action.yml create mode 100644 .github/workflows/check.yml create mode 100644 .gitignore create mode 100644 packages/app/package.json create mode 100644 packages/app/src/app/main.ts create mode 100644 packages/app/src/app/program.ts create mode 100644 packages/app/src/core/bootstrap.ts create mode 100644 packages/app/src/shell/bootstrap.ts rename src/args.mjs => packages/app/src/shell/cli.ts (59%) create mode 100644 packages/app/tests/bootstrap.test.ts create mode 100644 packages/app/tests/cli.test.ts create mode 100644 packages/app/tsconfig.build.json create mode 100644 packages/app/tsconfig.json create mode 100644 packages/app/vitest.config.ts create mode 100644 pnpm-lock.yaml create mode 100644 pnpm-workspace.yaml delete mode 100644 src/index.mjs delete mode 100755 src/main.mjs delete mode 100644 src/run.mjs delete mode 100644 src/template.mjs delete mode 100644 template-nextjs-overlay/README.md delete mode 100644 template-nextjs-overlay/next.config.ts delete mode 100644 template-nextjs-overlay/public/locales/en.json delete mode 100644 template-nextjs-overlay/public/locales/ru.json delete mode 100644 template-nextjs-overlay/public/tonconnect-manifest.json delete mode 100644 template-nextjs-overlay/spawndock.config.json delete mode 100644 template-nextjs-overlay/spawndock/config.mjs delete mode 100644 template-nextjs-overlay/spawndock/dev.mjs delete mode 100644 template-nextjs-overlay/spawndock/next.mjs delete mode 100644 template-nextjs-overlay/spawndock/tunnel.mjs delete mode 100644 tests/args.test.mjs create mode 100644 tsconfig.base.json create mode 100644 tsconfig.json diff --git a/.changeset/config.json b/.changeset/config.json new file mode 100644 index 0000000..8b78cb6 --- /dev/null +++ b/.changeset/config.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://unpkg.com/@changesets/config@3.0.2/schema.json", + "changelog": [ + "@changesets/changelog-github", + { + "repo": "SpawnDock/create-spawn-dock" + } + ], + "commit": false, + "fixed": [], + "linked": [], + "access": "public", + "baseBranch": "main", + "updateInternalDependencies": "patch", + "ignore": [] +} diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml new file mode 100644 index 0000000..ab675f1 --- /dev/null +++ b/.github/actions/setup/action.yml @@ -0,0 +1,22 @@ +name: Setup +description: Perform standard setup and install dependencies using pnpm. + +inputs: + node-version: + description: The version of Node.js to install + required: true + default: 22.12.0 + +runs: + using: composite + steps: + - name: Install pnpm + uses: pnpm/action-setup@v4 + - name: Install node + uses: actions/setup-node@v6 + with: + cache: pnpm + node-version: ${{ inputs.node-version }} + - name: Install dependencies + shell: bash + run: pnpm install diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml new file mode 100644 index 0000000..c0bd8a6 --- /dev/null +++ b/.github/workflows/check.yml @@ -0,0 +1,26 @@ +name: Check + +on: + workflow_dispatch: + pull_request: + branches: [main] + push: + branches: [main] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: {} + +jobs: + check: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v6 + - name: Install dependencies + uses: ./.github/actions/setup + - run: pnpm typecheck + - run: pnpm test + - run: pnpm build diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fe66e7a --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +node_modules +packages/*/dist +coverage +*.log +.DS_Store diff --git a/README.md b/README.md index 4bb9fcc..7b0776c 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,16 @@ SpawnDock bootstrap CLI for local TMA projects. -## Usage +This repository now follows an `effect-template`-style layout: -```bash -npx create-spawn-dock --token [project-dir] -``` +- root workspace with `packages/app` +- TypeScript + Effect entrypoint +- no embedded TMA starter overlay inside the CLI repo + +The canonical TMA starter lives only in `https://github.com/SpawnDock/tma-project`. +`create-spawn-dock` clones that repo and writes only project-specific runtime files. + +## Usage Until the npm package is published, run it directly from GitHub: @@ -14,19 +19,26 @@ Until the npm package is published, run it directly from GitHub: npx --yes github:SpawnDock/create-spawn-dock#main --token [project-dir] ``` -## What it does +After npm publish, the intended short form remains: + +```bash +npx create-spawn-dock --token [project-dir] +``` -- clones `SpawnDock/tma-project` -- claims the pairing token against the control plane -- writes `spawndock.config.json`, `.env.local`, `spawndock.dev-tunnel.json`, and `opencode.json` -- installs dependencies in the generated project +## What it writes -## Generated MCP URL +- `spawndock.config.json` +- `.env.local` +- `spawndock.dev-tunnel.json` +- `opencode.json` +- `public/tonconnect-manifest.json` -The bootstrap writes `MCP_SERVER_URL` to `/mcp/sse`. +Generated MCP config points to `/mcp/sse`. ## Development ```bash -npm test +pnpm install +pnpm test +pnpm build ``` diff --git a/package.json b/package.json index 01a6c9c..c8bba2e 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,13 @@ { "name": "create-spawn-dock", - "version": "0.1.0", + "version": "0.2.0", "type": "module", - "description": "SpawnDock CLI for bootstrapping local TMA projects", + "description": "SpawnDock bootstrap CLI for local TMA projects", "license": "ISC", + "packageManager": "pnpm@10.32.1", + "workspaces": [ + "packages/*" + ], "repository": { "type": "git", "url": "git+https://github.com/SpawnDock/create-spawn-dock.git" @@ -15,20 +19,31 @@ "publishConfig": { "access": "public" }, - "exports": { - ".": "./src/index.mjs", - "./run": "./src/run.mjs" - }, "files": [ "README.md", - "src", - "template-nextjs-overlay" + "packages/app/dist" ], "bin": { - "create-spawn-dock": "./src/main.mjs" + "create-spawn-dock": "./packages/app/dist/src/app/main.js" }, "scripts": { - "prepack": "npm test", - "test": "node --test tests/*.test.mjs" + "prepare": "corepack pnpm build", + "build": "pnpm --filter @create-spawn-dock/app build", + "check": "pnpm --filter @create-spawn-dock/app check", + "test": "pnpm --filter @create-spawn-dock/app test", + "typecheck": "pnpm --filter @create-spawn-dock/app typecheck", + "start": "pnpm --filter @create-spawn-dock/app start" + }, + "dependencies": { + "@effect/platform-node": "^0.106.0", + "@effect/schema": "^0.75.5", + "effect": "^3.21.0" + }, + "devDependencies": { + "@changesets/changelog-github": "^0.6.0", + "@changesets/cli": "^2.30.0", + "@types/node": "^24.12.0", + "typescript": "^5.9.3", + "vitest": "^4.1.0" } } diff --git a/packages/app/package.json b/packages/app/package.json new file mode 100644 index 0000000..50c2a8b --- /dev/null +++ b/packages/app/package.json @@ -0,0 +1,13 @@ +{ + "name": "@create-spawn-dock/app", + "version": "0.2.0", + "private": true, + "type": "module", + "scripts": { + "build": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.build.json && chmod +x dist/src/app/main.js", + "check": "pnpm run typecheck", + "start": "node dist/src/app/main.js", + "test": "vitest run", + "typecheck": "tsc --noEmit -p tsconfig.json" + } +} diff --git a/packages/app/src/app/main.ts b/packages/app/src/app/main.ts new file mode 100644 index 0000000..2a2b00d --- /dev/null +++ b/packages/app/src/app/main.ts @@ -0,0 +1,8 @@ +#!/usr/bin/env node +import { NodeContext, NodeRuntime } from "@effect/platform-node" +import { Effect, pipe } from "effect" +import { program } from "./program.js" + +const main = pipe(program, Effect.provide(NodeContext.layer)) + +NodeRuntime.runMain(main) diff --git a/packages/app/src/app/program.ts b/packages/app/src/app/program.ts new file mode 100644 index 0000000..d722ac1 --- /dev/null +++ b/packages/app/src/app/program.ts @@ -0,0 +1,27 @@ +import { Console, Effect, pipe } from "effect" +import type { BootstrapSummary } from "../core/bootstrap.js" +import { bootstrapProject } from "../shell/bootstrap.js" +import { formatUsage, readCliOptions } from "../shell/cli.js" + +const formatSuccess = (summary: BootstrapSummary): string => + [ + "", + `SpawnDock project created at ${summary.projectDir}`, + `Project: ${summary.projectName}`, + `Preview URL: ${summary.previewOrigin}`, + `Run: cd "${summary.projectDir}" && npm run dev`, + ].join("\n") + +const cliProgram = pipe( + readCliOptions, + Effect.flatMap((options) => + options.token.length > 0 + ? bootstrapProject(options) + : Effect.fail(new Error(formatUsage())), + ), +) + +export const program = Effect.matchEffect(cliProgram, { + onFailure: (error) => Console.error(error.message), + onSuccess: (summary) => Console.log(formatSuccess(summary)), +}) diff --git a/packages/app/src/core/bootstrap.ts b/packages/app/src/core/bootstrap.ts new file mode 100644 index 0000000..0d07367 --- /dev/null +++ b/packages/app/src/core/bootstrap.ts @@ -0,0 +1,175 @@ +export const DEFAULT_PROJECT_DIR = "spawndock-tma" +export const DEFAULT_CONTROL_PLANE_URL = "https://api.spawndock.app" +export const DEFAULT_CLAIM_PATH = "/v1/bootstrap/claim" +export const DEFAULT_TEMPLATE_REPO = "https://github.com/SpawnDock/tma-project.git" +export const DEFAULT_TEMPLATE_BRANCH = "master" +export const TEMPLATE_ID = "nextjs-template" + +export interface CliOptions { + readonly token: string + readonly controlPlaneUrl: string + readonly claimPath: string + readonly projectDir: string + readonly templateRepo: string + readonly templateBranch: string +} + +export interface ProjectContext { + readonly projectDir: string + readonly projectSlug: string + readonly projectName: string + readonly templateId: string +} + +export interface BootstrapClaim { + readonly projectId: string + readonly projectSlug: string + readonly controlPlaneUrl: string + readonly previewOrigin: string + readonly deviceSecret: string + readonly localPort: number +} + +export interface BootstrapSummary { + readonly projectDir: string + readonly projectName: string + readonly previewOrigin: string +} + +export interface GeneratedFile { + readonly path: string + readonly content: string +} + +export const normalizeDisplayName = (value: string): string => + value + .split(/[^a-zA-Z0-9]+/g) + .filter(Boolean) + .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1).toLowerCase()) + .join(" ") + +export const resolveProjectContext = (projectDir: string): ProjectContext => { + const projectSlug = projectDir.split(/[\\/]/g).filter(Boolean).at(-1) ?? projectDir + + return { + projectDir, + projectSlug, + projectName: normalizeDisplayName(projectSlug), + templateId: TEMPLATE_ID, + } +} + +export const resolvePreviewPath = (previewOrigin: string): string => { + const url = new URL(previewOrigin) + const normalizedPath = url.pathname.replace(/\/$/, "") + + return normalizedPath.length > 0 ? normalizedPath : "" +} + +export const resolvePreviewHost = (previewOrigin: string): string => + new URL(previewOrigin).host + +export const buildMcpServerUrl = (controlPlaneUrl: string): string => { + const url = new URL(controlPlaneUrl) + const normalizedPath = url.pathname.replace(/\/$/, "") + url.pathname = normalizedPath.length > 0 ? `${normalizedPath}/mcp/sse` : "/mcp/sse" + return url.toString() +} + +export const buildTonConnectManifest = ( + context: ProjectContext, + claim: BootstrapClaim, +): string => + `${JSON.stringify( + { + url: claim.previewOrigin, + name: context.projectName, + iconUrl: `${claim.previewOrigin}/favicon.ico`, + }, + null, + 2, + )}\n` + +export const buildGeneratedFiles = ( + context: ProjectContext, + claim: BootstrapClaim, +): ReadonlyArray => { + const previewPath = resolvePreviewPath(claim.previewOrigin) + const previewHost = resolvePreviewHost(claim.previewOrigin) + const mcpServerUrl = buildMcpServerUrl(claim.controlPlaneUrl) + + const appConfig = { + templateId: context.templateId, + projectId: claim.projectId, + projectSlug: claim.projectSlug, + projectName: context.projectName, + controlPlaneUrl: claim.controlPlaneUrl, + previewOrigin: claim.previewOrigin, + previewPath, + previewHost, + localPort: claim.localPort, + deviceSecret: claim.deviceSecret, + mcpServerUrl, + } + + const env = { + SPAWNDOCK_CONTROL_PLANE_URL: claim.controlPlaneUrl, + SPAWNDOCK_PREVIEW_ORIGIN: claim.previewOrigin, + SPAWNDOCK_PREVIEW_PATH: previewPath, + SPAWNDOCK_ASSET_PREFIX: previewPath, + SPAWNDOCK_PREVIEW_HOST: previewHost, + SPAWNDOCK_SERVER_ACTIONS_ALLOWED_ORIGINS: previewHost, + SPAWNDOCK_DEVICE_SECRET: claim.deviceSecret, + SPAWNDOCK_PROJECT_ID: claim.projectId, + SPAWNDOCK_PROJECT_SLUG: claim.projectSlug, + SPAWNDOCK_ALLOWED_DEV_ORIGINS: claim.previewOrigin, + } + + const opencode = { + $schema: "https://opencode.ai/config.json", + mcp: { + spawndock: { + type: "local", + command: ["npx", "-y", "@spawn-dock/mcp"], + enabled: true, + environment: { + MCP_SERVER_URL: mcpServerUrl, + }, + }, + }, + } + + return [ + { + path: "spawndock.config.json", + content: `${JSON.stringify(appConfig, null, 2)}\n`, + }, + { + path: ".env.local", + content: `${Object.entries(env) + .map(([key, value]) => `${key}=${value}`) + .join("\n")}\n`, + }, + { + path: "spawndock.dev-tunnel.json", + content: `${JSON.stringify( + { + controlPlane: claim.controlPlaneUrl, + projectSlug: claim.projectSlug, + deviceSecret: claim.deviceSecret, + port: claim.localPort, + }, + null, + 2, + )}\n`, + }, + { + path: "opencode.json", + content: `${JSON.stringify(opencode, null, 2)}\n`, + }, + { + path: "public/tonconnect-manifest.json", + content: buildTonConnectManifest(context, claim), + }, + ] +} diff --git a/packages/app/src/shell/bootstrap.ts b/packages/app/src/shell/bootstrap.ts new file mode 100644 index 0000000..d9d9d8d --- /dev/null +++ b/packages/app/src/shell/bootstrap.ts @@ -0,0 +1,252 @@ +import { mkdirSync, readdirSync, writeFileSync } from "node:fs" +import { spawnSync, type SpawnSyncReturns } from "node:child_process" +import { dirname, join, resolve } from "node:path" +import { Effect } from "effect" +import { + buildGeneratedFiles, + type BootstrapClaim, + type BootstrapSummary, + type CliOptions, + resolveProjectContext, +} from "../core/bootstrap.js" + +export const bootstrapProject = ( + options: CliOptions, +): Effect.Effect => + Effect.gen(function* () { + if (options.token.length === 0) { + yield* Effect.fail(new Error("Missing pairing token.")) + } + + const projectDir = resolve(process.cwd(), options.projectDir) + const context = resolveProjectContext(projectDir) + + yield* ensureEmptyProjectDir(projectDir) + yield* ensureParentDirectory(projectDir) + yield* cloneTemplateRepo(projectDir, options.templateRepo, options.templateBranch) + + const claim = yield* claimProject( + options.controlPlaneUrl, + options.claimPath, + { + token: options.token, + ["projectSlug"]: context.projectSlug, + projectName: context.projectName, + templateId: context.templateId, + ["localPort"]: 3000, + }, + ) + + yield* writeGeneratedFilesToProject(projectDir, context, claim) + yield* installDependencies(projectDir) + + return { + projectDir, + projectName: context.projectName, + previewOrigin: claim.previewOrigin, + } + }) + +const ensureEmptyProjectDir = (projectDir: string): Effect.Effect => + Effect.try({ + try: () => { + try { + const entries = readdirSync(projectDir) + if (entries.length > 0) { + throw new Error(`Target directory is not empty: ${projectDir}`) + } + } catch (error) { + if (isNodeError(error) && error.code === "ENOENT") { + return + } + + throw toError(error) + } + }, + catch: toError, + }) + +const ensureParentDirectory = (projectDir: string): Effect.Effect => + Effect.try({ + try: () => { + mkdirSync(dirname(projectDir), { recursive: true }) + }, + catch: toError, + }) + +const cloneTemplateRepo = ( + projectDir: string, + templateRepo: string, + templateBranch: string, +): Effect.Effect => + runCommand("git", [ + "clone", + "--depth", + "1", + "--branch", + templateBranch, + templateRepo, + projectDir, + ]).pipe(Effect.asVoid) + +const claimProject = ( + controlPlaneUrl: string, + claimPath: string, + payload: Record, +): Effect.Effect => + Effect.tryPromise({ + try: async () => { + const normalizedControlPlaneUrl = controlPlaneUrl.replace(/\/$/, "") + const resolvedClaimPath = claimPath.startsWith("/") ? claimPath : `/${claimPath}` + const response = await fetch(`${normalizedControlPlaneUrl}${resolvedClaimPath}`, { + method: "POST", + headers: { + "content-type": "application/json", + }, + body: JSON.stringify(payload), + }) + + if (!response.ok) { + throw new Error(`SpawnDock control plane claim failed: ${response.status}`) + } + + const json = (await response.json()) as unknown + const parsed = parseClaimResponse( + json, + payload["projectSlug"], + normalizedControlPlaneUrl, + payload["localPort"], + ) + + if (parsed === null) { + throw new Error("SpawnDock control plane response is missing required bootstrap fields") + } + + return parsed + }, + catch: toError, + }) + +const writeGeneratedFilesToProject = ( + projectDir: string, + context: ReturnType, + claim: BootstrapClaim, +): Effect.Effect => + Effect.try({ + try: () => { + for (const file of buildGeneratedFiles(context, claim)) { + const targetPath = join(projectDir, file.path) + mkdirSync(dirname(targetPath), { recursive: true }) + writeFileSync(targetPath, file.content, "utf8") + } + }, + catch: toError, + }) + +const installDependencies = (projectDir: string): Effect.Effect => + Effect.gen(function* () { + const corepackResult = yield* runCommand("corepack", ["pnpm", "install"], projectDir, false) + if (corepackResult.status === 0) { + return + } + + yield* runCommand("pnpm", ["install"], projectDir) + }) + +const runCommand = ( + command: string, + args: ReadonlyArray, + cwd = process.cwd(), + failOnNonZero = true, +): Effect.Effect, Error> => + Effect.try({ + try: () => { + const result = spawnSync(command, [...args], { + cwd, + encoding: "utf8", + stdio: "pipe", + }) + + if (failOnNonZero && result.status !== 0) { + throw new Error( + result.stderr.trim() || + result.stdout.trim() || + `Command failed: ${command} ${args.join(" ")}`, + ) + } + + return result + }, + catch: toError, + }) + +const parseClaimResponse = ( + input: unknown, + fallbackProjectSlug: string | number | undefined, + fallbackControlPlaneUrl: string, + fallbackLocalPort: string | number | undefined, +): BootstrapClaim | null => { + if (!isRecord(input)) { + return null + } + + const projectValue = input["project"] + const project = isRecord(projectValue) ? projectValue : {} + const projectId = readString(input, "projectId") ?? readString(project, "id") + const projectSlug = + readString(input, "projectSlug") ?? + readString(input, "slug") ?? + readString(project, "slug") ?? + (typeof fallbackProjectSlug === "string" ? fallbackProjectSlug : null) + const controlPlaneUrl = readString(input, "controlPlaneUrl") ?? fallbackControlPlaneUrl + const previewOrigin = + readString(input, "previewOrigin") ?? + readString(input, "launchUrl") ?? + readString(input, "staticAssetsBaseUrl") ?? + readString(input, "url") + const deviceSecret = + readString(input, "deviceSecret") ?? + readString(input, "deviceToken") ?? + readString(input, "deployToken") ?? + readString(input, "token") + const localPort = + readNumber(input, "localPort") ?? + (typeof fallbackLocalPort === "number" ? fallbackLocalPort : 3000) + + if ( + projectId === null || + projectSlug === null || + previewOrigin === null || + deviceSecret === null + ) { + return null + } + + return { + projectId, + projectSlug, + controlPlaneUrl, + previewOrigin, + deviceSecret, + localPort, + } +} + +const readNumber = (input: Record, key: string): number | null => { + const value = input[key] + return typeof value === "number" ? value : null +} + +const readString = (input: Record, key: string): string | null => { + const value = input[key] + return typeof value === "string" ? value : null +} + +const isRecord = (value: unknown): value is Record => + typeof value === "object" && value !== null + +const isNodeError = (error: unknown): error is NodeJS.ErrnoException => + error instanceof Error + +const toError = (cause: unknown): Error => + cause instanceof Error ? cause : new Error(String(cause)) diff --git a/src/args.mjs b/packages/app/src/shell/cli.ts similarity index 59% rename from src/args.mjs rename to packages/app/src/shell/cli.ts index 6d496cc..c8e6d50 100644 --- a/src/args.mjs +++ b/packages/app/src/shell/cli.ts @@ -1,30 +1,44 @@ -export const DEFAULT_PROJECT_DIR = "spawndock-tma" -export const DEFAULT_CONTROL_PLANE_URL = "https://api.spawndock.app" -export const DEFAULT_CLAIM_PATH = "/v1/bootstrap/claim" -export const DEFAULT_TEMPLATE_REPO = "https://github.com/SpawnDock/tma-project.git" -export const DEFAULT_TEMPLATE_BRANCH = "master" -export const TEMPLATE_ID = "nextjs-template" - -export const normalizeDisplayName = (value) => - value - .split(/[^a-zA-Z0-9]+/g) - .filter(Boolean) - .map((segment) => segment[0].toUpperCase() + segment.slice(1).toLowerCase()) - .join(" ") - -export const parseArgs = (argv, env = process.env) => { - const result = { +import { Effect } from "effect" +import { + DEFAULT_CLAIM_PATH, + DEFAULT_CONTROL_PLANE_URL, + DEFAULT_PROJECT_DIR, + DEFAULT_TEMPLATE_BRANCH, + DEFAULT_TEMPLATE_REPO, + type CliOptions, +} from "../core/bootstrap.js" + +export const formatUsage = ( + invocation = "npx create-spawn-dock --token [project-dir]", +): string => `Usage: ${invocation}` + +export const parseArgs = ( + argv: ReadonlyArray, + env: NodeJS.ProcessEnv = process.env, +): CliOptions => { + const result: { + token: string + controlPlaneUrl: string + claimPath: string + projectDir: string + templateRepo: string + templateBranch: string + } = { token: "", - controlPlaneUrl: env.SPAWNDOCK_CONTROL_PLANE_URL ?? DEFAULT_CONTROL_PLANE_URL, - claimPath: env.SPAWNDOCK_CLAIM_PATH ?? DEFAULT_CLAIM_PATH, + controlPlaneUrl: env["SPAWNDOCK_CONTROL_PLANE_URL"] ?? DEFAULT_CONTROL_PLANE_URL, + claimPath: env["SPAWNDOCK_CLAIM_PATH"] ?? DEFAULT_CLAIM_PATH, projectDir: DEFAULT_PROJECT_DIR, - templateRepo: env.SPAWNDOCK_TEMPLATE_REPO ?? DEFAULT_TEMPLATE_REPO, - templateBranch: env.SPAWNDOCK_TEMPLATE_BRANCH ?? DEFAULT_TEMPLATE_BRANCH + templateRepo: env["SPAWNDOCK_TEMPLATE_REPO"] ?? DEFAULT_TEMPLATE_REPO, + templateBranch: env["SPAWNDOCK_TEMPLATE_BRANCH"] ?? DEFAULT_TEMPLATE_BRANCH, } for (let index = 0; index < argv.length; index += 1) { const value = argv[index] + if (value === undefined) { + continue + } + if (value === "--token") { result.token = argv[index + 1] ?? "" index += 1 @@ -89,5 +103,7 @@ export const parseArgs = (argv, env = process.env) => { } } - return result + return result satisfies CliOptions } + +export const readCliOptions = Effect.sync(() => parseArgs(process.argv.slice(2), process.env)) diff --git a/packages/app/tests/bootstrap.test.ts b/packages/app/tests/bootstrap.test.ts new file mode 100644 index 0000000..76c6dc2 --- /dev/null +++ b/packages/app/tests/bootstrap.test.ts @@ -0,0 +1,55 @@ +import { describe, expect, it } from "vitest" +import { + buildGeneratedFiles, + buildMcpServerUrl, + normalizeDisplayName, + resolveProjectContext, +} from "../src/core/bootstrap.js" + +describe("normalizeDisplayName", () => { + it("converts slug to title case", () => { + expect(normalizeDisplayName("my-next-app")).toBe("My Next App") + }) +}) + +describe("resolveProjectContext", () => { + it("derives slug and title from project directory", () => { + const context = resolveProjectContext("/tmp/demo-project") + + expect(context.projectSlug).toBe("demo-project") + expect(context.projectName).toBe("Demo Project") + }) +}) + +describe("buildMcpServerUrl", () => { + it("builds the prefixed mcp url", () => { + expect(buildMcpServerUrl("https://api.example.com")).toBe("https://api.example.com/mcp/sse") + }) +}) + +describe("buildGeneratedFiles", () => { + it("creates runtime files without storing template overlay", () => { + const files = buildGeneratedFiles( + { + templateId: "nextjs-template", + projectDir: "/tmp/demo-project", + projectSlug: "demo-project", + projectName: "Demo Project", + }, + { + projectId: "project_123", + projectSlug: "demo-project", + controlPlaneUrl: "https://api.example.com", + previewOrigin: "https://api.example.com/preview/demo-project", + deviceSecret: "secret_123", + localPort: 3000, + }, + ) + + const fileMap = new Map(files.map((file) => [file.path, file.content])) + + expect(fileMap.get("opencode.json")).toContain("\"MCP_SERVER_URL\": \"https://api.example.com/mcp/sse\"") + expect(fileMap.get("public/tonconnect-manifest.json")).toContain("\"url\": \"https://api.example.com/preview/demo-project\"") + expect(fileMap.get("spawndock.dev-tunnel.json")).toContain("\"projectSlug\": \"demo-project\"") + }) +}) diff --git a/packages/app/tests/cli.test.ts b/packages/app/tests/cli.test.ts new file mode 100644 index 0000000..4472864 --- /dev/null +++ b/packages/app/tests/cli.test.ts @@ -0,0 +1,50 @@ +import { describe, expect, it } from "vitest" +import { formatUsage, parseArgs } from "../src/shell/cli.js" + +describe("parseArgs", () => { + it("reads token and project directory", () => { + const result = parseArgs(["--token", "abc", "my-project"]) + + expect(result.token).toBe("abc") + expect(result.projectDir).toBe("my-project") + }) + + it("reads custom claim path", () => { + const result = parseArgs(["--token=abc", "--claim-path", "/claim", "my-project"]) + + expect(result.claimPath).toBe("/claim") + expect(result.projectDir).toBe("my-project") + }) + + it("reads control plane URL from environment", () => { + const result = parseArgs( + ["--token", "abc", "my-project"], + { SPAWNDOCK_CONTROL_PLANE_URL: "https://example.trycloudflare.com" }, + ) + + expect(result.controlPlaneUrl).toBe("https://example.trycloudflare.com") + }) + + it("reads template repo and branch overrides", () => { + const result = parseArgs([ + "--token", + "abc", + "--template-repo", + "https://example.com/tma.git", + "--template-branch", + "next", + "my-project", + ]) + + expect(result.templateRepo).toBe("https://example.com/tma.git") + expect(result.templateBranch).toBe("next") + }) +}) + +describe("formatUsage", () => { + it("renders a custom invocation", () => { + expect(formatUsage("npx create-spawn-dock --token [project-dir]")).toBe( + "Usage: npx create-spawn-dock --token [project-dir]", + ) + }) +}) diff --git a/packages/app/tsconfig.build.json b/packages/app/tsconfig.build.json new file mode 100644 index 0000000..cac051e --- /dev/null +++ b/packages/app/tsconfig.build.json @@ -0,0 +1,5 @@ +{ + "extends": "./tsconfig.json", + "include": ["src/**/*"], + "exclude": ["dist", "node_modules", "tests", "vitest.config.ts"] +} diff --git a/packages/app/tsconfig.json b/packages/app/tsconfig.json new file mode 100644 index 0000000..a113abf --- /dev/null +++ b/packages/app/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": ".", + "outDir": "dist", + "types": ["node", "vitest/globals"], + "baseUrl": ".", + "paths": { + "@/*": ["src/*"] + } + }, + "include": ["src/**/*", "tests/**/*", "vitest.config.ts"], + "exclude": ["dist", "node_modules"] +} diff --git a/packages/app/vitest.config.ts b/packages/app/vitest.config.ts new file mode 100644 index 0000000..73368a2 --- /dev/null +++ b/packages/app/vitest.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from "vitest/config" + +export default defineConfig({ + test: { + environment: "node", + include: ["tests/**/*.test.ts"] + } +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..c6bc856 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,2086 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@effect/platform-node': + specifier: ^0.106.0 + version: 0.106.0(@effect/cluster@0.58.0(@effect/platform@0.96.0(effect@3.21.0))(@effect/rpc@0.75.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/sql@0.51.0(@effect/experimental@0.60.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/workflow@0.18.0(@effect/experimental@0.60.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(@effect/rpc@0.75.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(@effect/rpc@0.75.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/sql@0.51.0(@effect/experimental@0.60.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(effect@3.21.0) + '@effect/schema': + specifier: ^0.75.5 + version: 0.75.5(effect@3.21.0) + effect: + specifier: ^3.21.0 + version: 3.21.0 + devDependencies: + '@changesets/changelog-github': + specifier: ^0.6.0 + version: 0.6.0 + '@changesets/cli': + specifier: ^2.30.0 + version: 2.30.0(@types/node@24.12.0) + '@types/node': + specifier: ^24.12.0 + version: 24.12.0 + typescript: + specifier: ^5.9.3 + version: 5.9.3 + vitest: + specifier: ^4.1.0 + version: 4.1.0(@types/node@24.12.0)(vite@8.0.1(@types/node@24.12.0)) + + packages/app: {} + +packages: + + '@babel/runtime@7.29.2': + resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} + engines: {node: '>=6.9.0'} + + '@changesets/apply-release-plan@7.1.0': + resolution: {integrity: sha512-yq8ML3YS7koKQ/9bk1PqO0HMzApIFNwjlwCnwFEXMzNe8NpzeeYYKCmnhWJGkN8g7E51MnWaSbqRcTcdIxUgnQ==} + + '@changesets/assemble-release-plan@6.0.9': + resolution: {integrity: sha512-tPgeeqCHIwNo8sypKlS3gOPmsS3wP0zHt67JDuL20P4QcXiw/O4Hl7oXiuLnP9yg+rXLQ2sScdV1Kkzde61iSQ==} + + '@changesets/changelog-git@0.2.1': + resolution: {integrity: sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==} + + '@changesets/changelog-github@0.6.0': + resolution: {integrity: sha512-wA2/y4hR/A1K411cCT75rz0d46Iezxp1WYRFoFJDIUpkQ6oDBAIUiU7BZkDCmYgz0NBl94X1lgcZO+mHoiHnFg==} + + '@changesets/cli@2.30.0': + resolution: {integrity: sha512-5D3Nk2JPqMI1wK25pEymeWRSlSMdo5QOGlyfrKg0AOufrUcjEE3RQgaCpHoBiM31CSNrtSgdJ0U6zL1rLDDfBA==} + hasBin: true + + '@changesets/config@3.1.3': + resolution: {integrity: sha512-vnXjcey8YgBn2L1OPWd3ORs0bGC4LoYcK/ubpgvzNVr53JXV5GiTVj7fWdMRsoKUH7hhhMAQnsJUqLr21EncNw==} + + '@changesets/errors@0.2.0': + resolution: {integrity: sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==} + + '@changesets/get-dependents-graph@2.1.3': + resolution: {integrity: sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ==} + + '@changesets/get-github-info@0.8.0': + resolution: {integrity: sha512-cRnC+xdF0JIik7coko3iUP9qbnfi1iJQ3sAa6dE+Tx3+ET8bjFEm63PA4WEohgjYcmsOikPHWzPsMWWiZmntOQ==} + + '@changesets/get-release-plan@4.0.15': + resolution: {integrity: sha512-Q04ZaRPuEVZtA+auOYgFaVQQSA98dXiVe/yFaZfY7hoSmQICHGvP0TF4u3EDNHWmmCS4ekA/XSpKlSM2PyTS2g==} + + '@changesets/get-version-range-type@0.4.0': + resolution: {integrity: sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==} + + '@changesets/git@3.0.4': + resolution: {integrity: sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw==} + + '@changesets/logger@0.1.1': + resolution: {integrity: sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==} + + '@changesets/parse@0.4.3': + resolution: {integrity: sha512-ZDmNc53+dXdWEv7fqIUSgRQOLYoUom5Z40gmLgmATmYR9NbL6FJJHwakcCpzaeCy+1D0m0n7mT4jj2B/MQPl7A==} + + '@changesets/pre@2.0.2': + resolution: {integrity: sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==} + + '@changesets/read@0.6.7': + resolution: {integrity: sha512-D1G4AUYGrBEk8vj8MGwf75k9GpN6XL3wg8i42P2jZZwFLXnlr2Pn7r9yuQNbaMCarP7ZQWNJbV6XLeysAIMhTA==} + + '@changesets/should-skip-package@0.1.2': + resolution: {integrity: sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==} + + '@changesets/types@4.1.0': + resolution: {integrity: sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==} + + '@changesets/types@6.1.0': + resolution: {integrity: sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==} + + '@changesets/write@0.4.0': + resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} + + '@effect/cluster@0.58.0': + resolution: {integrity: sha512-0Zog7s7XdntWcTqdqWPoj6nc7hPaWIzp0k0DsFUWyCynXNPK9dAtgFrSce04NhddNqqbhtZck/lhuqJwNBrprQ==} + peerDependencies: + '@effect/platform': ^0.96.0 + '@effect/rpc': ^0.75.0 + '@effect/sql': ^0.51.0 + '@effect/workflow': ^0.18.0 + effect: ^3.21.0 + + '@effect/experimental@0.60.0': + resolution: {integrity: sha512-i5zIg7Xup2KgHyqHlYtkgqSE1bNzCL0GbbTQxrpIzKF0q/ebknOk/ox8B/gIq2vImjoEE81h/oxU+6i1NH210g==} + peerDependencies: + '@effect/platform': ^0.96.0 + effect: ^3.21.0 + ioredis: ^5 + lmdb: ^3 + peerDependenciesMeta: + ioredis: + optional: true + lmdb: + optional: true + + '@effect/platform-node-shared@0.59.0': + resolution: {integrity: sha512-3bq2YKKfLY7UFauZSxqZUneCXoA3SMSls82V+0RKunvRlfPuPQW0hVn6t1RkvEdh0PDoygWG2mZXYQa6Iqgp9A==} + peerDependencies: + '@effect/cluster': ^0.58.0 + '@effect/platform': ^0.96.0 + '@effect/rpc': ^0.75.0 + '@effect/sql': ^0.51.0 + effect: ^3.21.0 + + '@effect/platform-node@0.106.0': + resolution: {integrity: sha512-mpsJK2jNLVd0jQAjHKBo8j3wdKWznSGvfnKBcAuG/9Rr4mb8bMRZFLXHHT9wUP7EvnZ0tDZJgEDxkC+j+ByRag==} + peerDependencies: + '@effect/cluster': ^0.58.0 + '@effect/platform': ^0.96.0 + '@effect/rpc': ^0.75.0 + '@effect/sql': ^0.51.0 + effect: ^3.21.0 + + '@effect/platform@0.96.0': + resolution: {integrity: sha512-U7PLhkVzg7zzrgFvyWATOzD6reL87KG/fcdOxgLWBQ/J5CCU6qdPAVG+0o6o+IxcsLoqGwxs+rFxaFzrdtDV1A==} + peerDependencies: + effect: ^3.21.0 + + '@effect/rpc@0.75.0': + resolution: {integrity: sha512-VFeJ16cZUXqiIzG9UHOVKGuiBPJ7fV+0lEbJU6xi12JnnxXe/19BQPpOwiRawCUbPOR3/xIURDUgGxU+Ft0pvQ==} + peerDependencies: + '@effect/platform': ^0.96.0 + effect: ^3.21.0 + + '@effect/schema@0.75.5': + resolution: {integrity: sha512-TQInulTVCuF+9EIbJpyLP6dvxbQJMphrnRqgexm/Ze39rSjfhJuufF7XvU3SxTgg3HnL7B/kpORTJbHhlE6thw==} + deprecated: this package has been merged into the main effect package + peerDependencies: + effect: ^3.9.2 + + '@effect/sql@0.51.0': + resolution: {integrity: sha512-e7hWe46QD15eMCr4kNBMVdItIVK/WLHJG+d8DLL1FjVf5Ra82k2mwUYIXplJewVbHjt3my6GSKPPd1ZrQjVd5A==} + peerDependencies: + '@effect/experimental': ^0.60.0 + '@effect/platform': ^0.96.0 + effect: ^3.21.0 + + '@effect/workflow@0.18.0': + resolution: {integrity: sha512-9Zp+x9ADtR0H6CRhU6wLyPcIRjO1PXjvSpUlFlBQ8piw7ldjPmnUWEY8YQuH6eExV2dalQ4z2LMiZ5Bd7XAJbA==} + peerDependencies: + '@effect/experimental': ^0.60.0 + '@effect/platform': ^0.96.0 + '@effect/rpc': ^0.75.0 + effect: ^3.21.0 + + '@emnapi/core@1.9.1': + resolution: {integrity: sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==} + + '@emnapi/runtime@1.9.1': + resolution: {integrity: sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==} + + '@emnapi/wasi-threads@1.2.0': + resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==} + + '@inquirer/external-editor@1.0.3': + resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@manypkg/find-root@1.1.0': + resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} + + '@manypkg/get-packages@1.1.3': + resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} + + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': + resolution: {integrity: sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==} + cpu: [arm64] + os: [darwin] + + '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3': + resolution: {integrity: sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==} + cpu: [x64] + os: [darwin] + + '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3': + resolution: {integrity: sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==} + cpu: [arm64] + os: [linux] + + '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3': + resolution: {integrity: sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==} + cpu: [arm] + os: [linux] + + '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3': + resolution: {integrity: sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==} + cpu: [x64] + os: [linux] + + '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3': + resolution: {integrity: sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==} + cpu: [x64] + os: [win32] + + '@napi-rs/wasm-runtime@1.1.1': + resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@oxc-project/types@0.120.0': + resolution: {integrity: sha512-k1YNu55DuvAip/MGE1FTsIuU3FUCn6v/ujG9V7Nq5Df/kX2CWb13hhwD0lmJGMGqE+bE1MXvv9SZVnMzEXlWcg==} + + '@parcel/watcher-android-arm64@2.5.6': + resolution: {integrity: sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] + + '@parcel/watcher-darwin-arm64@2.5.6': + resolution: {integrity: sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] + + '@parcel/watcher-darwin-x64@2.5.6': + resolution: {integrity: sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] + + '@parcel/watcher-freebsd-x64@2.5.6': + resolution: {integrity: sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] + + '@parcel/watcher-linux-arm-glibc@2.5.6': + resolution: {integrity: sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@parcel/watcher-linux-arm-musl@2.5.6': + resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + libc: [musl] + + '@parcel/watcher-linux-arm64-glibc@2.5.6': + resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@parcel/watcher-linux-arm64-musl@2.5.6': + resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@parcel/watcher-linux-x64-glibc@2.5.6': + resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@parcel/watcher-linux-x64-musl@2.5.6': + resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@parcel/watcher-win32-arm64@2.5.6': + resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] + + '@parcel/watcher-win32-ia32@2.5.6': + resolution: {integrity: sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==} + engines: {node: '>= 10.0.0'} + cpu: [ia32] + os: [win32] + + '@parcel/watcher-win32-x64@2.5.6': + resolution: {integrity: sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] + + '@parcel/watcher@2.5.6': + resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==} + engines: {node: '>= 10.0.0'} + + '@rolldown/binding-android-arm64@1.0.0-rc.10': + resolution: {integrity: sha512-jOHxwXhxmFKuXztiu1ORieJeTbx5vrTkcOkkkn2d35726+iwhrY1w/+nYY/AGgF12thg33qC3R1LMBF5tHTZHg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.0-rc.10': + resolution: {integrity: sha512-gED05Teg/vtTZbIJBc4VNMAxAFDUPkuO/rAIyyxZjTj1a1/s6z5TII/5yMGZ0uLRCifEtwUQn8OlYzuYc0m70w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.0-rc.10': + resolution: {integrity: sha512-rI15NcM1mA48lqrIxVkHfAqcyFLcQwyXWThy+BQ5+mkKKPvSO26ir+ZDp36AgYoYVkqvMcdS8zOE6SeBsR9e8A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.0-rc.10': + resolution: {integrity: sha512-XZRXHdTa+4ME1MuDVp021+doQ+z6Ei4CCFmNc5/sKbqb8YmkiJdj8QKlV3rCI0AJtAeSB5n0WGPuJWNL9p/L2w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.10': + resolution: {integrity: sha512-R0SQMRluISSLzFE20sPWYHVmJdDQnRyc/FzSCN72BqQmh2SOZUFG+N3/vBZpR4C6WpEUVYJLrYUXaj43sJsNLA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.10': + resolution: {integrity: sha512-Y1reMrV/o+cwpduYhJuOE3OMKx32RMYCidf14y+HssARRmhDuWXJ4yVguDg2R/8SyyGNo+auzz64LnPK9Hq6jg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.10': + resolution: {integrity: sha512-vELN+HNb2IzuzSBUOD4NHmP9yrGwl1DVM29wlQvx1OLSclL0NgVWnVDKl/8tEks79EFek/kebQKnNJkIAA4W2g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.10': + resolution: {integrity: sha512-ZqrufYTgzxbHwpqOjzSsb0UV/aV2TFIY5rP8HdsiPTv/CuAgCRjM6s9cYFwQ4CNH+hf9Y4erHW1GjZuZ7WoI7w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.10': + resolution: {integrity: sha512-gSlmVS1FZJSRicA6IyjoRoKAFK7IIHBs7xJuHRSmjImqk3mPPWbR7RhbnfH2G6bcmMEllCt2vQ/7u9e6bBnByg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.10': + resolution: {integrity: sha512-eOCKUpluKgfObT2pHjztnaWEIbUabWzk3qPZ5PuacuPmr4+JtQG4k2vGTY0H15edaTnicgU428XW/IH6AimcQw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.0.0-rc.10': + resolution: {integrity: sha512-Xdf2jQbfQowJnLcgYfD/m0Uu0Qj5OdxKallD78/IPPfzaiaI4KRAwZzHcKQ4ig1gtg1SuzC7jovNiM2TzQsBXA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.10': + resolution: {integrity: sha512-o1hYe8hLi1EY6jgPFyxQgQ1wcycX+qz8eEbVmot2hFkgUzPxy9+kF0u0NIQBeDq+Mko47AkaFFaChcvZa9UX9Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.0-rc.10': + resolution: {integrity: sha512-Ugv9o7qYJudqQO5Y5y2N2SOo6S4WiqiNOpuQyoPInnhVzCY+wi/GHltcLHypG9DEUYMB0iTB/huJrpadiAcNcA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.10': + resolution: {integrity: sha512-7UODQb4fQUNT/vmgDZBl3XOBAIOutP5R3O/rkxg0aLfEGQ4opbCgU5vOw/scPe4xOqBwL9fw7/RP1vAMZ6QlAQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.10': + resolution: {integrity: sha512-PYxKHMVHOb5NJuDL53vBUl1VwUjymDcYI6rzpIni0C9+9mTiJedvUxSk7/RPp7OOAm3v+EjgMu9bIy3N6b408w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.0-rc.10': + resolution: {integrity: sha512-UkVDEFk1w3mveXeKgaTuYfKWtPbvgck1dT8TUG3bnccrH0XtLTuAyfCoks4Q/M5ZGToSVJTIQYCzy2g/atAOeg==} + + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/node@12.20.55': + resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} + + '@types/node@24.12.0': + resolution: {integrity: sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==} + + '@vitest/expect@4.1.0': + resolution: {integrity: sha512-EIxG7k4wlWweuCLG9Y5InKFwpMEOyrMb6ZJ1ihYu02LVj/bzUwn2VMU+13PinsjRW75XnITeFrQBMH5+dLvCDA==} + + '@vitest/mocker@4.1.0': + resolution: {integrity: sha512-evxREh+Hork43+Y4IOhTo+h5lGmVRyjqI739Rz4RlUPqwrkFFDF6EMvOOYjTx4E8Tl6gyCLRL8Mu7Ry12a13Tw==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@4.1.0': + resolution: {integrity: sha512-3RZLZlh88Ib0J7NQTRATfc/3ZPOnSUn2uDBUoGNn5T36+bALixmzphN26OUD3LRXWkJu4H0s5vvUeqBiw+kS0A==} + + '@vitest/runner@4.1.0': + resolution: {integrity: sha512-Duvx2OzQ7d6OjchL+trw+aSrb9idh7pnNfxrklo14p3zmNL4qPCDeIJAK+eBKYjkIwG96Bc6vYuxhqDXQOWpoQ==} + + '@vitest/snapshot@4.1.0': + resolution: {integrity: sha512-0Vy9euT1kgsnj1CHttwi9i9o+4rRLEaPRSOJ5gyv579GJkNpgJK+B4HSv/rAWixx2wdAFci1X4CEPjiu2bXIMg==} + + '@vitest/spy@4.1.0': + resolution: {integrity: sha512-pz77k+PgNpyMDv2FV6qmk5ZVau6c3R8HC8v342T2xlFxQKTrSeYw9waIJG8KgV9fFwAtTu4ceRzMivPTH6wSxw==} + + '@vitest/utils@4.1.0': + resolution: {integrity: sha512-XfPXT6a8TZY3dcGY8EdwsBulFCIw+BeeX0RZn2x/BtiY/75YGh8FeWGG8QISN/WhaqSrE2OrlDgtF8q5uhOTmw==} + + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + better-path-resolve@1.0.0: + resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} + engines: {node: '>=4'} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} + + chardet@2.1.1: + resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + dataloader@1.4.0: + resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==} + + detect-indent@6.1.0: + resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} + engines: {node: '>=8'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + dotenv@8.6.0: + resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==} + engines: {node: '>=10'} + + effect@3.21.0: + resolution: {integrity: sha512-PPN80qRokCd1f015IANNhrwOnLO7GrrMQfk4/lnZRE/8j7UPWrNNjPV0uBrZutI/nHzernbW+J0hdqQysHiSnQ==} + + enquirer@2.4.1: + resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} + engines: {node: '>=8.6'} + + es-module-lexer@2.0.0: + resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + engines: {node: '>=12.0.0'} + + extendable-error@0.1.7: + resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} + + fast-check@3.23.2: + resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==} + engines: {node: '>=8.0.0'} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-my-way-ts@0.1.6: + resolution: {integrity: sha512-a85L9ZoXtNAey3Y6Z+eBWW658kO/MwR7zIafkIUPUMf3isZG0NCs2pjW2wtjxAKuJPxMAsHUIP4ZPGv0o5gyTA==} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + fs-extra@7.0.1: + resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} + engines: {node: '>=6 <7 || >=8'} + + fs-extra@8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + human-id@4.1.3: + resolution: {integrity: sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q==} + hasBin: true + + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + engines: {node: '>=0.10.0'} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-subdir@1.2.0: + resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} + engines: {node: '>=4'} + + is-windows@1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + js-yaml@3.14.2: + resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} + hasBin: true + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + jsonfile@4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + + kubernetes-types@1.30.0: + resolution: {integrity: sha512-Dew1okvhM/SQcIa2rcgujNndZwU8VnSapDgdxlYoB84ZlpAD43U6KLAFqYo17ykSFGHNPrg0qry0bP+GJd9v7Q==} + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + lodash.startcase@4.4.0: + resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime@3.0.0: + resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} + engines: {node: '>=10.0.0'} + hasBin: true + + mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + + msgpackr-extract@3.0.3: + resolution: {integrity: sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==} + hasBin: true + + msgpackr@1.11.9: + resolution: {integrity: sha512-FkoAAyyA6HM8wL882EcEyFZ9s7hVADSwG9xrVx3dxxNQAtgADTrJoEWivID82Iv1zWDsv/OtbrrcZAzGzOMdNw==} + + multipasta@0.2.7: + resolution: {integrity: sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-gyp-build-optional-packages@5.2.2: + resolution: {integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==} + hasBin: true + + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + + outdent@0.5.0: + resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} + + p-filter@2.1.0: + resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} + engines: {node: '>=8'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-map@2.1.0: + resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} + engines: {node: '>=6'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + package-manager-detector@0.2.11: + resolution: {integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + pify@4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} + + postcss@8.5.8: + resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} + engines: {node: ^10 || ^12 || >=14} + + prettier@2.8.8: + resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} + engines: {node: '>=10.13.0'} + hasBin: true + + pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + + quansync@0.2.11: + resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + read-yaml-file@1.1.0: + resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} + engines: {node: '>=6'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rolldown@1.0.0-rc.10: + resolution: {integrity: sha512-q7j6vvarRFmKpgJUT8HCAUljkgzEp4LAhPlJUvQhA5LA1SUL36s5QCysMutErzL3EbNOZOkoziSx9iZC4FddKA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + engines: {node: '>=10'} + hasBin: true + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + spawndamnit@3.0.1: + resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@4.0.0: + resolution: {integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + term-size@2.2.1: + resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} + engines: {node: '>=8'} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@1.0.4: + resolution: {integrity: sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==} + engines: {node: '>=18'} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + tinyrainbow@3.1.0: + resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} + engines: {node: '>=14.0.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + + undici@7.24.5: + resolution: {integrity: sha512-3IWdCpjgxp15CbJnsi/Y9TCDE7HWVN19j1hmzVhoAkY/+CJx449tVxT5wZc1Gwg8J+P0LWvzlBzxYRnHJ+1i7Q==} + engines: {node: '>=20.18.1'} + + universalify@0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + + uuid@11.1.0: + resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} + hasBin: true + + vite@8.0.1: + resolution: {integrity: sha512-wt+Z2qIhfFt85uiyRt5LPU4oVEJBXj8hZNWKeqFG4gRG/0RaRGJ7njQCwzFVjO+v4+Ipmf5CY7VdmZRAYYBPHw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.0 + esbuild: ^0.27.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@4.1.0: + resolution: {integrity: sha512-YbDrMF9jM2Lqc++2530UourxZHmkKLxrs4+mYhEwqWS97WJ7wOYEkcr+QfRgJ3PW9wz3odRijLZjHEaRLTNbqw==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.1.0 + '@vitest/browser-preview': 4.1.0 + '@vitest/browser-webdriverio': 4.1.0 + '@vitest/ui': 4.1.0 + happy-dom: '*' + jsdom: '*' + vite: ^6.0.0 || ^7.0.0 || ^8.0.0-0 + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + ws@8.19.0: + resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + +snapshots: + + '@babel/runtime@7.29.2': {} + + '@changesets/apply-release-plan@7.1.0': + dependencies: + '@changesets/config': 3.1.3 + '@changesets/get-version-range-type': 0.4.0 + '@changesets/git': 3.0.4 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + detect-indent: 6.1.0 + fs-extra: 7.0.1 + lodash.startcase: 4.4.0 + outdent: 0.5.0 + prettier: 2.8.8 + resolve-from: 5.0.0 + semver: 7.7.4 + + '@changesets/assemble-release-plan@6.0.9': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.3 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + semver: 7.7.4 + + '@changesets/changelog-git@0.2.1': + dependencies: + '@changesets/types': 6.1.0 + + '@changesets/changelog-github@0.6.0': + dependencies: + '@changesets/get-github-info': 0.8.0 + '@changesets/types': 6.1.0 + dotenv: 8.6.0 + transitivePeerDependencies: + - encoding + + '@changesets/cli@2.30.0(@types/node@24.12.0)': + dependencies: + '@changesets/apply-release-plan': 7.1.0 + '@changesets/assemble-release-plan': 6.0.9 + '@changesets/changelog-git': 0.2.1 + '@changesets/config': 3.1.3 + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.3 + '@changesets/get-release-plan': 4.0.15 + '@changesets/git': 3.0.4 + '@changesets/logger': 0.1.1 + '@changesets/pre': 2.0.2 + '@changesets/read': 0.6.7 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@changesets/write': 0.4.0 + '@inquirer/external-editor': 1.0.3(@types/node@24.12.0) + '@manypkg/get-packages': 1.1.3 + ansi-colors: 4.1.3 + enquirer: 2.4.1 + fs-extra: 7.0.1 + mri: 1.2.0 + package-manager-detector: 0.2.11 + picocolors: 1.1.1 + resolve-from: 5.0.0 + semver: 7.7.4 + spawndamnit: 3.0.1 + term-size: 2.2.1 + transitivePeerDependencies: + - '@types/node' + + '@changesets/config@3.1.3': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.3 + '@changesets/logger': 0.1.1 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + fs-extra: 7.0.1 + micromatch: 4.0.8 + + '@changesets/errors@0.2.0': + dependencies: + extendable-error: 0.1.7 + + '@changesets/get-dependents-graph@2.1.3': + dependencies: + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + picocolors: 1.1.1 + semver: 7.7.4 + + '@changesets/get-github-info@0.8.0': + dependencies: + dataloader: 1.4.0 + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + + '@changesets/get-release-plan@4.0.15': + dependencies: + '@changesets/assemble-release-plan': 6.0.9 + '@changesets/config': 3.1.3 + '@changesets/pre': 2.0.2 + '@changesets/read': 0.6.7 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + + '@changesets/get-version-range-type@0.4.0': {} + + '@changesets/git@3.0.4': + dependencies: + '@changesets/errors': 0.2.0 + '@manypkg/get-packages': 1.1.3 + is-subdir: 1.2.0 + micromatch: 4.0.8 + spawndamnit: 3.0.1 + + '@changesets/logger@0.1.1': + dependencies: + picocolors: 1.1.1 + + '@changesets/parse@0.4.3': + dependencies: + '@changesets/types': 6.1.0 + js-yaml: 4.1.1 + + '@changesets/pre@2.0.2': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + fs-extra: 7.0.1 + + '@changesets/read@0.6.7': + dependencies: + '@changesets/git': 3.0.4 + '@changesets/logger': 0.1.1 + '@changesets/parse': 0.4.3 + '@changesets/types': 6.1.0 + fs-extra: 7.0.1 + p-filter: 2.1.0 + picocolors: 1.1.1 + + '@changesets/should-skip-package@0.1.2': + dependencies: + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + + '@changesets/types@4.1.0': {} + + '@changesets/types@6.1.0': {} + + '@changesets/write@0.4.0': + dependencies: + '@changesets/types': 6.1.0 + fs-extra: 7.0.1 + human-id: 4.1.3 + prettier: 2.8.8 + + '@effect/cluster@0.58.0(@effect/platform@0.96.0(effect@3.21.0))(@effect/rpc@0.75.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/sql@0.51.0(@effect/experimental@0.60.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/workflow@0.18.0(@effect/experimental@0.60.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(@effect/rpc@0.75.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(effect@3.21.0))(effect@3.21.0)': + dependencies: + '@effect/platform': 0.96.0(effect@3.21.0) + '@effect/rpc': 0.75.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0) + '@effect/sql': 0.51.0(@effect/experimental@0.60.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0) + '@effect/workflow': 0.18.0(@effect/experimental@0.60.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(@effect/rpc@0.75.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(effect@3.21.0) + effect: 3.21.0 + kubernetes-types: 1.30.0 + + '@effect/experimental@0.60.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0)': + dependencies: + '@effect/platform': 0.96.0(effect@3.21.0) + effect: 3.21.0 + uuid: 11.1.0 + + '@effect/platform-node-shared@0.59.0(@effect/cluster@0.58.0(@effect/platform@0.96.0(effect@3.21.0))(@effect/rpc@0.75.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/sql@0.51.0(@effect/experimental@0.60.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/workflow@0.18.0(@effect/experimental@0.60.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(@effect/rpc@0.75.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(@effect/rpc@0.75.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/sql@0.51.0(@effect/experimental@0.60.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(effect@3.21.0)': + dependencies: + '@effect/cluster': 0.58.0(@effect/platform@0.96.0(effect@3.21.0))(@effect/rpc@0.75.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/sql@0.51.0(@effect/experimental@0.60.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/workflow@0.18.0(@effect/experimental@0.60.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(@effect/rpc@0.75.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(effect@3.21.0))(effect@3.21.0) + '@effect/platform': 0.96.0(effect@3.21.0) + '@effect/rpc': 0.75.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0) + '@effect/sql': 0.51.0(@effect/experimental@0.60.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0) + '@parcel/watcher': 2.5.6 + effect: 3.21.0 + multipasta: 0.2.7 + ws: 8.19.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@effect/platform-node@0.106.0(@effect/cluster@0.58.0(@effect/platform@0.96.0(effect@3.21.0))(@effect/rpc@0.75.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/sql@0.51.0(@effect/experimental@0.60.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/workflow@0.18.0(@effect/experimental@0.60.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(@effect/rpc@0.75.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(@effect/rpc@0.75.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/sql@0.51.0(@effect/experimental@0.60.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(effect@3.21.0)': + dependencies: + '@effect/cluster': 0.58.0(@effect/platform@0.96.0(effect@3.21.0))(@effect/rpc@0.75.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/sql@0.51.0(@effect/experimental@0.60.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/workflow@0.18.0(@effect/experimental@0.60.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(@effect/rpc@0.75.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(effect@3.21.0))(effect@3.21.0) + '@effect/platform': 0.96.0(effect@3.21.0) + '@effect/platform-node-shared': 0.59.0(@effect/cluster@0.58.0(@effect/platform@0.96.0(effect@3.21.0))(@effect/rpc@0.75.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/sql@0.51.0(@effect/experimental@0.60.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/workflow@0.18.0(@effect/experimental@0.60.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(@effect/rpc@0.75.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(@effect/rpc@0.75.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/sql@0.51.0(@effect/experimental@0.60.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(effect@3.21.0) + '@effect/rpc': 0.75.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0) + '@effect/sql': 0.51.0(@effect/experimental@0.60.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0) + effect: 3.21.0 + mime: 3.0.0 + undici: 7.24.5 + ws: 8.19.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@effect/platform@0.96.0(effect@3.21.0)': + dependencies: + effect: 3.21.0 + find-my-way-ts: 0.1.6 + msgpackr: 1.11.9 + multipasta: 0.2.7 + + '@effect/rpc@0.75.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0)': + dependencies: + '@effect/platform': 0.96.0(effect@3.21.0) + effect: 3.21.0 + msgpackr: 1.11.9 + + '@effect/schema@0.75.5(effect@3.21.0)': + dependencies: + effect: 3.21.0 + fast-check: 3.23.2 + + '@effect/sql@0.51.0(@effect/experimental@0.60.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0)': + dependencies: + '@effect/experimental': 0.60.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0) + '@effect/platform': 0.96.0(effect@3.21.0) + effect: 3.21.0 + uuid: 11.1.0 + + '@effect/workflow@0.18.0(@effect/experimental@0.60.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(@effect/platform@0.96.0(effect@3.21.0))(@effect/rpc@0.75.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0))(effect@3.21.0)': + dependencies: + '@effect/experimental': 0.60.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0) + '@effect/platform': 0.96.0(effect@3.21.0) + '@effect/rpc': 0.75.0(@effect/platform@0.96.0(effect@3.21.0))(effect@3.21.0) + effect: 3.21.0 + + '@emnapi/core@1.9.1': + dependencies: + '@emnapi/wasi-threads': 1.2.0 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.9.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@inquirer/external-editor@1.0.3(@types/node@24.12.0)': + dependencies: + chardet: 2.1.1 + iconv-lite: 0.7.2 + optionalDependencies: + '@types/node': 24.12.0 + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@manypkg/find-root@1.1.0': + dependencies: + '@babel/runtime': 7.29.2 + '@types/node': 12.20.55 + find-up: 4.1.0 + fs-extra: 8.1.0 + + '@manypkg/get-packages@1.1.3': + dependencies: + '@babel/runtime': 7.29.2 + '@changesets/types': 4.1.0 + '@manypkg/find-root': 1.1.0 + fs-extra: 8.1.0 + globby: 11.1.0 + read-yaml-file: 1.1.0 + + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': + optional: true + + '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3': + optional: true + + '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3': + optional: true + + '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3': + optional: true + + '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3': + optional: true + + '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3': + optional: true + + '@napi-rs/wasm-runtime@1.1.1': + dependencies: + '@emnapi/core': 1.9.1 + '@emnapi/runtime': 1.9.1 + '@tybys/wasm-util': 0.10.1 + optional: true + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.20.1 + + '@oxc-project/types@0.120.0': {} + + '@parcel/watcher-android-arm64@2.5.6': + optional: true + + '@parcel/watcher-darwin-arm64@2.5.6': + optional: true + + '@parcel/watcher-darwin-x64@2.5.6': + optional: true + + '@parcel/watcher-freebsd-x64@2.5.6': + optional: true + + '@parcel/watcher-linux-arm-glibc@2.5.6': + optional: true + + '@parcel/watcher-linux-arm-musl@2.5.6': + optional: true + + '@parcel/watcher-linux-arm64-glibc@2.5.6': + optional: true + + '@parcel/watcher-linux-arm64-musl@2.5.6': + optional: true + + '@parcel/watcher-linux-x64-glibc@2.5.6': + optional: true + + '@parcel/watcher-linux-x64-musl@2.5.6': + optional: true + + '@parcel/watcher-win32-arm64@2.5.6': + optional: true + + '@parcel/watcher-win32-ia32@2.5.6': + optional: true + + '@parcel/watcher-win32-x64@2.5.6': + optional: true + + '@parcel/watcher@2.5.6': + dependencies: + detect-libc: 2.1.2 + is-glob: 4.0.3 + node-addon-api: 7.1.1 + picomatch: 4.0.3 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.5.6 + '@parcel/watcher-darwin-arm64': 2.5.6 + '@parcel/watcher-darwin-x64': 2.5.6 + '@parcel/watcher-freebsd-x64': 2.5.6 + '@parcel/watcher-linux-arm-glibc': 2.5.6 + '@parcel/watcher-linux-arm-musl': 2.5.6 + '@parcel/watcher-linux-arm64-glibc': 2.5.6 + '@parcel/watcher-linux-arm64-musl': 2.5.6 + '@parcel/watcher-linux-x64-glibc': 2.5.6 + '@parcel/watcher-linux-x64-musl': 2.5.6 + '@parcel/watcher-win32-arm64': 2.5.6 + '@parcel/watcher-win32-ia32': 2.5.6 + '@parcel/watcher-win32-x64': 2.5.6 + + '@rolldown/binding-android-arm64@1.0.0-rc.10': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.0-rc.10': + optional: true + + '@rolldown/binding-darwin-x64@1.0.0-rc.10': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.0-rc.10': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.10': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.10': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.10': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.10': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.10': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.10': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.0-rc.10': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.10': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.0-rc.10': + dependencies: + '@napi-rs/wasm-runtime': 1.1.1 + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.10': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.10': + optional: true + + '@rolldown/pluginutils@1.0.0-rc.10': {} + + '@standard-schema/spec@1.1.0': {} + + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/deep-eql@4.0.2': {} + + '@types/estree@1.0.8': {} + + '@types/node@12.20.55': {} + + '@types/node@24.12.0': + dependencies: + undici-types: 7.16.0 + + '@vitest/expect@4.1.0': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.1.0 + '@vitest/utils': 4.1.0 + chai: 6.2.2 + tinyrainbow: 3.1.0 + + '@vitest/mocker@4.1.0(vite@8.0.1(@types/node@24.12.0))': + dependencies: + '@vitest/spy': 4.1.0 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 8.0.1(@types/node@24.12.0) + + '@vitest/pretty-format@4.1.0': + dependencies: + tinyrainbow: 3.1.0 + + '@vitest/runner@4.1.0': + dependencies: + '@vitest/utils': 4.1.0 + pathe: 2.0.3 + + '@vitest/snapshot@4.1.0': + dependencies: + '@vitest/pretty-format': 4.1.0 + '@vitest/utils': 4.1.0 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@4.1.0': {} + + '@vitest/utils@4.1.0': + dependencies: + '@vitest/pretty-format': 4.1.0 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.0 + + ansi-colors@4.1.3: {} + + ansi-regex@5.0.1: {} + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + argparse@2.0.1: {} + + array-union@2.1.0: {} + + assertion-error@2.0.1: {} + + better-path-resolve@1.0.0: + dependencies: + is-windows: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + chai@6.2.2: {} + + chardet@2.1.1: {} + + convert-source-map@2.0.0: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + dataloader@1.4.0: {} + + detect-indent@6.1.0: {} + + detect-libc@2.1.2: {} + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + dotenv@8.6.0: {} + + effect@3.21.0: + dependencies: + '@standard-schema/spec': 1.1.0 + fast-check: 3.23.2 + + enquirer@2.4.1: + dependencies: + ansi-colors: 4.1.3 + strip-ansi: 6.0.1 + + es-module-lexer@2.0.0: {} + + esprima@4.0.1: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + expect-type@1.3.0: {} + + extendable-error@0.1.7: {} + + fast-check@3.23.2: + dependencies: + pure-rand: 6.1.0 + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-my-way-ts@0.1.6: {} + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + fs-extra@7.0.1: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fs-extra@8.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fsevents@2.3.3: + optional: true + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + globby@11.1.0: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.3 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 3.0.0 + + graceful-fs@4.2.11: {} + + human-id@4.1.3: {} + + iconv-lite@0.7.2: + dependencies: + safer-buffer: 2.1.2 + + ignore@5.3.2: {} + + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + is-subdir@1.2.0: + dependencies: + better-path-resolve: 1.0.0 + + is-windows@1.0.2: {} + + isexe@2.0.0: {} + + js-yaml@3.14.2: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + jsonfile@4.0.0: + optionalDependencies: + graceful-fs: 4.2.11 + + kubernetes-types@1.30.0: {} + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + lodash.startcase@4.4.0: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime@3.0.0: {} + + mri@1.2.0: {} + + msgpackr-extract@3.0.3: + dependencies: + node-gyp-build-optional-packages: 5.2.2 + optionalDependencies: + '@msgpackr-extract/msgpackr-extract-darwin-arm64': 3.0.3 + '@msgpackr-extract/msgpackr-extract-darwin-x64': 3.0.3 + '@msgpackr-extract/msgpackr-extract-linux-arm': 3.0.3 + '@msgpackr-extract/msgpackr-extract-linux-arm64': 3.0.3 + '@msgpackr-extract/msgpackr-extract-linux-x64': 3.0.3 + '@msgpackr-extract/msgpackr-extract-win32-x64': 3.0.3 + optional: true + + msgpackr@1.11.9: + optionalDependencies: + msgpackr-extract: 3.0.3 + + multipasta@0.2.7: {} + + nanoid@3.3.11: {} + + node-addon-api@7.1.1: {} + + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + + node-gyp-build-optional-packages@5.2.2: + dependencies: + detect-libc: 2.1.2 + optional: true + + obug@2.1.1: {} + + outdent@0.5.0: {} + + p-filter@2.1.0: + dependencies: + p-map: 2.1.0 + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-map@2.1.0: {} + + p-try@2.2.0: {} + + package-manager-detector@0.2.11: + dependencies: + quansync: 0.2.11 + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + path-type@4.0.0: {} + + pathe@2.0.3: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.3: {} + + pify@4.0.1: {} + + postcss@8.5.8: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prettier@2.8.8: {} + + pure-rand@6.1.0: {} + + quansync@0.2.11: {} + + queue-microtask@1.2.3: {} + + read-yaml-file@1.1.0: + dependencies: + graceful-fs: 4.2.11 + js-yaml: 3.14.2 + pify: 4.0.1 + strip-bom: 3.0.0 + + resolve-from@5.0.0: {} + + reusify@1.1.0: {} + + rolldown@1.0.0-rc.10: + dependencies: + '@oxc-project/types': 0.120.0 + '@rolldown/pluginutils': 1.0.0-rc.10 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.0-rc.10 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.10 + '@rolldown/binding-darwin-x64': 1.0.0-rc.10 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.10 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.10 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.10 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.10 + '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.10 + '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.10 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.10 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.10 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.10 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.10 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.10 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.10 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safer-buffer@2.1.2: {} + + semver@7.7.4: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + siginfo@2.0.0: {} + + signal-exit@4.1.0: {} + + slash@3.0.0: {} + + source-map-js@1.2.1: {} + + spawndamnit@3.0.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + sprintf-js@1.0.3: {} + + stackback@0.0.2: {} + + std-env@4.0.0: {} + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-bom@3.0.0: {} + + term-size@2.2.1: {} + + tinybench@2.9.0: {} + + tinyexec@1.0.4: {} + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + tinyrainbow@3.1.0: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + tr46@0.0.3: {} + + tslib@2.8.1: + optional: true + + typescript@5.9.3: {} + + undici-types@7.16.0: {} + + undici@7.24.5: {} + + universalify@0.1.2: {} + + uuid@11.1.0: {} + + vite@8.0.1(@types/node@24.12.0): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.3 + postcss: 8.5.8 + rolldown: 1.0.0-rc.10 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 24.12.0 + fsevents: 2.3.3 + + vitest@4.1.0(@types/node@24.12.0)(vite@8.0.1(@types/node@24.12.0)): + dependencies: + '@vitest/expect': 4.1.0 + '@vitest/mocker': 4.1.0(vite@8.0.1(@types/node@24.12.0)) + '@vitest/pretty-format': 4.1.0 + '@vitest/runner': 4.1.0 + '@vitest/snapshot': 4.1.0 + '@vitest/spy': 4.1.0 + '@vitest/utils': 4.1.0 + es-module-lexer: 2.0.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.3 + std-env: 4.0.0 + tinybench: 2.9.0 + tinyexec: 1.0.4 + tinyglobby: 0.2.15 + tinyrainbow: 3.1.0 + vite: 8.0.1(@types/node@24.12.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 24.12.0 + transitivePeerDependencies: + - msw + + webidl-conversions@3.0.1: {} + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + ws@8.19.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..924b55f --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - packages/* diff --git a/src/index.mjs b/src/index.mjs deleted file mode 100644 index 4e41e98..0000000 --- a/src/index.mjs +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./args.mjs" -export * from "./run.mjs" -export * from "./template.mjs" diff --git a/src/main.mjs b/src/main.mjs deleted file mode 100755 index 50027ba..0000000 --- a/src/main.mjs +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env node -import { runCli } from "./run.mjs" - -process.exit(runCli(process.argv.slice(2))) diff --git a/src/run.mjs b/src/run.mjs deleted file mode 100644 index 50304b9..0000000 --- a/src/run.mjs +++ /dev/null @@ -1,58 +0,0 @@ -import { dirname, resolve } from "node:path" -import { mkdirSync } from "node:fs" - -import { DEFAULT_PROJECT_DIR, parseArgs } from "./args.mjs" -import { - bootstrapTemplate, - claimProject, - cloneTemplateRepo, - ensureEmptyProjectDir, - installDependencies, - resolveProjectContext -} from "./template.mjs" - -const defaultUsage = "npx create-spawn-dock --token [project-dir]" - -export const formatUsage = (invocation = defaultUsage) => `Usage: ${invocation}` - -export const runCli = (argv = process.argv.slice(2), options = {}) => { - const invocation = options.invocation ?? defaultUsage - - try { - const args = parseArgs(argv) - - if (!args.token) { - console.error(formatUsage(invocation)) - return 1 - } - - const projectDir = resolve(process.cwd(), args.projectDir ?? DEFAULT_PROJECT_DIR) - const context = resolveProjectContext(projectDir) - - ensureEmptyProjectDir(projectDir) - mkdirSync(dirname(projectDir), { recursive: true }) - cloneTemplateRepo(projectDir, args.templateRepo, args.templateBranch) - - const claim = claimProject(args.controlPlaneUrl, args.claimPath, { - token: args.token, - projectSlug: context.projectSlug, - projectName: context.projectName, - templateId: context.templateId, - localPort: 3000 - }) - - bootstrapTemplate(projectDir, claim, context) - installDependencies(projectDir) - - console.log("") - console.log(`SpawnDock project created at ${projectDir}`) - console.log(`Project: ${context.projectName}`) - console.log(`Preview URL: ${claim.previewOrigin}`) - console.log(`Run: cd "${projectDir}" && npm run dev`) - - return 0 - } catch (error) { - console.error(error instanceof Error ? error.message : String(error)) - return 1 - } -} diff --git a/src/template.mjs b/src/template.mjs deleted file mode 100644 index e181926..0000000 --- a/src/template.mjs +++ /dev/null @@ -1,287 +0,0 @@ -import { mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs" -import { join, resolve } from "node:path" -import { spawnSync } from "node:child_process" -import { fileURLToPath } from "node:url" - -import { - DEFAULT_TEMPLATE_BRANCH, - DEFAULT_TEMPLATE_REPO, - TEMPLATE_ID, - normalizeDisplayName -} from "./args.mjs" - -export const TEMPLATE_OVERLAY_DIR = resolve( - fileURLToPath(new URL("../template-nextjs-overlay", import.meta.url)) -) - -export const renderTemplate = (input, replacements) => { - let output = input - - for (const [token, value] of Object.entries(replacements)) { - output = output.split(token).join(String(value)) - } - - return output -} - -export const resolveProjectContext = (projectDir) => { - const projectSlug = projectDir.split(/[\\/]/g).filter(Boolean).at(-1) ?? projectDir - - return { - projectDir, - projectSlug, - projectName: normalizeDisplayName(projectSlug), - templateId: TEMPLATE_ID - } -} - -export const ensureEmptyProjectDir = (projectDir) => { - try { - const entries = readdirSync(projectDir) - - if (entries.length > 0) { - throw new Error(`Target directory is not empty: ${projectDir}`) - } - } catch (error) { - if (error && error.code === "ENOENT") { - return - } - - if (error instanceof Error) { - throw error - } - } -} - -export const cloneTemplateRepo = ( - projectDir, - templateRepo = DEFAULT_TEMPLATE_REPO, - templateBranch = DEFAULT_TEMPLATE_BRANCH -) => { - const cloneResult = spawnSync( - "git", - ["clone", "--depth", "1", "--branch", templateBranch, templateRepo, projectDir], - { - stdio: "inherit" - } - ) - - if (cloneResult.status !== 0) { - throw new Error(`Failed to clone template repository: ${templateRepo}`) - } -} - -export const copyOverlayTree = (sourceDir, targetDir, replacements) => { - const entries = readdirSync(sourceDir, { withFileTypes: true }) - - for (const entry of entries) { - const sourcePath = join(sourceDir, entry.name) - const targetPath = join(targetDir, entry.name) - - if (entry.isDirectory()) { - rmSync(targetPath, { force: true, recursive: true }) - mkdirSync(targetPath, { recursive: true }) - copyOverlayTree(sourcePath, targetPath, replacements) - continue - } - - const content = readFileSync(sourcePath, "utf8") - const rendered = renderTemplate(content, replacements) - - writeFileSync(targetPath, rendered, "utf8") - } -} - -export const patchPackageJson = (projectDir) => { - const packageJsonPath = join(projectDir, "package.json") - const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8")) - - packageJson.scripts = { - ...(packageJson.scripts ?? {}), - dev: "node ./spawndock/dev.mjs", - "dev:next": "node ./spawndock/next.mjs", - "dev:tunnel": "node ./spawndock/tunnel.mjs" - } - - packageJson.devDependencies = { - ...(packageJson.devDependencies ?? {}), - "@spawn-dock/dev-tunnel": "latest" - } - - writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`) -} - -export const writeRuntimeConfig = (projectDir, context, claim) => { - const previewPath = resolvePreviewPath(claim.previewOrigin) - const previewHost = resolvePreviewHost(claim.previewOrigin) - const mcpServerUrl = buildMcpServerUrl(claim.controlPlaneUrl) - const config = { - templateId: context.templateId, - projectId: claim.projectId, - projectSlug: claim.projectSlug, - projectName: context.projectName, - controlPlaneUrl: claim.controlPlaneUrl, - previewOrigin: claim.previewOrigin, - previewPath, - previewHost, - localPort: claim.localPort, - deviceSecret: claim.deviceSecret, - mcpServerUrl - } - - const env = { - SPAWNDOCK_CONTROL_PLANE_URL: claim.controlPlaneUrl, - SPAWNDOCK_PREVIEW_ORIGIN: claim.previewOrigin, - SPAWNDOCK_PREVIEW_PATH: previewPath, - SPAWNDOCK_ASSET_PREFIX: previewPath, - SPAWNDOCK_PREVIEW_HOST: previewHost, - SPAWNDOCK_SERVER_ACTIONS_ALLOWED_ORIGINS: previewHost, - SPAWNDOCK_DEVICE_SECRET: claim.deviceSecret, - SPAWNDOCK_PROJECT_ID: claim.projectId, - SPAWNDOCK_PROJECT_SLUG: claim.projectSlug, - SPAWNDOCK_ALLOWED_DEV_ORIGINS: claim.previewOrigin - } - - writeFileSync(join(projectDir, "spawndock.config.json"), `${JSON.stringify(config, null, 2)}\n`) - - writeFileSync( - join(projectDir, ".env.local"), - `${Object.entries(env) - .map(([key, value]) => `${key}=${value}`) - .join("\n")}\n` - ) - - writeFileSync( - join(projectDir, "spawndock.dev-tunnel.json"), - `${JSON.stringify( - { - controlPlane: claim.controlPlaneUrl, - projectSlug: claim.projectSlug, - deviceSecret: claim.deviceSecret, - port: claim.localPort - }, - null, - 2 - )}\n` - ) - - writeFileSync( - join(projectDir, "opencode.json"), - `${JSON.stringify( - { - $schema: "https://opencode.ai/config.json", - mcp: { - spawndock: { - type: "local", - command: ["npx", "-y", "@spawn-dock/mcp"], - enabled: true, - environment: { - MCP_SERVER_URL: mcpServerUrl - } - } - } - }, - null, - 2 - )}\n` - ) -} - -const buildMcpServerUrl = (controlPlaneUrl) => { - const url = new URL(controlPlaneUrl) - const normalizedPath = url.pathname.replace(/\/$/, "") - url.pathname = normalizedPath.length > 0 ? `${normalizedPath}/mcp/sse` : "/mcp/sse" - return url.toString() -} - -export const installDependencies = (projectDir) => { - const corepackResult = spawnSync("corepack", ["pnpm", "install"], { - cwd: projectDir, - stdio: "inherit" - }) - - if (corepackResult.status === 0) { - return - } - - const pnpmResult = spawnSync("pnpm", ["install"], { - cwd: projectDir, - stdio: "inherit" - }) - - if (pnpmResult.status !== 0) { - throw new Error("Dependency installation failed") - } -} - -export const claimProject = (controlPlaneUrl, claimPath, payload) => { - const resolvedClaimPath = claimPath ?? "/v1/bootstrap/claim" - const request = spawnSync( - "curl", - [ - "-fsS", - "-X", - "POST", - `${controlPlaneUrl.replace(/\/$/, "")}${resolvedClaimPath.startsWith("/") ? resolvedClaimPath : `/${resolvedClaimPath}`}`, - "-H", - "content-type: application/json", - "--data-binary", - JSON.stringify(payload) - ], - { - encoding: "utf8" - } - ) - - if (request.status !== 0) { - throw new Error(request.stderr?.trim() || "Failed to claim the project in the SpawnDock control plane") - } - - const response = JSON.parse(request.stdout) - const project = response.project ?? {} - const projectId = response.projectId ?? response.id ?? project.id - const projectSlug = response.projectSlug ?? response.slug ?? project.slug ?? payload.projectSlug - const resolvedControlPlaneUrl = response.controlPlaneUrl ?? controlPlaneUrl.replace(/\/$/, "") - const previewOrigin = - response.previewOrigin ?? response.launchUrl ?? response.staticAssetsBaseUrl ?? response.url - const deviceSecret = response.deviceSecret ?? response.deviceToken ?? response.deployToken ?? response.token - - if (!projectId || !projectSlug || !previewOrigin || !deviceSecret) { - throw new Error("SpawnDock control plane response is missing required bootstrap fields") - } - - return { - projectId, - projectSlug, - controlPlaneUrl: resolvedControlPlaneUrl, - previewOrigin, - deviceSecret, - localPort: response.localPort ?? payload.localPort ?? 3000 - } -} - -export const bootstrapTemplate = (projectDir, claim, context) => { - const previewHost = resolvePreviewHost(claim.previewOrigin) - const replacements = { - __SPAWNDOCK_PROJECT_ID__: claim.projectId, - __SPAWNDOCK_PROJECT_SLUG__: claim.projectSlug, - __SPAWNDOCK_PROJECT_NAME__: context.projectName, - __SPAWNDOCK_CONTROL_PLANE_URL__: claim.controlPlaneUrl, - __SPAWNDOCK_PREVIEW_ORIGIN__: claim.previewOrigin, - __SPAWNDOCK_PREVIEW_HOST__: previewHost, - __SPAWNDOCK_DEVICE_SECRET__: claim.deviceSecret - } - - copyOverlayTree(TEMPLATE_OVERLAY_DIR, projectDir, replacements) - patchPackageJson(projectDir) - writeRuntimeConfig(projectDir, context, claim) -} - -const resolvePreviewPath = (previewOrigin) => { - const url = new URL(previewOrigin) - const normalizedPath = url.pathname.replace(/\/$/, "") - - return normalizedPath.length > 0 ? normalizedPath : "" -} - -const resolvePreviewHost = (previewOrigin) => new URL(previewOrigin).host diff --git a/template-nextjs-overlay/README.md b/template-nextjs-overlay/README.md deleted file mode 100644 index bc7698b..0000000 --- a/template-nextjs-overlay/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# __SPAWNDOCK_PROJECT_NAME__ - -This project was bootstrapped from the SpawnDock TMA starter repository and -patched for SpawnDock local development. - -## Scripts - -- `npm run dev` starts Next.js and the SpawnDock tunnel client together. -- `npm run dev:next` starts only the local Next.js dev server. -- `npm run dev:tunnel` starts only the SpawnDock tunnel client. - -## Local config - -- `spawndock.config.json` contains preview/runtime values for the local app. -- `spawndock.dev-tunnel.json` contains the control plane URL, project slug, device secret, and local port for `@spawn-dock/dev-tunnel`. -- `opencode.json` wires the project to `@spawn-dock/mcp`. -- `.env.local` mirrors the runtime values needed by the local app. - -## Flow - -1. Run `npm run dev`. -2. Open the SpawnDock preview URL in Telegram. -3. Use OpenCode in this directory with the generated `opencode.json`. -4. Edit locally and refresh to see the changes. diff --git a/template-nextjs-overlay/next.config.ts b/template-nextjs-overlay/next.config.ts deleted file mode 100644 index f00cd29..0000000 --- a/template-nextjs-overlay/next.config.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { NextConfig } from "next" -import createNextIntlPlugin from "next-intl/plugin" - -const withNextIntl = createNextIntlPlugin("./src/core/i18n/i18n.ts") - -const parseAllowedOrigins = (value: string | undefined): Array => - value - ? value - .split(",") - .map((origin) => origin.trim()) - .filter(Boolean) - : [] - -const allowedDevOrigins = parseAllowedOrigins( - process.env.SPAWNDOCK_ALLOWED_DEV_ORIGINS -) -const previewPath = process.env.SPAWNDOCK_PREVIEW_PATH -const serverActionOrigins = parseAllowedOrigins( - process.env.SPAWNDOCK_SERVER_ACTIONS_ALLOWED_ORIGINS -) -const normalizedPreviewPath = - previewPath && previewPath.length > 0 ? previewPath : undefined - -const nextConfig: NextConfig = { - allowedDevOrigins, - assetPrefix: normalizedPreviewPath, - basePath: normalizedPreviewPath, - experimental: { - serverActions: { - allowedOrigins: serverActionOrigins - } - } -} - -export default withNextIntl(nextConfig) diff --git a/template-nextjs-overlay/public/locales/en.json b/template-nextjs-overlay/public/locales/en.json deleted file mode 100644 index 50b3581..0000000 --- a/template-nextjs-overlay/public/locales/en.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "i18n": { - "header": "Language", - "footer": "Switch the locale used by the template pages." - } -} diff --git a/template-nextjs-overlay/public/locales/ru.json b/template-nextjs-overlay/public/locales/ru.json deleted file mode 100644 index c4cefe4..0000000 --- a/template-nextjs-overlay/public/locales/ru.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "i18n": { - "header": "Язык", - "footer": "Переключите локаль, которую используют страницы шаблона." - } -} diff --git a/template-nextjs-overlay/public/tonconnect-manifest.json b/template-nextjs-overlay/public/tonconnect-manifest.json deleted file mode 100644 index bc0b83b..0000000 --- a/template-nextjs-overlay/public/tonconnect-manifest.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "url": "__SPAWNDOCK_PREVIEW_ORIGIN__", - "name": "__SPAWNDOCK_PROJECT_NAME__", - "iconUrl": "__SPAWNDOCK_PREVIEW_ORIGIN__/favicon.ico" -} diff --git a/template-nextjs-overlay/spawndock.config.json b/template-nextjs-overlay/spawndock.config.json deleted file mode 100644 index 16dc080..0000000 --- a/template-nextjs-overlay/spawndock.config.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "templateId": "nextjs-template", - "projectId": "__SPAWNDOCK_PROJECT_ID__", - "projectSlug": "__SPAWNDOCK_PROJECT_SLUG__", - "projectName": "__SPAWNDOCK_PROJECT_NAME__", - "controlPlaneUrl": "__SPAWNDOCK_CONTROL_PLANE_URL__", - "previewOrigin": "__SPAWNDOCK_PREVIEW_ORIGIN__", - "previewPath": "/preview/__SPAWNDOCK_PROJECT_SLUG__", - "previewHost": "__SPAWNDOCK_PREVIEW_HOST__", - "localPort": 3000, - "deviceSecret": "__SPAWNDOCK_DEVICE_SECRET__" -} diff --git a/template-nextjs-overlay/spawndock/config.mjs b/template-nextjs-overlay/spawndock/config.mjs deleted file mode 100644 index 35f95b0..0000000 --- a/template-nextjs-overlay/spawndock/config.mjs +++ /dev/null @@ -1,14 +0,0 @@ -import { readFileSync } from "node:fs" -import { resolve } from "node:path" - -export const readSpawndockConfig = (cwd = process.cwd()) => - JSON.parse(readFileSync(resolve(cwd, "spawndock.config.json"), "utf8")) - -export const resolveLocalOrigin = (config) => - `http://127.0.0.1:${config.localPort ?? 3000}` - -export const resolvePreviewOrigin = (config) => - config.previewOrigin ?? "" - -export const resolveAllowedDevOrigins = (config) => - [config.previewOrigin].filter(Boolean) diff --git a/template-nextjs-overlay/spawndock/dev.mjs b/template-nextjs-overlay/spawndock/dev.mjs deleted file mode 100644 index 03e4049..0000000 --- a/template-nextjs-overlay/spawndock/dev.mjs +++ /dev/null @@ -1,48 +0,0 @@ -import { spawn } from "node:child_process" -import { setTimeout } from "node:timers" - -const scripts = [ - ["node", ["spawndock/next.mjs"]], - ["node", ["spawndock/tunnel.mjs"]] -] - -const children = [] - -const stopChildren = (signal) => { - for (const child of children) { - if (!child.killed) { - child.kill(signal ?? "SIGTERM") - } - } -} - -process.on("SIGINT", () => { - stopChildren("SIGINT") - process.exit(0) -}) - -process.on("SIGTERM", () => { - stopChildren("SIGTERM") - process.exit(0) -}) - -for (const [command, args] of scripts) { - const child = spawn(command, args, { - cwd: process.cwd(), - env: process.env, - stdio: "inherit" - }) - - children.push(child) - - child.on("exit", (code) => { - if (typeof code === "number" && code !== 0) { - stopChildren() - process.exit(code) - } - }) -} - -setTimeout(() => { - console.log("SpawnDock dev session is ready.") -}, 0) diff --git a/template-nextjs-overlay/spawndock/next.mjs b/template-nextjs-overlay/spawndock/next.mjs deleted file mode 100644 index bd9af80..0000000 --- a/template-nextjs-overlay/spawndock/next.mjs +++ /dev/null @@ -1,76 +0,0 @@ -import { spawn } from "node:child_process" -import readline from "node:readline" - -import { - readSpawndockConfig, - resolveAllowedDevOrigins -} from "./config.mjs" - -const config = readSpawndockConfig() -const localPort = Number(config.localPort ?? 3000) -const allowedOrigins = resolveAllowedDevOrigins(config) -const previewOrigin = config.previewOrigin ?? "" - -const child = spawn( - "pnpm", - ["exec", "next", "dev", "-p", String(localPort)], - { - cwd: process.cwd(), - env: { - ...process.env, - SPAWNDOCK_ALLOWED_DEV_ORIGINS: allowedOrigins.join(","), - SPAWNDOCK_PREVIEW_PATH: config.previewPath ?? "", - SPAWNDOCK_ASSET_PREFIX: config.previewPath ?? "", - SPAWNDOCK_SERVER_ACTIONS_ALLOWED_ORIGINS: config.previewHost ?? "" - }, - stdio: ["inherit", "pipe", "pipe"] - } -) - -const exitWithChild = (code) => { - process.exit(typeof code === "number" ? code : 1) -} - -const rewriteNextLine = (line) => { - if (previewOrigin.length === 0) { - return line - } - - if (line.includes("Local:")) { - return " - Local: " + previewOrigin - } - - if (line.includes("Network:")) { - return " - Network: " + previewOrigin - } - - return line -} - -const forwardStream = (stream, writer) => { - if (!stream) { - return - } - - const interfaceHandle = readline.createInterface({ - input: stream - }) - - interfaceHandle.on("line", (line) => { - writer(rewriteNextLine(line) + "\n") - }) -} - -forwardStream(child.stdout, (chunk) => { - process.stdout.write(chunk) -}) - -forwardStream(child.stderr, (chunk) => { - process.stderr.write(chunk) -}) - -child.on("exit", exitWithChild) -child.on("error", (error) => { - console.error(error) - process.exit(1) -}) diff --git a/template-nextjs-overlay/spawndock/tunnel.mjs b/template-nextjs-overlay/spawndock/tunnel.mjs deleted file mode 100644 index 367cb36..0000000 --- a/template-nextjs-overlay/spawndock/tunnel.mjs +++ /dev/null @@ -1,16 +0,0 @@ -import { spawn } from "node:child_process" - -const child = spawn("pnpm", ["exec", "spawn-dock-tunnel", "dev"], { - cwd: process.cwd(), - env: process.env, - stdio: "inherit" -}) - -child.on("exit", (code) => { - process.exit(typeof code === "number" ? code : 1) -}) - -child.on("error", (error) => { - console.error(error) - process.exit(1) -}) diff --git a/tests/args.test.mjs b/tests/args.test.mjs deleted file mode 100644 index 5adc3ee..0000000 --- a/tests/args.test.mjs +++ /dev/null @@ -1,133 +0,0 @@ -import test from "node:test" -import assert from "node:assert/strict" -import { mkdtempSync, mkdirSync, readFileSync, writeFileSync } from "node:fs" -import { tmpdir } from "node:os" -import { join } from "node:path" - -import { normalizeDisplayName, parseArgs } from "../src/args.mjs" -import { - copyOverlayTree, - patchPackageJson, - renderTemplate, - writeRuntimeConfig -} from "../src/template.mjs" -import { formatUsage } from "../src/run.mjs" - -test("parseArgs reads token and project directory", () => { - const result = parseArgs(["--token", "abc", "my-project"]) - - assert.equal(result.token, "abc") - assert.equal(result.projectDir, "my-project") -}) - -test("parseArgs reads custom claim path", () => { - const result = parseArgs(["--token=abc", "--claim-path", "/claim", "my-project"]) - - assert.equal(result.claimPath, "/claim") - assert.equal(result.projectDir, "my-project") -}) - -test("parseArgs reads control plane URL from environment", () => { - const result = parseArgs(["--token", "abc", "my-project"], { - SPAWNDOCK_CONTROL_PLANE_URL: "https://garage-switch-bloom-pens.trycloudflare.com" - }) - - assert.equal(result.controlPlaneUrl, "https://garage-switch-bloom-pens.trycloudflare.com") -}) - -test("parseArgs reads template repo and branch overrides", () => { - const result = parseArgs( - [ - "--token", - "abc", - "--template-repo", - "https://example.com/tma.git", - "--template-branch", - "next", - "my-project" - ] - ) - - assert.equal(result.templateRepo, "https://example.com/tma.git") - assert.equal(result.templateBranch, "next") -}) - -test("normalizeDisplayName converts slug to title case", () => { - assert.equal(normalizeDisplayName("my-next-app"), "My Next App") -}) - -test("renderTemplate replaces all tokens", () => { - const rendered = renderTemplate("a __A__ b __A__", { __A__: "x" }) - - assert.equal(rendered, "a x b x") -}) - -test("patchPackageJson injects spawn dock scripts", () => { - const dir = mkdtempSync(join(tmpdir(), "spawndock-package-")) - const packageJsonPath = join(dir, "package.json") - - writeFileSync( - packageJsonPath, - JSON.stringify({ name: "demo", scripts: { build: "next build" } }, null, 2) - ) - - patchPackageJson(dir) - - const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8")) - - assert.equal(packageJson.scripts.dev, "node ./spawndock/dev.mjs") - assert.equal(packageJson.scripts["dev:next"], "node ./spawndock/next.mjs") - assert.equal(packageJson.scripts["dev:tunnel"], "node ./spawndock/tunnel.mjs") - assert.equal(packageJson.devDependencies["@spawn-dock/dev-tunnel"], "latest") - assert.equal(packageJson.scripts.build, "next build") -}) - -test("copyOverlayTree renders placeholders into target files", () => { - const sourceDir = mkdtempSync(join(tmpdir(), "spawndock-overlay-src-")) - const targetDir = mkdtempSync(join(tmpdir(), "spawndock-overlay-dst-")) - - mkdirSync(join(sourceDir, "nested"), { recursive: true }) - writeFileSync(join(sourceDir, "nested", "file.txt"), "hello __TOKEN__") - - copyOverlayTree(sourceDir, targetDir, { __TOKEN__: "world" }) - - assert.equal(readFileSync(join(targetDir, "nested", "file.txt"), "utf8"), "hello world") -}) - -test("formatUsage renders a custom invocation", () => { - assert.equal( - formatUsage("npx create-spawn-dock --token [project-dir]"), - "Usage: npx create-spawn-dock --token [project-dir]" - ) -}) - -test("writeRuntimeConfig creates dev tunnel and opencode config", () => { - const dir = mkdtempSync(join(tmpdir(), "spawndock-runtime-")) - - writeRuntimeConfig( - dir, - { - templateId: "nextjs-template", - projectDir: dir, - projectSlug: "demo-project", - projectName: "Demo Project" - }, - { - projectId: "project_123", - projectSlug: "demo-project", - controlPlaneUrl: "https://api.example.com", - previewOrigin: "https://api.example.com/preview/demo-project", - deviceSecret: "secret_123", - localPort: 3000 - } - ) - - const appConfig = JSON.parse(readFileSync(join(dir, "spawndock.config.json"), "utf8")) - const tunnelConfig = JSON.parse(readFileSync(join(dir, "spawndock.dev-tunnel.json"), "utf8")) - const opencodeConfig = JSON.parse(readFileSync(join(dir, "opencode.json"), "utf8")) - - assert.equal(appConfig.deviceSecret, "secret_123") - assert.equal(tunnelConfig.controlPlane, "https://api.example.com") - assert.equal(tunnelConfig.projectSlug, "demo-project") - assert.equal(opencodeConfig.mcp.spawndock.environment.MCP_SERVER_URL, "https://api.example.com/mcp/sse") -}) diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 0000000..d5e1e53 --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "strict": true, + "alwaysStrict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "exactOptionalPropertyTypes": true, + "noUncheckedIndexedAccess": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "allowUnusedLabels": false, + "allowUnreachableCode": false, + "verbatimModuleSyntax": true, + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "lib": ["ES2022"], + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "resolveJsonModule": true, + "isolatedModules": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "plugins": [{ "name": "@effect/language-service" }] + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..2439790 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "./tsconfig.base.json", + "include": [], + "references": [{ "path": "./packages/app" }] +}