diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d91627f..847bc6b 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -8,6 +8,7 @@ on: types: - opened - synchronize + - labeled - reopened - ready_for_review @@ -22,7 +23,10 @@ concurrency: jobs: preview: name: Publish PR preview - if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository + if: >- + github.event_name == 'pull_request' && + github.event.pull_request.head.repo.full_name == github.repository && + (github.event.action != 'labeled' || github.event.label.name == 'release:next') runs-on: ubuntu-latest timeout-minutes: 15 permissions: @@ -39,20 +43,27 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: "22.14.0" + node-version: "22.18.0" registry-url: "https://registry.npmjs.org" - name: Compute preview metadata id: preview run: | PR_NUMBER="${{ github.event.pull_request.number }}" + PUBLISH_NEXT="${{ contains(github.event.pull_request.labels.*.name, 'release:next') }}" BASE_VERSION=$(node -e "const fs=require('fs');const p=JSON.parse(fs.readFileSync('package.json','utf8'));process.stdout.write(p.version)") - PREVIEW_VERSION="${BASE_VERSION}-pr.${PR_NUMBER}.${{ github.run_number }}.${{ github.run_attempt }}" - DIST_TAG="pr${PR_NUMBER}" + if [ "$PUBLISH_NEXT" = "true" ]; then + PREVIEW_VERSION="${BASE_VERSION}-next.${PR_NUMBER}.${{ github.run_number }}.${{ github.run_attempt }}" + DIST_TAG="next" + else + PREVIEW_VERSION="${BASE_VERSION}-pr.${PR_NUMBER}.${{ github.run_number }}.${{ github.run_attempt }}" + DIST_TAG="pr${PR_NUMBER}" + fi echo "base_version=$BASE_VERSION" >> "$GITHUB_OUTPUT" echo "version=$PREVIEW_VERSION" >> "$GITHUB_OUTPUT" echo "dist_tag=$DIST_TAG" >> "$GITHUB_OUTPUT" + echo "publish_next=$PUBLISH_NEXT" >> "$GITHUB_OUTPUT" - name: Ensure npm version for trusted publishing run: | @@ -88,6 +99,9 @@ jobs: - name: Build run: bun run build + env: + CREATE_PRISMA_TELEMETRY_API_KEY: ${{ steps.preview.outputs.publish_next == 'true' && secrets.CREATE_PRISMA_TELEMETRY_API_KEY || '' }} + CREATE_PRISMA_TELEMETRY_HOST: ${{ steps.preview.outputs.publish_next == 'true' && vars.CREATE_PRISMA_TELEMETRY_HOST || '' }} - name: Publish to npm run: npm publish --access public --tag "${{ steps.preview.outputs.dist_tag }}" @@ -97,16 +111,21 @@ jobs: env: PREVIEW_VERSION: ${{ steps.preview.outputs.version }} DIST_TAG: ${{ steps.preview.outputs.dist_tag }} + PUBLISH_NEXT: ${{ steps.preview.outputs.publish_next }} RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} with: script: | const marker = ""; + const isNext = process.env.PUBLISH_NEXT === "true"; const body = [ marker, - "## PR preview published", + isNext ? "## @next preview published" : "## PR preview published", "", `- Version: \`${process.env.PREVIEW_VERSION}\``, `- Tag: \`${process.env.DIST_TAG}\``, + ...(isNext + ? ["- Trigger: PR has the `release:next` label, so this is available as `create-prisma@next`"] + : []), `- Run with Bun: \`bunx create-prisma@${process.env.DIST_TAG}\``, `- Run with npm: \`npx create-prisma@${process.env.DIST_TAG}\``, `- Run with Yarn: \`yarn dlx create-prisma@${process.env.DIST_TAG}\``, @@ -145,10 +164,17 @@ jobs: - name: Preview summary run: | - echo "## PR preview published" >> "$GITHUB_STEP_SUMMARY" + if [ "${{ steps.preview.outputs.publish_next }}" = "true" ]; then + echo "## @next preview published" >> "$GITHUB_STEP_SUMMARY" + else + echo "## PR preview published" >> "$GITHUB_STEP_SUMMARY" + fi echo "" >> "$GITHUB_STEP_SUMMARY" echo "- Version: \`${{ steps.preview.outputs.version }}\`" >> "$GITHUB_STEP_SUMMARY" echo "- Tag: \`${{ steps.preview.outputs.dist_tag }}\`" >> "$GITHUB_STEP_SUMMARY" + if [ "${{ steps.preview.outputs.publish_next }}" = "true" ]; then + echo "- Trigger: PR has the \`release:next\` label" >> "$GITHUB_STEP_SUMMARY" + fi echo "- Run with Bun: \`bunx create-prisma@${{ steps.preview.outputs.dist_tag }}\`" >> "$GITHUB_STEP_SUMMARY" echo "- Run with npm: \`npx create-prisma@${{ steps.preview.outputs.dist_tag }}\`" >> "$GITHUB_STEP_SUMMARY" echo "- Run with Yarn: \`yarn dlx create-prisma@${{ steps.preview.outputs.dist_tag }}\`" >> "$GITHUB_STEP_SUMMARY" @@ -175,7 +201,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: "22.14.0" + node-version: "22.18.0" registry-url: "https://registry.npmjs.org" - name: Extract version from commit message diff --git a/.gitignore b/.gitignore index d28d2ed..22168fa 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ node_modules dist .DS_Store prisma/generated - +prisma-next +prisma-cli diff --git a/README.md b/README.md index 0946028..2a42ae1 100644 --- a/README.md +++ b/README.md @@ -1,195 +1,71 @@ # create-prisma -Scaffold a new app with Prisma already wired up. +Create a Prisma 8 app with Prisma Composer built in. -`create-prisma` gives you a project template, Prisma setup, database scripts, and a working starting point without making you assemble everything by hand. +## Quick start -## What It Does - -- creates a new app from a supported template -- adds Prisma 7 dependencies for your database -- scaffolds `prisma/schema.prisma`, `prisma/seed.ts`, `prisma.config.ts`, and Compute deploy defaults for Compute-ready templates -- writes a Prisma client singleton in the right place for the selected template -- adds `db:generate`, `db:migrate`, and `db:seed` scripts -- creates or updates the template env file with `DATABASE_URL` -- can install dependencies and run `prisma generate` for you -- can deploy the finished app to Prisma Compute and return a live URL - -## Quick Start - -Use the package runner you already have: - -```bash -npx create-prisma@latest -``` - -```bash -pnpm dlx create-prisma@latest -``` - -```bash -yarn dlx create-prisma@latest -``` - -```bash -bunx create-prisma@latest -``` - -```bash -deno run -A npm:create-prisma@latest -``` - -If you already have it available locally: +Use your package manager: ```bash -create-prisma +npx create-prisma@next my-app +pnpm dlx create-prisma@next my-app +yarn dlx create-prisma@next my-app +bunx create-prisma@next my-app ``` -## Common Examples +The CLI initializes Prisma 8 with `prisma@next`, installs dependencies, emits the contract, and generates a deployable Composer app. PostgreSQL projects use Composer's native Prisma Postgres provider, including migrations and a typed runtime client. -Create a project interactively: +The deployment prompt is: -```bash -create-prisma +```text +Deploy to Prisma now? ``` -Create a Hono app non-interactively: +Choose no to deploy later with the generated `deploy` script. -```bash -create-prisma --name my-api --template hono --provider postgresql -``` - -Scaffold into the current directory: - -```bash -create-prisma --name . --template hono --provider postgresql -``` - -Create a monorepo with a shared Prisma package: - -```bash -create-prisma --name my-monorepo --template turborepo --provider postgresql -``` - -Use Prisma Postgres auto-provisioning: - -```bash -create-prisma --name my-app --template nest --provider postgresql --prisma-postgres -``` +When multiple Prisma workspace sessions are available, the CLI asks which workspace should receive +the deployment. For unattended usage, pass `--workspace ` or omit it to use the active +workspace. Choosing another workspace also updates the Prisma CLI's active workspace session. -Deploy a supported app to Prisma Compute: - -```bash -create-prisma --name my-api --template hono --provider postgresql --deploy -``` - -With PostgreSQL and no `--database-url`, the Compute flow asks whether to use Prisma Postgres. If accepted, or if `--prisma-postgres` is passed, it creates a Prisma Compute project, creates a `main` Prisma Postgres database on the `main` branch, writes `DATABASE_URL` to the template env file, and deploys the app with the env file configured in `prisma.compute.ts`. Pass `--no-prisma-postgres` to deploy without provisioning a database. - -## Supported Templates +## Templates +- `minimal` - `hono` - `elysia` - `nest` - `next` -- `svelte` +- `svelte` (SvelteKit) - `astro` - `nuxt` - `tanstack-start` -- `turborepo` - -Prisma Compute deployment is currently supported for: - -- `hono` -- `elysia` -- `nest` -- `next` -- `astro` -- `nuxt` -- `tanstack-start` -- `turborepo` - -## Supported Databases - -- `postgresql` -- `mysql` -- `sqlite` -- `sqlserver` -- `cockroachdb` - -## Supported Package Managers -- `npm` -- `pnpm` -- `yarn` -- `bun` -- `deno` +PostgreSQL and MongoDB are supported with PSL or TypeScript contract authoring. npm, pnpm, Yarn, and Bun are supported. -## Useful Flags +## Options -- `--name` project name or relative path -- `--template` choose the template -- `--provider` choose the database provider -- `--package-manager` choose the package manager/runtime -- `--schema-preset empty|basic` -- `--deploy` deploy supported templates to Prisma Compute -- `--yes` accept defaults and skip prompts -- `--no-install` scaffold only -- `--no-generate` skip `prisma generate` -- `--prisma-postgres` provision Prisma Postgres for PostgreSQL -- `--skills --mcp --extension` enable optional add-ons -- `--force` allow scaffolding into a non-empty directory -- `--verbose` print full command output +- positional project name or `--name` +- `--template` +- `--provider postgres|postgresql|mongo|mongodb` +- `--authoring psl|typescript` +- `--package-manager npm|pnpm|yarn|bun` +- `--deploy` / `--no-deploy` +- `--workspace ` +- `--yes` +- `--force` +- `--verbose` -## Add-ons +This branch intentionally targets Prisma 8 only. It does not generate a Prisma 7 compatibility path. -`create-prisma` can also help with a few optional extras: - -- Prisma skills for coding agents -- Prisma MCP setup -- Prisma IDE extension install - -These can be selected interactively or enabled with flags. -When Prisma Compute deploy is selected, the skills add-on recommends the `prisma-compute` skill too. - -## Deploy to Prisma Compute - -After scaffolding, `create-prisma` can deploy your app to [Prisma Compute](https://www.prisma.io/docs/compute), the serverless hosting for TypeScript apps that runs next to your Prisma Postgres database. It is offered for the templates the Prisma CLI can deploy today: `hono`, `elysia`, `nest`, `next`, `astro`, `nuxt`, `tanstack-start`, and `turborepo`. - -Accept the deploy prompt when it appears, or pass the flag: - -```bash -create-prisma --name my-api --template hono --provider postgresql --deploy -``` - -The deploy step signs you in with the Prisma CLI if you are not signed in yet. With PostgreSQL and no `--database-url`, create-prisma asks whether to use Prisma Postgres. If accepted, or if `--prisma-postgres` is passed, setup creates a Prisma Compute project, creates a `main` Prisma Postgres database on the `main` branch, writes `DATABASE_URL` to the template env file, runs the requested Prisma setup, then deploys the app with the env file configured in `prisma.compute.ts`. Pass `--no-prisma-postgres` to deploy without provisioning a database. - -A `prisma.compute.ts` file is generated with the app framework, runtime port, target, and env-file defaults. When deployment is selected, a `compute:deploy` script is added to the generated project so you can redeploy app changes later. That script runs `@prisma/cli@latest app deploy` using `prisma.compute.ts`; it does not create a new project, create a new database, run migrations, or seed data. - -The deploy prompt is skipped in `--yes` runs unless you pass `--deploy`. Browser sign-in may still need a person at the keyboard if no Prisma CLI session exists. - -## Local Development +## Development ```bash bun install +bun run test:unit +bun run typecheck bun run check bun run build -bun run start ``` -Useful repo scripts: - -- `bun run dev` -- `bun run typecheck` -- `bun run format` -- `bun run lint` -- `bun run bump` - ## Telemetry -Published builds may send anonymous usage telemetry to help improve the CLI. It does not include project names, file paths, or database URLs. - -Disable it with any of: - -- `DO_NOT_TRACK` -- `CREATE_PRISMA_DISABLE_TELEMETRY` -- `CREATE_PRISMA_TELEMETRY_DISABLED` +Published builds may send anonymous usage telemetry. It never includes project names, file paths, or database URLs. Disable it with `DO_NOT_TRACK`, `CREATE_PRISMA_DISABLE_TELEMETRY`, or `CREATE_PRISMA_TELEMETRY_DISABLED`. diff --git a/bun.lock b/bun.lock index 010f8b6..c333548 100644 --- a/bun.lock +++ b/bun.lock @@ -5,47 +5,57 @@ "": { "name": "create-prisma", "dependencies": { - "@clack/prompts": "^1.6.0", - "@orpc/server": "^1.14.6", + "@clack/prompts": "^1.7.0", + "@orpc/server": "^1.13.5", "execa": "^9.6.1", - "fs-extra": "^11.3.5", - "handlebars": "^4.7.9", - "posthog-node": "^5.38.2", - "trpc-cli": "^0.15.1", - "zod": "^4.4.3", + "fs-extra": "^11.3.3", + "handlebars": "^4.7.8", + "posthog-node": "^5.28.2", + "trpc-cli": "^0.12.4", + "zod": "^4.3.6", }, "devDependencies": { - "@types/bun": "^1.3.14", + "@prisma/dev": "0.24.7", + "@types/bun": "^1.3.9", "@types/fs-extra": "^11.0.4", - "@types/node": "^26.0.0", + "@types/node": "^25.3.0", "changelogithub": "^14.0.0", - "oxfmt": "^0.56.0", - "oxlint": "^1.71.0", - "tsdown": "^0.22.3", - "typescript": "^6.0.3", + "mongodb-memory-server": "11.1.0", + "oxfmt": "^0.37.0", + "oxlint": "^1.52.0", + "tsdown": "^0.20.3", + "typescript": "^5.9.3", }, }, }, "packages": { - "@babel/generator": ["@babel/generator@8.0.0", "", { "dependencies": { "@babel/parser": "^8.0.0", "@babel/types": "^8.0.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "@types/jsesc": "^2.5.0", "jsesc": "^3.0.2" } }, "sha512-NT9NrVwJsbSV6Y2FSstWa71EETOnzrjkL5/wX3D2mYHtKM+qvqB1DvR4D0Setb/gDBsHzRICifwEWMO8CnTF6g=="], + "@babel/generator": ["@babel/generator@8.0.0-rc.1", "", { "dependencies": { "@babel/parser": "^8.0.0-rc.1", "@babel/types": "^8.0.0-rc.1", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "@types/jsesc": "^2.5.0", "jsesc": "^3.0.2" } }, "sha512-3ypWOOiC4AYHKr8vYRVtWtWmyvcoItHtVqF8paFax+ydpmUdPsJpLBkBBs5ItmhdrwC3a0ZSqqFAdzls4ODP3w=="], - "@babel/helper-string-parser": ["@babel/helper-string-parser@8.0.0", "", {}, "sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg=="], + "@babel/helper-string-parser": ["@babel/helper-string-parser@8.0.0-rc.2", "", {}, "sha512-noLx87RwlBEMrTzncWd/FvTxoJ9+ycHNg0n8yyYydIoDsLZuxknKgWRJUqcrVkNrJ74uGyhWQzQaS3q8xfGAhQ=="], - "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@8.0.2", "", {}, "sha512-9Fr9QeyCAyi1BR1jKZ6uYQ24EIhQUx5ReHfQU7drOE+TPOb+w11/dsqLkMOT2U29OdCT71XajrOT8xDc1C7orA=="], + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@8.0.0-rc.1", "", {}, "sha512-I4YnARytXC2RzkLNVnf5qFNFMzp679qZpmtw/V3Jt2uGnWiIxyJtaukjG7R8pSx8nG2NamICpGfljQsogj+FbQ=="], - "@babel/parser": ["@babel/parser@8.0.0", "", { "dependencies": { "@babel/types": "^8.0.0" }, "bin": "./bin/babel-parser.js" }, "sha512-aLxAE+imI9bCcyaPrUDjBv3uSkWieifjLe0kuFOZF0zli0L6GCsTmsePnTr55adbIAgYz2zhN1vnFimCBUYcRQ=="], + "@babel/parser": ["@babel/parser@8.0.0-rc.1", "", { "dependencies": { "@babel/types": "^8.0.0-rc.1" }, "bin": "./bin/babel-parser.js" }, "sha512-6HyyU5l1yK/7h9Ki52i5h6mDAx4qJdiLQO4FdCyJNoB/gy3T3GGJdhQzzbZgvgZCugYBvwtQiWRt94QKedHnkA=="], - "@babel/types": ["@babel/types@8.0.0", "", { "dependencies": { "@babel/helper-string-parser": "^8.0.0", "@babel/helper-validator-identifier": "^8.0.0" } }, "sha512-K8ponJDxBwDHigkeFqaqT5wLGl4bTlwMafR8k7b5CPxr6Ww+UG9ls8Yx6Tcpboxu97eeGVEEyKcHmEyOwN1vSw=="], + "@babel/types": ["@babel/types@8.0.0-rc.1", "", { "dependencies": { "@babel/helper-string-parser": "^8.0.0-rc.1", "@babel/helper-validator-identifier": "^8.0.0-rc.1" } }, "sha512-ubmJ6TShyaD69VE9DQrlXcdkvJbmwWPB8qYj0H2kaJi29O7vJT9ajSdBd2W8CG34pwL9pYA74fi7RHC1qbLoVQ=="], - "@clack/core": ["@clack/core@1.4.2", "", { "dependencies": { "fast-wrap-ansi": "^0.2.0", "sisteransi": "^1.0.5" } }, "sha512-0Ty/1Gfm+Kb07sXcuESjyKfwEhSy4Ns1AgeEisHb/bDY5fWme0tTeTkU14T1Gmcs17YIjB/teiDe4uaCghbYqQ=="], + "@clack/core": ["@clack/core@1.4.3", "", { "dependencies": { "fast-wrap-ansi": "^0.2.0", "sisteransi": "^1.0.5" } }, "sha512-/kr3UWNtdJfxZtPgDqUOmG2pvwlmcLGheex5yiZKdwbzZJxhV+HMNR9QNmyY5cGwTNV6LrR7Jtp+KjhUAP1qBQ=="], - "@clack/prompts": ["@clack/prompts@1.6.0", "", { "dependencies": { "@clack/core": "1.4.2", "fast-string-width": "^3.0.2", "fast-wrap-ansi": "^0.2.0", "sisteransi": "^1.0.5" } }, "sha512-EYlRokl8szrP9Z25qT5aepMdBjzBvHF9ZEhzIiUBc9guz/T31EqRgvD0QSgZcpE93xiwrr+OkB4nz0BZyF6fSA=="], + "@clack/prompts": ["@clack/prompts@1.7.0", "", { "dependencies": { "@clack/core": "1.4.3", "fast-string-width": "^3.0.2", "fast-wrap-ansi": "^0.2.0", "sisteransi": "^1.0.5" } }, "sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A=="], - "@emnapi/core": ["@emnapi/core@1.11.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" } }, "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ=="], + "@electric-sql/pglite": ["@electric-sql/pglite@0.4.3", "", {}, "sha512-ichuWTgtd4mOM1G4SpyGJa5trT03lWbMypDV0fUXUCXg5hiHqVAz/bZyV68NqmkLB7WcYmj1RMJVSp8HV/v/ZQ=="], - "@emnapi/runtime": ["@emnapi/runtime@1.11.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw=="], + "@electric-sql/pglite-socket": ["@electric-sql/pglite-socket@0.1.3", "", { "peerDependencies": { "@electric-sql/pglite": "0.4.3" }, "bin": { "pglite-server": "dist/scripts/server.js" } }, "sha512-LAciWM0M1dCL8hlsxu2venbVZcdxema0BtDfpWYVqr+Y468UADw0pFWidhKw1M8sfJ8rdLT71tjMmnirf/IZRQ=="], - "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA=="], + "@electric-sql/pglite-tools": ["@electric-sql/pglite-tools@0.3.3", "", { "peerDependencies": { "@electric-sql/pglite": "0.4.3" } }, "sha512-AlzLJTRJ8+UFgK8CmxIpyIpJ0+YaFw02IiOSdYrqxwPXdSyeIShz8aa9Tq+tYFXdPwcaMp/Fc80mQZ1dkOQ/wg=="], + + "@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="], + + "@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="], + + "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], + + "@hono/node-server": ["@hono/node-server@1.19.11", "", { "peerDependencies": { "hono": "^4" } }, "sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g=="], "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], @@ -55,145 +65,151 @@ "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], - "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.5", "", { "dependencies": { "@tybys/wasm-util": "^0.10.2" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q=="], + "@mongodb-js/saslprep": ["@mongodb-js/saslprep@1.4.11", "", { "dependencies": { "sparse-bitfield": "^3.0.3" } }, "sha512-o9rAHc0IpIjuPSxRutWpE1F62x7n+4mVS4rCNHkzhIUMQcc18bb6xEq5wd2NdN0WjepIyXIppRshYI2kQDOZVA=="], - "@orpc/client": ["@orpc/client@1.14.6", "", { "dependencies": { "@orpc/shared": "1.14.6", "@orpc/standard-server": "1.14.6", "@orpc/standard-server-fetch": "1.14.6", "@orpc/standard-server-peer": "1.14.6" } }, "sha512-Y03NcTtmEJdxcqkKBkdGxqe1IHVpD9IorshG4PaTnz9dQIW+RYI8anRo7o0IlbBlzBICN+Ubo1rnw6bpkhagCQ=="], + "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" } }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="], - "@orpc/contract": ["@orpc/contract@1.14.6", "", { "dependencies": { "@orpc/client": "1.14.6", "@orpc/shared": "1.14.6", "@standard-schema/spec": "^1.1.0", "openapi-types": "^12.1.3" } }, "sha512-o4i2ciYWtALidF969S8yj/VFk7ZUmHHKaYGRVitX5K2uMaSB8lJM6TMyBKzRC5Clo99VPjCb9mcl6jMLEAgmKw=="], + "@orpc/client": ["@orpc/client@1.13.5", "", { "dependencies": { "@orpc/shared": "1.13.5", "@orpc/standard-server": "1.13.5", "@orpc/standard-server-fetch": "1.13.5", "@orpc/standard-server-peer": "1.13.5" } }, "sha512-j0VJpiWiFv9Xfan3NOoouHL07nSiHX8haxYaZzHYWSdWh+ABzwa8aRTwQSUpuCfD6i0EtYEZJAB6gVwtAnQoxQ=="], - "@orpc/interop": ["@orpc/interop@1.14.6", "", {}, "sha512-ZjNaHH9754uUkC98DHfm9HaGnniFnFRLdXXBWL2u+o1TVzEbiNX8dA5+oChxoSTUD3GiwpjLjAuTWXvrbhm4fA=="], + "@orpc/contract": ["@orpc/contract@1.13.5", "", { "dependencies": { "@orpc/client": "1.13.5", "@orpc/shared": "1.13.5", "@standard-schema/spec": "^1.1.0", "openapi-types": "^12.1.3" } }, "sha512-JeklRu2kxsRKyaPeKqA40YHsGRLjQdAuEGNCNU6VxA3v4UReh8ZsDG+WvEoHfXIOLRn2VWBzEsbE1G2MwRCGsg=="], - "@orpc/server": ["@orpc/server@1.14.6", "", { "dependencies": { "@orpc/client": "1.14.6", "@orpc/contract": "1.14.6", "@orpc/interop": "1.14.6", "@orpc/shared": "1.14.6", "@orpc/standard-server": "1.14.6", "@orpc/standard-server-aws-lambda": "1.14.6", "@orpc/standard-server-fastify": "1.14.6", "@orpc/standard-server-fetch": "1.14.6", "@orpc/standard-server-node": "1.14.6", "@orpc/standard-server-peer": "1.14.6", "cookie": "^1.1.1" }, "peerDependencies": { "crossws": ">=0.3.4", "ws": ">=8.18.1" }, "optionalPeers": ["crossws", "ws"] }, "sha512-aHn8dW2clr/fRZzMLbRsZ1Pe4AYxg7YmM3tSZSAkPjn5/3UaHnpuwWeY7LYPok23CGYUmjidTmJQjm0zm+vgoA=="], + "@orpc/interop": ["@orpc/interop@1.13.5", "", {}, "sha512-l02yMZWJ9hJ2Z0PF14UsP2Hd71jbUbNgvA5/hxzGkx9ci89cgJ3F9yv3clpwz8VElfh2Qp9jta+peKgiRV1a5A=="], - "@orpc/shared": ["@orpc/shared@1.14.6", "", { "dependencies": { "radash": "^12.1.1", "type-fest": "^5.4.4" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0" }, "optionalPeers": ["@opentelemetry/api"] }, "sha512-P2W+DdrUq18kUiF7nIw5wDOA0SR41mM/NsVKDVRsdyhdHk9V9KDuW1JRymyMl+7Wo5SDeSr1Rm/VjA5v08+PHw=="], + "@orpc/server": ["@orpc/server@1.13.5", "", { "dependencies": { "@orpc/client": "1.13.5", "@orpc/contract": "1.13.5", "@orpc/interop": "1.13.5", "@orpc/shared": "1.13.5", "@orpc/standard-server": "1.13.5", "@orpc/standard-server-aws-lambda": "1.13.5", "@orpc/standard-server-fastify": "1.13.5", "@orpc/standard-server-fetch": "1.13.5", "@orpc/standard-server-node": "1.13.5", "@orpc/standard-server-peer": "1.13.5", "cookie": "^1.1.1" }, "peerDependencies": { "crossws": ">=0.3.4", "ws": ">=8.18.1" }, "optionalPeers": ["crossws", "ws"] }, "sha512-RiSzyZ8hp3XmG6F98czJNV3BsRW/5zjUnOk1v16KIiuYk3p46bYEpzhHJT5Sxr5DOjmm4xHTV+fe0gczyyf+gA=="], - "@orpc/standard-server": ["@orpc/standard-server@1.14.6", "", { "dependencies": { "@orpc/shared": "1.14.6" } }, "sha512-75Oh4rAZb8K7P46d6v7R2JhjqjLLEo7Qs4+ABdF+f0m0uKM1oaykJWy7leqTJ+WaYm+uDbsZl/3nyWie9aeJTg=="], + "@orpc/shared": ["@orpc/shared@1.13.5", "", { "dependencies": { "radash": "^12.1.1", "type-fest": "^5.4.3" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0" }, "optionalPeers": ["@opentelemetry/api"] }, "sha512-yBFD9FqwazpbcOegEOZ0kAz7i9oNO110HX5AV5YAPGh+zxOY3RfZFXODQ5kBR1mr2nyo4ju+5ohYbJppZuWlcA=="], - "@orpc/standard-server-aws-lambda": ["@orpc/standard-server-aws-lambda@1.14.6", "", { "dependencies": { "@orpc/shared": "1.14.6", "@orpc/standard-server": "1.14.6", "@orpc/standard-server-fetch": "1.14.6", "@orpc/standard-server-node": "1.14.6" } }, "sha512-8FQX0uBQ2OKkIrF0u5qpd9EH2uqaM1n37NJSw9bvQqLnqoSfzk0xzVkP5s+c8N0Gec6M9mnrLvB7aqQSlpPukw=="], + "@orpc/standard-server": ["@orpc/standard-server@1.13.5", "", { "dependencies": { "@orpc/shared": "1.13.5" } }, "sha512-Upu82h5TlKOWlttcL+TTkIxyJEzjdKWd8Ri9ya8o1+BxYiqd/y3TQnmBQM+pfj8N1w+zI86Q3cLGB8RGtMqf5g=="], - "@orpc/standard-server-fastify": ["@orpc/standard-server-fastify@1.14.6", "", { "dependencies": { "@orpc/shared": "1.14.6", "@orpc/standard-server": "1.14.6", "@orpc/standard-server-node": "1.14.6" }, "peerDependencies": { "fastify": ">=5.6.1" }, "optionalPeers": ["fastify"] }, "sha512-cwS7jRfc+yM8bFyEFVzVcXfgYLfy96KpdPBPUlIQLpInwYvMxePpENM3rEAJ3MHOfMHx1PT5LidrlbR7Npb1Cg=="], + "@orpc/standard-server-aws-lambda": ["@orpc/standard-server-aws-lambda@1.13.5", "", { "dependencies": { "@orpc/shared": "1.13.5", "@orpc/standard-server": "1.13.5", "@orpc/standard-server-fetch": "1.13.5", "@orpc/standard-server-node": "1.13.5" } }, "sha512-fnjglw4a24ORmFxRgqrPATwOjxhjrAx7i1mDM9JYVSouRBb5X3J3kcvvOeuqiCw6Ov1X6WczykziB5cLy8aIpQ=="], - "@orpc/standard-server-fetch": ["@orpc/standard-server-fetch@1.14.6", "", { "dependencies": { "@orpc/shared": "1.14.6", "@orpc/standard-server": "1.14.6" } }, "sha512-XnwEnHaKMMBoilK0QVwgMsUvDbCXyz6CDoLgMN51v+p3VSnwjIkrMdOwbc/sj43z6T4irQDu9Zm8T1pxxh1L8w=="], + "@orpc/standard-server-fastify": ["@orpc/standard-server-fastify@1.13.5", "", { "dependencies": { "@orpc/shared": "1.13.5", "@orpc/standard-server": "1.13.5", "@orpc/standard-server-node": "1.13.5" }, "peerDependencies": { "fastify": ">=5.6.1" }, "optionalPeers": ["fastify"] }, "sha512-UxfCfwMYxZdkjYxAn+/wTeUUpdCrKdf5bHiO/BFq89jex3uVbfWWr0zbB7NVqonF2hUtBu88P6ZoGup1UCLkVQ=="], - "@orpc/standard-server-node": ["@orpc/standard-server-node@1.14.6", "", { "dependencies": { "@orpc/shared": "1.14.6", "@orpc/standard-server": "1.14.6", "@orpc/standard-server-fetch": "1.14.6" } }, "sha512-CmW/EPu1dxoppYMRmsK+F3Z22wMx74RLUtjRokXyRKu4XEX/Ja6nwD+xauQcAMiAQYkp39aCMofAW7BvA46Qcg=="], + "@orpc/standard-server-fetch": ["@orpc/standard-server-fetch@1.13.5", "", { "dependencies": { "@orpc/shared": "1.13.5", "@orpc/standard-server": "1.13.5" } }, "sha512-Z0xzVQ2rpLxjrsgUC5b4ezlAEpL4enDXx9fOJUfYouUUVnbgUkDe/uTpavKLgA/I97svWeZ5Smt6ycWuuoHoAQ=="], - "@orpc/standard-server-peer": ["@orpc/standard-server-peer@1.14.6", "", { "dependencies": { "@orpc/shared": "1.14.6", "@orpc/standard-server": "1.14.6" } }, "sha512-jwVGc5yRA5hk1F/W4yw45P2H4fbu4Tfsk62XijJBXRvtlSNKvvPAuwAd6jFv/fxnq2SH/uskgi91Ja9wgfnYDQ=="], + "@orpc/standard-server-node": ["@orpc/standard-server-node@1.13.5", "", { "dependencies": { "@orpc/shared": "1.13.5", "@orpc/standard-server": "1.13.5", "@orpc/standard-server-fetch": "1.13.5" } }, "sha512-cFyoKU6kHM2AcLd+fLdty3hohm5h1Sc0wAvXasI7PVZlx9mKxSfV1n4Ej2Una8ik1Jt62AH+o9fMLtPJ6/wvbQ=="], - "@oxc-project/types": ["@oxc-project/types@0.137.0", "", {}, "sha512-WT+Gb24i8hmvo85AIv2oEYouEXkRlKAlT9WaCa3TfLgNCN+GhrJOGZuIlMouAh38Qe4QOx26eUOVsq70qXrywA=="], + "@orpc/standard-server-peer": ["@orpc/standard-server-peer@1.13.5", "", { "dependencies": { "@orpc/shared": "1.13.5", "@orpc/standard-server": "1.13.5" } }, "sha512-pEvnaYtwXaw2Fjy0VJyvfZTma/AprSUGSJlOcnfBySo0TU3ZfsB54vhTlQCCN+WUCGjInZ75vCjIQnGj3Af3gg=="], - "@oxfmt/binding-android-arm-eabi": ["@oxfmt/binding-android-arm-eabi@0.56.0", "", { "os": "android", "cpu": "arm" }, "sha512-CSCxi7ovYojgfdPOdUb9T508HKeAdDIKeRGg7x8IZwVJrWz9gVgX7MbUnFqtQAE4QvoNo07mj2JlwnOzJw4qqA=="], + "@oxc-project/types": ["@oxc-project/types@0.112.0", "", {}, "sha512-m6RebKHIRsax2iCwVpYW2ErQwa4ywHJrE4sCK3/8JK8ZZAWOKXaRJFl/uP51gaVyyXlaS4+chU1nSCdzYf6QqQ=="], - "@oxfmt/binding-android-arm64": ["@oxfmt/binding-android-arm64@0.56.0", "", { "os": "android", "cpu": "arm64" }, "sha512-HYJFnd+PkDwf6S9ZPGzXXtjNqvRWFnnhdbWaouh4mi/SxU8wmDuzlMn3xo/wDTGnr4Q1VA7ZzOaE/D4biW0W6A=="], + "@oxfmt/binding-android-arm-eabi": ["@oxfmt/binding-android-arm-eabi@0.37.0", "", { "os": "android", "cpu": "arm" }, "sha512-2AW4VHG6mePEb1r4l6nBOVz1MwevNa0obayXd5Xce+gtP+cL/FCaoVK7JtpqCj4cEVxbLU4jijBUIWK41X2GGg=="], - "@oxfmt/binding-darwin-arm64": ["@oxfmt/binding-darwin-arm64@0.56.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-sftR/bEOr+t1gs+evwsHi/Xbq2FAPA2uU3VMr8n6ZU9PoK/IMSfnfu7+OEe/uy1+knhrFl4Wvy7Vkm3uo9mJ7g=="], + "@oxfmt/binding-android-arm64": ["@oxfmt/binding-android-arm64@0.37.0", "", { "os": "android", "cpu": "arm64" }, "sha512-fW/oGfK337wYb/qfoeqKrcv3tMv7DlsKVmHca0DZrWHLMUYftpYD9z7TYOD5VQ1Lg8D/iTzQiTneT2CAMThPxg=="], - "@oxfmt/binding-darwin-x64": ["@oxfmt/binding-darwin-x64@0.56.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-z66SdjLqa3MUPKvTp3Mbb5nSjKSbnYxJGeB+Wx987s8T5hPcIRiBMfnJ6zcPgYtQn3x5xjvdzNVkXrSeYH6ZFg=="], + "@oxfmt/binding-darwin-arm64": ["@oxfmt/binding-darwin-arm64@0.37.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-8sfuzKA8Ic43ZCC1ZMwk12rNVao9nn7K6crTvtLQy+yQVbXE1xxR4P1YTxqaLEOGJNq+sB2xyrfJywKVF9VODw=="], - "@oxfmt/binding-freebsd-x64": ["@oxfmt/binding-freebsd-x64@0.56.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-t2tkrV1vtZyaItSQ71dTi2ZVKZEI39b/LqLT12V5KMfIeXK6N32TUC1jhOXKVQmhECq9j2ZXMQV3JeT1kh9Vmg=="], + "@oxfmt/binding-darwin-x64": ["@oxfmt/binding-darwin-x64@0.37.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-X67bSfIDL1ufBY5OLxK3oG5Gj8Jvp7f2yEDVSduvolV+a0k6KJ1ZDFqG9wyTfancKVb7aZ5lTs63pAOxZYrj4A=="], - "@oxfmt/binding-linux-arm-gnueabihf": ["@oxfmt/binding-linux-arm-gnueabihf@0.56.0", "", { "os": "linux", "cpu": "arm" }, "sha512-+gCy+Tp3RHeXQ9y/QrS76lXIpZkbziTyp6hIgjB2MssCwfMph3vG/GEfkhO34Rai1vhYIaUkvv8UT1BcDorJPw=="], + "@oxfmt/binding-freebsd-x64": ["@oxfmt/binding-freebsd-x64@0.37.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-ULQ6098xUjZoZbT38qHj3Bgwq1BbglgnLOpB01Dsi79n94Dd4V0dPD4TlnSCdX33Rr/DBje4S2IpzgnAs8kknw=="], - "@oxfmt/binding-linux-arm-musleabihf": ["@oxfmt/binding-linux-arm-musleabihf@0.56.0", "", { "os": "linux", "cpu": "arm" }, "sha512-0kKkVvQ2I+FJ2sxQyUu1zJ0yWP5kcWse/yVFnGQSFCXMwSSkfEaUGu0dW774O7nyy3jrcBGap7OSc8dZmU/CdA=="], + "@oxfmt/binding-linux-arm-gnueabihf": ["@oxfmt/binding-linux-arm-gnueabihf@0.37.0", "", { "os": "linux", "cpu": "arm" }, "sha512-GsNuj91bKV8jHdRBtnCxe7vpX06IADFbyOwkScmDaoroRooBOK9NeStctE0/wE4DT6QY7qfF0YzUTGB2e5tjzQ=="], - "@oxfmt/binding-linux-arm64-gnu": ["@oxfmt/binding-linux-arm64-gnu@0.56.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-npkA2siMbyWRh+wEhi1aTAx4RirukGcGNt8V4Ch86pG+xU9aurqS1MZOnKYMu03ISwat3rB6zkQx51SsB9obNw=="], + "@oxfmt/binding-linux-arm-musleabihf": ["@oxfmt/binding-linux-arm-musleabihf@0.37.0", "", { "os": "linux", "cpu": "arm" }, "sha512-13ywNNp291Tc1nUaISUS3u2Y2O26zERJoVy1xK2uO+/1oon3EAHxMrXd0bQjopT+Ia3rTPwO6iFxW1DZratehA=="], - "@oxfmt/binding-linux-arm64-musl": ["@oxfmt/binding-linux-arm64-musl@0.56.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-UekqOjGkV4/MkqreCV9SPIB2jlR3/HbXrmhV1rVXJZ9wfDXMyCMriLtq3tHqLY4PkbVWNtfcm1kMojJ26KLSJw=="], + "@oxfmt/binding-linux-arm64-gnu": ["@oxfmt/binding-linux-arm64-gnu@0.37.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-JAYqsm6sTfZZbUp1CQfWZ+prXg9qBRSs5bO7bgLdD9SiqsDHn2+EfJXESL6uLqT/UO5FYvE16wivup0EOHit5w=="], - "@oxfmt/binding-linux-ppc64-gnu": ["@oxfmt/binding-linux-ppc64-gnu@0.56.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-XSzveSpeZMD5XJpew5lRFVtNnT04xd3rJxENXmk7wkZzN9oWzv2aFJyoNDhOtoz69BYaS/fg4SYl+CfEZRpB0Q=="], + "@oxfmt/binding-linux-arm64-musl": ["@oxfmt/binding-linux-arm64-musl@0.37.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-EZj3TurW1iLbq+7tBr++wsxwFyD+pvjMrTNRuSynDrs8J7w46cu/ZIzU/lFw7OG1/tDRDZ9nrKXxwbvIKXo2zA=="], - "@oxfmt/binding-linux-riscv64-gnu": ["@oxfmt/binding-linux-riscv64-gnu@0.56.0", "", { "os": "linux", "cpu": "none" }, "sha512-EkQ0nJa7k7HDDIVuPF7WY+k4k+bzdclLYtyIXNt7/OqVghfNiMym6YGppFBgx1XRIHW6QylxBz5OogumPjPJbQ=="], + "@oxfmt/binding-linux-ppc64-gnu": ["@oxfmt/binding-linux-ppc64-gnu@0.37.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-ELXrDe1xRj+f7VpzJO2j54izMbi+Hov+kdqusXO3T1BwVEbA5sWgZrVMqkwEsj4k6Lw/obJK1SLUeNulR1D//g=="], - "@oxfmt/binding-linux-riscv64-musl": ["@oxfmt/binding-linux-riscv64-musl@0.56.0", "", { "os": "linux", "cpu": "none" }, "sha512-dyjAGW8jKRge0ik6U/dgvQG0nVpA3iBlRskQTz5qJLvQWIrySxX5jpqzPetLBNIIZ231KA82fDdi1nLTk8ENCw=="], + "@oxfmt/binding-linux-riscv64-gnu": ["@oxfmt/binding-linux-riscv64-gnu@0.37.0", "", { "os": "linux", "cpu": "none" }, "sha512-79gMZgLD62dGmo5Xl4gaMc6NHRFj3GuxPrchHBlW54tcRSXTtb3gLh/J6Bl8nbbzSFRQGR7dkNQ8yYadXt6txQ=="], - "@oxfmt/binding-linux-s390x-gnu": ["@oxfmt/binding-linux-s390x-gnu@0.56.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-60ZGH3LtfqlW8X6vcLdSFY4lvCQYINurttYBKaALnHCDVAUCYJ1LsUgS6p1XOzVlzEDx3yNUZvDF1Lvt59zoZw=="], + "@oxfmt/binding-linux-riscv64-musl": ["@oxfmt/binding-linux-riscv64-musl@0.37.0", "", { "os": "linux", "cpu": "none" }, "sha512-QFdi9OhyWxnh975jeG490atcINXZwZb7epyNASPaT4wcodOTuDitrDgSPT8CFl8BcGOFTGZ6c3P/s8Afeg1Ngg=="], - "@oxfmt/binding-linux-x64-gnu": ["@oxfmt/binding-linux-x64-gnu@0.56.0", "", { "os": "linux", "cpu": "x64" }, "sha512-u1suj1tgJHK4ZqB7buCtdbNef2n8+d0lXTPJwLHNmtyK6p+DTpsaoDvmqhQrA56fgKYv4LuRxNtL8YooebKOew=="], + "@oxfmt/binding-linux-s390x-gnu": ["@oxfmt/binding-linux-s390x-gnu@0.37.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-qweAj7+pLFQXfe3UU7EZiOmo+/2SWjzVZjyyTDcrZAT0E92zEKJBvYpHinUAOqipfo2Xlp8GIfq0FSb5Tmqd8g=="], - "@oxfmt/binding-linux-x64-musl": ["@oxfmt/binding-linux-x64-musl@0.56.0", "", { "os": "linux", "cpu": "x64" }, "sha512-aYGLvlQHt80y+qKEtfJY/Nm27G0125Lv+qyh9SJ4Cjc6lXnXjD+ndfhqQnbV24POpMi7rNRi0jvx/0d70FRpCQ=="], + "@oxfmt/binding-linux-x64-gnu": ["@oxfmt/binding-linux-x64-gnu@0.37.0", "", { "os": "linux", "cpu": "x64" }, "sha512-Lqc/0vS20qzZLw1ThpWn1hQgRqj4rM+E7PuBzrqp+wLH5lYFqieAiontGpl2pMPvJ0QrmQYav9mslHlAB5kOSQ=="], - "@oxfmt/binding-openharmony-arm64": ["@oxfmt/binding-openharmony-arm64@0.56.0", "", { "os": "none", "cpu": "arm64" }, "sha512-H/re/gO+7ysVc+kywHNuzY3C33EN9sQcZhg0kp1ZwOZl7y998ZE5mhnBiuGR/nYI0pqLL5xQfrHVUOJ/cIJsCA=="], + "@oxfmt/binding-linux-x64-musl": ["@oxfmt/binding-linux-x64-musl@0.37.0", "", { "os": "linux", "cpu": "x64" }, "sha512-TnJm22+1cEcpYXzbcXS5Z9+9c+R0ronFdx5bG4OTdOL/wSpQQKzc2izgAXJ03QkP3tq7aAPhlhhxasvH3xgoUA=="], - "@oxfmt/binding-win32-arm64-msvc": ["@oxfmt/binding-win32-arm64-msvc@0.56.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-6qLNXfXmtAs8jXDvYMkxk6Wec5SUJoew+ZX1uOZmqaR7ks0EJFbAohuOCELDyJMWyVlxotVG8Xf8m74Bfq0O2w=="], + "@oxfmt/binding-openharmony-arm64": ["@oxfmt/binding-openharmony-arm64@0.37.0", "", { "os": "none", "cpu": "arm64" }, "sha512-YLq27qMur3hPUponvV3Zr0oHxowox71j3+nc+/oCc1O+M0zFafhd6AoAoCiRrSYRW+asWhz3/UMPh0bYpimcMw=="], - "@oxfmt/binding-win32-ia32-msvc": ["@oxfmt/binding-win32-ia32-msvc@0.56.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-UXEXuKphAe15bsob4AswNMArCw38XSmUIs3wk1s6e6MX9OWGW/IRWU95s1hZDiVg09STy1jHgyN2qkqbu1FT0w=="], + "@oxfmt/binding-win32-arm64-msvc": ["@oxfmt/binding-win32-arm64-msvc@0.37.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-0lYOsiYSODNh5RE9VqsydSUY7yMz8l+C4O2i3zpdZWEDNR6Tk949sMbakwUbtE5hViHnAq1cubr197DzKW+d6g=="], - "@oxfmt/binding-win32-x64-msvc": ["@oxfmt/binding-win32-x64-msvc@0.56.0", "", { "os": "win32", "cpu": "x64" }, "sha512-HPyNDjky+NIOuaMvHZflR+kst3YWdUOH2JUQYkf99grqZ5mEBTQM6h9iGy501Z8Xt5xMScrwHOuVCOlqDrktRw=="], + "@oxfmt/binding-win32-ia32-msvc": ["@oxfmt/binding-win32-ia32-msvc@0.37.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-KHQF8DsMTE6nqQ5uBU0sx8sQsyBK/PzJdJV65+28lJGOJO59jCS5WlGcKnGtq14a2B3Xr6LoJGrSFi19xsBs/A=="], - "@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.71.0", "", { "os": "android", "cpu": "arm" }, "sha512-ImGmd1njEg4FEJH03jhRnveEegtO3czCtfptvaHivKAZQIYATbVFBrrzbaYMYv0oJioTnxZAZVSyV+oL7W8S2g=="], + "@oxfmt/binding-win32-x64-msvc": ["@oxfmt/binding-win32-x64-msvc@0.37.0", "", { "os": "win32", "cpu": "x64" }, "sha512-tDVVCHOPbIJ+sQE1z2DdWk82ewhmgcbXlYv4xUCnkY75vM7R3VkVgO2KqgEolMRXwI5RrsAbk+ZoP9/LKdzKVg=="], - "@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.71.0", "", { "os": "android", "cpu": "arm64" }, "sha512-4A5BEexBrwY1YFF8Kiq/lp/wQPRG79G3BWIE1FuWaM5MvmpYSd+7ZySVcKkHdwo0UDzdQGddp6pD9mpctMqLnw=="], + "@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.52.0", "", { "os": "android", "cpu": "arm" }, "sha512-fW2pmR1VzFEdcvOYeSiv+R7CqffOjr9Bv5QmZaHuHJ4ZCqouaF6o48N/hJ3H1n9Zd8PCMFgJkeqUvUsVce01mw=="], - "@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.71.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-9wJA9GJulLwS2usU3CEisI/ESDO1n1z9eyTCvApMDrAkbJ1ve0mORgTMjcWWsKxkzkeZ2N/Gpra5IQE7x8tYgQ=="], + "@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.52.0", "", { "os": "android", "cpu": "arm64" }, "sha512-ptuJljIB+klNi8//qxXyGD51NLJXY9lv40Olc7l3/pEyjejWwXGvGMO0GM6f0JsjmbnDL+VkX7RVQNhByaX8WA=="], - "@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.71.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-PlLCjS06V0PeJMAJwzjrExw1sYNW9Gch3JtNlcwwZDXGlTYDuwHNN89zYH8LTXFfgkVtsYvs2nv0FqrzyuFDzg=="], + "@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.52.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5d079Uw43BHVZzOwm3uJI2PgSbsZJTpfHDq2jMOR6rRjGiEBlgasaEvAA26VBqpkO1++/59ZCKLBnEpkro3zIg=="], - "@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.71.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Lhil7bWre0ncxbUoDoxfS0JzpTz17BRQKW7iwoAUY8GJ66+WwJEfYPCFJ1P0WgVZR5/O/b3Q2pENlHOjeXLOGQ=="], + "@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.52.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-vRTjnhPEHAyfUhO9w6GM1VkxeVXFcDs+huyB5YNMw+Py+6PRYDFFrrOEr0rZYcoGtSH25ScozZV8I1UXrzaDjQ=="], - "@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.71.0", "", { "os": "linux", "cpu": "arm" }, "sha512-Oo9/L58PYD3RC0x05d2upAPLllHytTjHQGsnC06P6Ynn7jKkp5mdImQxXdJ3+FnBaKspNpGogzgVsi6g872LiA=="], + "@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.52.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-vFthhhciRAliAjoKMsvi7UkkQp/EtMNhmCRYBuKsNiTH0k4H3SFfbuWWr80Q7+uTXijfBP91KO/EeF48RggC7A=="], - "@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.71.0", "", { "os": "linux", "cpu": "arm" }, "sha512-mSHfyfgJrEbyIR29ejaeS50BdPk+GoNPlC1dckpDiUZbJAIel68sjSMdOt4WY0/gva+ECC7FNITQkxMJU+vSBw=="], + "@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.52.0", "", { "os": "linux", "cpu": "arm" }, "sha512-qX3K4mKbju54ojUa8nigVxxZAUDBGu5MGzpoXvWmiw+7hafoQKaLAoTm94EqRlv9v27p864GQBgc4g3qYtMXXA=="], - "@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.71.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-n9yY4M2tiy3aij4AqtlnspzpfdpeT5JQfK2/w2d8oyp5W0FRwOb1dIeX99nORNcxGr08iD9bH8N5XFz3I2iy8w=="], + "@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.52.0", "", { "os": "linux", "cpu": "arm" }, "sha512-x5D5/EUS9U4kndPncLB6mDfCsv7i8XcRLu0DZyTngXvyqapc96WwmyyOG2j8Dt26aE8Ykgh6AhsHp9bQtoBUAw=="], - "@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.71.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-fJZrs5sDZtTaPIOiemRQQmo82Ezy+vOGXemPc4Ok7iVVsYsFa7SlW6Z5XN819VfsqBHRm3NJ3rTdnR8+bJYJdQ=="], + "@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.52.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-2Ep1tnGLuGG7lUkKG/nilIJ0/T2rebEcATxMJ7afuhD6Z2Sc9dDcpX00IngAMyR9l6hXrvaOw9YA5HUAJVSENg=="], - "@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.71.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-cwl7VKGERIy9p+G+AvZdfy/06q0aHXaTt/mMRReC751iuNYJgqKjB7NydXSS30nBT9vtr2tunciOtrR4fD6FUA=="], + "@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.52.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-54wxvb1Pztz0GMgTLUG9HsH8uhZSL4UbG7n4PDxWIRT9TygTVYKfD6D7iasYdKg6ZpWB5Y86VMxgjSJpR/Y7bQ=="], - "@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.71.0", "", { "os": "linux", "cpu": "none" }, "sha512-eZ8ieVXvzGi8jr7+ybQGPK2STw3mldfxZlgA2738iflfB/rzA69sE6m5rDRpQaxC7dpm745Enlh1Tod0QAk9Gg=="], + "@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.52.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-A82Zks1lJyLclrj8n2tJPHOw2ieZXCaBctnCarS1BRlPQMC1Y98vWCLqgvg9ssWy5ZAja0IjUHN1cYsp53mrqA=="], - "@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.71.0", "", { "os": "linux", "cpu": "none" }, "sha512-puMDbQYe6+NXwfMusojoA7CXGn2b3utukmd23PQqc1E3XhVCwyZ+FueSMzDYeNgDV2dUfIVXAAKZBcFDeCL6sA=="], + "@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.52.0", "", { "os": "linux", "cpu": "none" }, "sha512-ci89Ou+u9vnA0r4eQqGm/KPEkpea+QEtZCLKkrOAD/K5ZBwjS8ToID6aMgsDbIOJUNBGufsmX0iCC7EWrNKQFA=="], - "@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.71.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-4NJLxBs1ujISCt3L/1FcywLs73PWtJuw+piD6feK2V6h6OS6P7xu9/sWt1DTRLibe6QCzmfZzmM/2HPORoV/Lg=="], + "@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.52.0", "", { "os": "linux", "cpu": "none" }, "sha512-3/+DVDWajFSu69TaYnKkoUgMEcHR3puO8TcBu3fPCKRhbLjgwDiYIVRdvQX0QaSjkNPJARmpYq7vlPHWNo2cUA=="], - "@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.71.0", "", { "os": "linux", "cpu": "x64" }, "sha512-cFDaiR8L3430qp88tfZnvFlt3KotFhR/DlbIL0nHOMMYiG/9Wy4l+6f7t8G8pTa9bd8Lt8+M0y/qjRQ/xcB74g=="], + "@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.52.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-BU7CbceOh00NDmY1IYr72qZoj4sJVHB9DCL2tIq2vyNllNJIpZWTxqlzdqmC4FViXWMy8kZNkOa+SdauH+EcoQ=="], - "@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.71.0", "", { "os": "linux", "cpu": "x64" }, "sha512-orfixdt76KlpNly9z0PkWBBNfwjKz+JFVLP/7wnVchlKNU9Dpt9InU/ZggeSej6fC7qwHmHNOGlhLnQXcYoGuA=="], + "@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.52.0", "", { "os": "linux", "cpu": "x64" }, "sha512-JUVZ6TKYl1yArS3xGsNLQlZxgVpjNKtZFja6VxSTDy2ToN7H58PiDRcxWoN2XoIcWlHSvK7pkIPFNOyzdEJ23A=="], - "@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.71.0", "", { "os": "none", "cpu": "arm64" }, "sha512-9emQu2lAp6yhPB3XuI+++vR+l/o6JR1X+EpxwcumPdQXBWXEPAsquPGL7l158EqU8SebQMXTUa/S5zN98juyHw=="], + "@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.52.0", "", { "os": "linux", "cpu": "x64" }, "sha512-IatLKG6UUbIbTBjBZ9SIAYp4SIvOpYIXPXn9cMLqWxh9HrHsu0fLNL+VQ67y4vdlIleYLeuIHkAp3M6saIN1RQ=="], - "@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.71.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-bd5kI8spYwTm3BILDtGhi73zoup5dw8MlPQNT8YB3BD5UIsjNe3K9/4ctrzQMX4SZMoK5HgzVLkLJzacEXB7fA=="], + "@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.52.0", "", { "os": "none", "cpu": "arm64" }, "sha512-CWgJ6FepHryuc/lgQWStFf3lcvEkbFLSa9zqO0D0QLVfrdg43I4XItKpL/bnfm4n7obzwgG8j8sBggdoxJQKfw=="], - "@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.71.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-W4HvOHGzVLHcrmFu+bMrJlho+/yrlX5ZNdJZqGe8MEldkQG+RHYhxxad9P4jvWAYFmIqUA5i9DQ8QsJqSU9GIw=="], + "@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.52.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-EuNAbPpctu8jYMZnvYh53Xw3YVY2nIi9bQlyMjY0eKiJxDv8ikHrAfcVcwTQW9xa5tp0eiMkmW7iHPP5CYUC9Q=="], - "@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.71.0", "", { "os": "win32", "cpu": "x64" }, "sha512-D2kyEIPHk/G/wiZLnwTVC/sVst+T/lKldVOjAFpgTIBUAOlry72e5OiapDbDBF4LfJLkN5ypJb/8Eu6yJzkveQ=="], + "@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.52.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-wu3fquQttzSXwyy8DfdOG3Kyb17yAbRhwPlly7NHSXkrffAEAmZ6+o38tCNgsReGLugbn/wbq4uS4nEQubCq+A=="], - "@posthog/core": ["@posthog/core@1.35.4", "", { "dependencies": { "@posthog/types": "^1.390.2" } }, "sha512-DowOjN83tGtg4NPv0tmExjXiIWapHDDTv0ZZHg70XBjH5o/AB3DkMVMvj5ODIi1Y5bw7eMETidGvRwWH0/g3wA=="], + "@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.52.0", "", { "os": "win32", "cpu": "x64" }, "sha512-wikx9I9J9/lPOZlrCCNgm8YjWkia8NZfhWd1TTvZTMguyChbw/oA2VEM6Fzx+kkpA+1qu5Mo7nrLdOXEJavw8g=="], - "@posthog/types": ["@posthog/types@1.390.2", "", {}, "sha512-WcfKz2GNn2vfDX8vXmJYbKxegPxVWHuDQ/pHdAn0HoZDXDFnEp/+x3qBQA+fEvtbPjjtjgAt2wIgJMlM7asx7g=="], + "@posthog/core": ["@posthog/core@1.23.4", "", { "dependencies": { "cross-spawn": "^7.0.6" } }, "sha512-gSM1gnIuw5UOBUOTz0IhCTH8jOHoFr5rzSDb5m7fn9ofLHvz3boZT1L1f+bcuk+mvzNJfrJ3ByVQGKmUQnKQ8g=="], - "@quansync/fs": ["@quansync/fs@1.0.0", "", { "dependencies": { "quansync": "^1.0.0" } }, "sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ=="], + "@prisma/debug": ["@prisma/debug@7.2.0", "", {}, "sha512-YSGTiSlBAVJPzX4ONZmMotL+ozJwQjRmZweQNIq/ER0tQJKJynNkRB3kyvt37eOfsbMCXk3gnLF6J9OJ4QWftw=="], - "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.1.2", "", { "os": "android", "cpu": "arm64" }, "sha512-2cZ+7xRS+DBcuJBJKnfzsbleumJhBqSlJVpuzHC0nTqfd3QQ7Vx2/x5YR/D7cBamKSeWplwo82Fn9lqYUDEMfA=="], + "@prisma/dev": ["@prisma/dev@0.24.7", "", { "dependencies": { "@electric-sql/pglite": "0.4.3", "@electric-sql/pglite-socket": "0.1.3", "@electric-sql/pglite-tools": "0.3.3", "@hono/node-server": "1.19.11", "@prisma/get-platform": "7.2.0", "@prisma/query-plan-executor": "7.2.0", "@prisma/streams-local": "0.1.5", "foreground-child": "3.3.1", "get-port-please": "3.2.0", "hono": "^4.12.8", "http-status-codes": "2.3.0", "pathe": "2.0.3", "proper-lockfile": "4.1.2", "remeda": "2.33.4", "std-env": "3.10.0", "valibot": "1.2.0", "zeptomatch": "2.1.0" } }, "sha512-gBukr0R+F65hWrhOfMCjYm1aCl3MqU+eFYxggFnxETNjFS5WRj+Mo9ureSH4SfAw/qM9RGTNfUSeiJK1obot1A=="], - "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.1.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RkPMJnygxsgOYdkfqgpwY0/Fzm8d0VQe6HGU2/B00Xa9eqdLbrII+DOKAodbJAn3ZL1AJxGHkZRPYazgGY6Ljw=="], + "@prisma/get-platform": ["@prisma/get-platform@7.2.0", "", { "dependencies": { "@prisma/debug": "7.2.0" } }, "sha512-k1V0l0Td1732EHpAfi2eySTezyllok9dXb6UQanajkJQzPUGi3vO2z7jdkz67SypFTdmbnyGYxvEvYZdZsMAVA=="], - "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.1.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-Uiczh6vFhwyfd7WNe7Q7mCA4KxAiLdz7jPE/WGizfRpIieoyFuNVMmM8HqZ9HwudTkY6/AeMQwlNJ9NJijguWw=="], + "@prisma/query-plan-executor": ["@prisma/query-plan-executor@7.2.0", "", {}, "sha512-EOZmNzcV8uJ0mae3DhTsiHgoNCuu1J9mULQpGCh62zN3PxPTd+qI9tJvk5jOst8WHKQNwJWR3b39t0XvfBB0WQ=="], - "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.1.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-+TpdtTRgHiJFjCVFbw311SuLk3KfytPOQQn+VlAEv+gBxYPtL7E6JS9e/tk+8CwxhIZvemJKo4rTKgfWNsKkkA=="], + "@prisma/streams-local": ["@prisma/streams-local@0.1.5", "", { "dependencies": { "ajv": "^8.12.0", "better-result": "^2.7.0", "env-paths": "^3.0.0", "proper-lockfile": "^4.1.2" } }, "sha512-cassjQ6a18P4onZOK5dBIczk4xc6g6nJAyraOr+rdckR3SWeZfN7fCFERwcN3/XYZeiFH+XLx8FH+bGYbm4hxQ=="], - "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.1.2", "", { "os": "linux", "cpu": "arm" }, "sha512-4lv1/tkmi7ueIVHnyreaOeUpiZP26BH9rRy6hoYfR9310A2B9nUEVRDvBx69vx64Nr3eTPPRkyciqJJs+j9Jmw=="], + "@quansync/fs": ["@quansync/fs@1.0.0", "", { "dependencies": { "quansync": "^1.0.0" } }, "sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ=="], - "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.1.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-gBSUVO0eaWgw1JMjK3gB8BMlX2Mk148s2lTiVT3e9vjVxbl7UDfMWWY8CfIaaqiXuM9fVTMxIpUz6CAo/B6Vlw=="], + "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-rc.3", "", { "os": "android", "cpu": "arm64" }, "sha512-0T1k9FinuBZ/t7rZ8jN6OpUKPnUjNdYHoj/cESWrQ3ZraAJ4OMm6z7QjSfCxqj8mOp9kTKc1zHK3kGz5vMu+nQ=="], - "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.1.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-LjQP/iZLBu8o8PjIfk4x3At0/mT6h282pvz8Z5LAyhGbu/kDezyO7ea62rF5uoqmgnIYqbN/MqJ3Si3Aymi7xQ=="], + "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.0-rc.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-JWWLzvcmc/3pe7qdJqPpuPk91SoE/N+f3PcWx/6ZwuyDVyungAEJPvKm/eEldiDdwTmaEzWfIR+HORxYWrCi1A=="], - "@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.1.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-X/7bVLWelEsbyWDUSXt7zVsTniLLPIY2n1rH58qr78l9i7MNbbxBWD8gI2vRfBWf4NUXJCUuQnfZDsp32LqsfQ=="], + "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.0-rc.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-MTakBxfx3tde5WSmbHxuqlDsIW0EzQym+PJYGF4P6lG2NmKzi128OGynoFUqoD5ryCySEY85dug4v+LWGBElIw=="], - "@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.1.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-gb6dYKW/1KDorGXyy48glEBJs/sxVSC5pcVrox/pFGV4mvwSFeg2sK5L2tRkVsVlh7kueqOgg4GEcuipJcGuKg=="], + "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.0-rc.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-jje3oopyOLs7IwfvXoS6Lxnmie5JJO7vW29fdGFu5YGY1EDbVDhD+P9vDihqS5X6fFiqL3ZQZCMBg6jyHkSVww=="], - "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.1.2", "", { "os": "linux", "cpu": "x64" }, "sha512-JY4w85pU3iAiJVMh5nuk4/Mh9GjMsupe8MrIN53rwxAZW64GKrWeJBuN6SxQg9QTU5uB1cxyhDzW8jqRn1EABw=="], + "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.3", "", { "os": "linux", "cpu": "arm" }, "sha512-A0n8P3hdLAaqzSFrQoA42p23ZKBYQOw+8EH5r15Sa9X1kD9/JXe0YT2gph2QTWvdr0CVK2BOXiK6ENfy6DXOag=="], - "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.1.2", "", { "os": "linux", "cpu": "x64" }, "sha512-xvpA7o5KCYLB0Rwscmuylb1/zHHSUx4g4xilm4prC5jP76pEUlzBmMbgpbh7bVDbId4NcfT96gN5i6mE6UDaiw=="], + "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.0-rc.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-kWXkoxxarYISBJ4bLNf5vFkEbb4JvccOwxWDxuK9yee8lg5XA7OpvlTptfRuwEvYcOZf+7VS69Uenpmpyo5Bjw=="], - "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.1.2", "", { "os": "none", "cpu": "arm64" }, "sha512-p/ts6KBLjuk49Bp21XH77poQGt02iNz7ChgHep7tudPOaLinR/De/RHdxF8w8Yj4r/bF/bqXwH6PZrB2sA+Nvw=="], + "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.0-rc.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-Z03/wrqau9Bicfgb3Dbs6SYTHliELk2PM2LpG2nFd+cGupTMF5kanLEcj2vuuJLLhptNyS61rtk7SOZ+lPsTUA=="], - "@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.1.2", "", { "dependencies": { "@emnapi/core": "1.11.1", "@emnapi/runtime": "1.11.1", "@napi-rs/wasm-runtime": "^1.1.5" }, "cpu": "none" }, "sha512-VMu/wmrZ9hJzYlRhbw7jK5PODlugyKZ5mOdX78+lS8OvuFkWNQdz1pFLrI2p3P0pjXOmUZ7B48o5VnMH9QOGtg=="], + "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.0-rc.3", "", { "os": "linux", "cpu": "x64" }, "sha512-iSXXZsQp08CSilff/DCTFZHSVEpEwdicV3W8idHyrByrcsRDVh9sGC3sev6d8BygSGj3vt8GvUKBPCoyMA4tgQ=="], - "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.1.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-xtUJqs8qEkuSviS0n1tsohaPuz3a1SPhZywOji4Oo+sgrJs8daEDMZ0QtqL0OS7dx8PoVpg2J/ZZycPY5I2+Zg=="], + "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.0-rc.3", "", { "os": "linux", "cpu": "x64" }, "sha512-qaj+MFudtdCv9xZo9znFvkgoajLdc+vwf0Kz5N44g+LU5XMe+IsACgn3UG7uTRlCCvhMAGXm1XlpEA5bZBrOcw=="], - "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.1.2", "", { "os": "win32", "cpu": "x64" }, "sha512-85YiLQqjUKgSO/Zjnf9e0XIn5Ymrh1fLDWBeAkZqpuBR/3R8TpfoHXuyblqyQrftSSgWO9qpcHN8mkyKsLraoA=="], + "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.0-rc.3", "", { "os": "none", "cpu": "arm64" }, "sha512-U662UnMETyjT65gFmG9ma+XziENrs7BBnENi/27swZPYagubfHRirXHG2oMl+pEax2WvO7Kb9gHZmMakpYqBHQ=="], - "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.1", "", {}, "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw=="], + "@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.0-rc.3", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.1.1" }, "cpu": "none" }, "sha512-gekrQ3Q2HiC1T5njGyuUJoGpK/l6B/TNXKed3fZXNf9YRTJn3L5MOZsFBn4bN2+UX+8+7hgdlTcEsexX988G4g=="], + + "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.0-rc.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-85y5JifyMgs8m5K2XzR/VDsapKbiFiohl7s5lEj7nmNGO0pkTXE7q6TQScei96BNAsoK7JC3pA7ukA8WRHVJpg=="], + + "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.0-rc.3", "", { "os": "win32", "cpu": "x64" }, "sha512-a4VUQZH7LxGbUJ3qJ/TzQG8HxdHvf+jOnqf7B7oFx1TEBm+j2KNL2zr5SQ7wHkNAcaPevF6gf9tQnVBnC4mD+A=="], + + "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.3", "", {}, "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q=="], "@sec-ant/readable-stream": ["@sec-ant/readable-stream@0.4.1", "", {}, "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg=="], @@ -201,9 +217,9 @@ "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], - "@tybys/wasm-util": ["@tybys/wasm-util@0.10.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg=="], + "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], - "@types/bun": ["@types/bun@1.3.14", "", { "dependencies": { "bun-types": "1.3.14" } }, "sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw=="], + "@types/bun": ["@types/bun@1.3.9", "", { "dependencies": { "bun-types": "1.3.9" } }, "sha512-KQ571yULOdWJiMH+RIWIOZ7B2RXQGpL1YQrBtLIV3FqDcCu6FsbFUBwhdKUlCKUpS3PJDsHlJ1QKlpxoVR+xtw=="], "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], @@ -213,15 +229,41 @@ "@types/jsonfile": ["@types/jsonfile@6.1.4", "", { "dependencies": { "@types/node": "*" } }, "sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ=="], - "@types/node": ["@types/node@26.0.0", "", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-vf2YFi1iY9lHGwNJMs01biZFbKJkrZR1T6/MlzjhJLPdntOHLhTrDSnSVcdtvjihi4VQNlrFRIxLsDBlQpAipA=="], + "@types/node": ["@types/node@25.3.0", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A=="], + + "@types/webidl-conversions": ["@types/webidl-conversions@7.0.3", "", {}, "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA=="], + + "@types/whatwg-url": ["@types/whatwg-url@13.0.0", "", { "dependencies": { "@types/webidl-conversions": "*" } }, "sha512-N8WXpbE6Wgri7KUSvrmQcqrMllKZ9uxkYWMt+mCSGwNc0Hsw9VQTW7ApqI4XNrx6/SaM2QQJCzMPDEXE058s+Q=="], "acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="], + "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], + + "ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="], + "ansis": ["ansis@4.2.0", "", {}, "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig=="], "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], - "ast-kit": ["ast-kit@3.0.0", "", { "dependencies": { "@babel/parser": "^8.0.0", "estree-walker": "^3.0.3", "pathe": "^2.0.3" } }, "sha512-8OG92q3R35qjC/4i6BLBMg8IB+fClWu/1PEwg2Z9Rn+BuNaiEgJzpzn+pxWOdHJWDCAwu2JP0wCDTozAM4QirQ=="], + "ast-kit": ["ast-kit@3.0.0-beta.1", "", { "dependencies": { "@babel/parser": "^8.0.0-beta.4", "estree-walker": "^3.0.3", "pathe": "^2.0.3" } }, "sha512-trmleAnZ2PxN/loHWVhhx1qeOHSRXq4TDsBBxq3GqeJitfk3+jTQ+v/C1km/KYq9M7wKqCewMh+/NAvVH7m+bw=="], + + "async-mutex": ["async-mutex@0.5.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA=="], + + "b4a": ["b4a@1.8.1", "", { "peerDependencies": { "react-native-b4a": "*" }, "optionalPeers": ["react-native-b4a"] }, "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw=="], + + "bare-events": ["bare-events@2.8.3", "", { "peerDependencies": { "bare-abort-controller": "*" }, "optionalPeers": ["bare-abort-controller"] }, "sha512-HdUm8EMQBLaJvGUdidNNbqpA1kYkwNcb+MYxkxCLAPJGQzlv9J0C24h8V65Z4c5GLd/JEALDvpFCQgpLJqc0zw=="], + + "bare-fs": ["bare-fs@4.7.1", "", { "dependencies": { "bare-events": "^2.5.4", "bare-path": "^3.0.0", "bare-stream": "^2.6.4", "bare-url": "^2.2.2", "fast-fifo": "^1.3.2" }, "peerDependencies": { "bare-buffer": "*" }, "optionalPeers": ["bare-buffer"] }, "sha512-WDRsyVN52eAx/lBamKD6uyw8H4228h/x0sGGGegOamM2cd7Pag88GfMQalobXI+HaEUxpCkbKQUDOQqt9wawRw=="], + + "bare-os": ["bare-os@3.9.1", "", {}, "sha512-6M5XjcnsygQNPMCMPXSK379xrJFiZ/AEMNBmFEmQW8d/789VQATvriyi5r0HYTL9TkQ26rn3kgdTG3aisbrXkQ=="], + + "bare-path": ["bare-path@3.0.0", "", { "dependencies": { "bare-os": "^3.0.1" } }, "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw=="], + + "bare-stream": ["bare-stream@2.13.1", "", { "dependencies": { "streamx": "^2.25.0", "teex": "^1.0.1" }, "peerDependencies": { "bare-abort-controller": "*", "bare-buffer": "*", "bare-events": "*" }, "optionalPeers": ["bare-abort-controller", "bare-buffer", "bare-events"] }, "sha512-Vp0cnjYyrEC4whYTymQ+YZi6pBpfiICZO3cfRG8sy67ZNWe951urv1x4eW1BKNngw3U+3fPYb5JQvHbCtxH7Ow=="], + + "bare-url": ["bare-url@2.4.3", "", { "dependencies": { "bare-path": "^3.0.0" } }, "sha512-Kccpc7ACfXaxfeInfqKcZtW4pT5YBn1mesc4sCsun6sRwtbJ4h+sNOaksUpYEJUKfN65YWC6Bw2OJEFiKxq8nQ=="], + + "better-result": ["better-result@2.9.2", "", {}, "sha512-WIFoBPCdnTOdk9inkE1ZRvCZ4P0CpSkAiLlchC65N7n9DcjZ3NhqkBOlafzpOVnO8ixyi37kicmSJ3ENhPZl7Q=="], "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], @@ -229,7 +271,11 @@ "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], - "bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="], + "bson": ["bson@7.2.0", "", {}, "sha512-YCEo7KjMlbNlyHhz7zAZNDpIpQbd+wOEHJYezv0nMYTn4x31eIUM2yomNNubclAt63dObUzKHWsBLJ9QcZNSnQ=="], + + "buffer-crc32": ["buffer-crc32@0.2.13", "", {}, "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ=="], + + "bun-types": ["bun-types@1.3.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-+UBWWOakIP4Tswh0Bt0QD0alpTY8cb5hvgiYeWCMet9YukHbzuruIEeXC2D7nMJPB12kbh8C7XJykSexEqGKJg=="], "bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="], @@ -237,6 +283,8 @@ "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="], + "camelcase": ["camelcase@6.3.0", "", {}, "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="], + "changelogen": ["changelogen@0.5.7", "", { "dependencies": { "c12": "^1.11.2", "colorette": "^2.0.20", "consola": "^3.2.3", "convert-gitmoji": "^0.1.5", "mri": "^1.2.0", "node-fetch-native": "^1.6.4", "ofetch": "^1.3.4", "open": "^10.1.0", "pathe": "^1.1.2", "pkg-types": "^1.2.0", "scule": "^1.3.0", "semver": "^7.6.3", "std-env": "^3.7.0", "yaml": "^2.5.1" }, "bin": { "changelogen": "dist/cli.mjs" } }, "sha512-cTZXBcJMl3pudE40WENOakXkcVtrbBpbkmSkM20NdRiUqa4+VYRdXdEsgQ0BNQ6JBE2YymTNWtPKVF7UCTN5+g=="], "changelogithub": ["changelogithub@14.0.0", "", { "dependencies": { "ansis": "^4.2.0", "c12": "^3.3.2", "cac": "^6.7.14", "changelogen": "0.5.7", "convert-gitmoji": "^0.1.5", "execa": "^9.6.0", "ofetch": "^1.5.1", "semver": "^7.7.3", "tinyglobby": "^0.2.15" }, "bin": { "changelogithub": "cli.mjs" } }, "sha512-VBuDqqU2si6tNjraFIuUEIVP++y77w+jt5CMnLCXjdP6OEBWUcbNYgIPq+aKQH4Yp2KkGKAjqP8dDmJutICk6g=="], @@ -251,6 +299,8 @@ "commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="], + "commondir": ["commondir@1.0.1", "", {}, "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg=="], + "confbox": ["confbox@0.2.4", "", {}, "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ=="], "consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], @@ -261,32 +311,44 @@ "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + "default-browser": ["default-browser@5.5.0", "", { "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" } }, "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw=="], "default-browser-id": ["default-browser-id@5.0.1", "", {}, "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q=="], "define-lazy-prop": ["define-lazy-prop@3.0.0", "", {}, "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg=="], - "defu": ["defu@6.1.7", "", {}, "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ=="], + "defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="], "destr": ["destr@2.0.5", "", {}, "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA=="], "dotenv": ["dotenv@17.3.1", "", {}, "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA=="], - "dts-resolver": ["dts-resolver@3.0.0", "", { "peerDependencies": { "oxc-resolver": ">=11.0.0" }, "optionalPeers": ["oxc-resolver"] }, "sha512-1T1f+z+4tl9XD+m+0HBgWoL/nm0bOIffyWaUuUSBlFg/86IWvfx+wjNaO/ybU0AJzG9/Mi5hBUgGV6zCmWEN7Q=="], + "dts-resolver": ["dts-resolver@2.1.3", "", { "peerDependencies": { "oxc-resolver": ">=11.0.0" }, "optionalPeers": ["oxc-resolver"] }, "sha512-bihc7jPC90VrosXNzK0LTE2cuLP6jr0Ro8jk+kMugHReJVLIpHz/xadeq3MhuwyO4TD4OA3L1Q8pBBFRc08Tsw=="], + + "empathic": ["empathic@2.0.0", "", {}, "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA=="], - "empathic": ["empathic@2.0.1", "", {}, "sha512-YGRs8knHhKHVShLkFET/rWAU8kmHbOV5LwN938RHI0pljAJ1Gf6SzXsSmRaEzcXTtOOmVqJ5+WtQPL5uigY50Q=="], + "env-paths": ["env-paths@3.0.0", "", {}, "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A=="], "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], + "events-universal": ["events-universal@1.0.1", "", { "dependencies": { "bare-events": "^2.7.0" } }, "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw=="], + "execa": ["execa@9.6.1", "", { "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "cross-spawn": "^7.0.6", "figures": "^6.1.0", "get-stream": "^9.0.0", "human-signals": "^8.0.1", "is-plain-obj": "^4.1.0", "is-stream": "^4.0.1", "npm-run-path": "^6.0.0", "pretty-ms": "^9.2.0", "signal-exit": "^4.1.0", "strip-final-newline": "^4.0.0", "yoctocolors": "^2.1.1" } }, "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA=="], "exsolve": ["exsolve@1.0.8", "", {}, "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA=="], + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + + "fast-fifo": ["fast-fifo@1.3.2", "", {}, "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ=="], + "fast-string-truncated-width": ["fast-string-truncated-width@3.0.3", "", {}, "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g=="], "fast-string-width": ["fast-string-width@3.0.2", "", { "dependencies": { "fast-string-truncated-width": "^3.0.2" } }, "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg=="], + "fast-uri": ["fast-uri@3.1.2", "", {}, "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ=="], + "fast-wrap-ansi": ["fast-wrap-ansi@0.2.2", "", { "dependencies": { "fast-string-width": "^3.0.2" } }, "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q=="], "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], @@ -295,15 +357,25 @@ "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], - "fs-extra": ["fs-extra@11.3.5", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg=="], + "find-cache-dir": ["find-cache-dir@3.3.2", "", { "dependencies": { "commondir": "^1.0.1", "make-dir": "^3.0.2", "pkg-dir": "^4.1.0" } }, "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig=="], + + "find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], + + "follow-redirects": ["follow-redirects@1.16.0", "", {}, "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw=="], + + "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], + + "fs-extra": ["fs-extra@11.3.3", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg=="], "fs-minipass": ["fs-minipass@2.1.0", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg=="], "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + "get-port-please": ["get-port-please@3.2.0", "", {}, "sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A=="], + "get-stream": ["get-stream@9.0.1", "", { "dependencies": { "@sec-ant/readable-stream": "^0.4.1", "is-stream": "^4.0.1" } }, "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA=="], - "get-tsconfig": ["get-tsconfig@5.0.0-beta.5", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-/6gFNr0N04nob252sTQxyFLi3eKFRqIg1I87YcqAMT1i6SQrSF6KujUEQrtrjMV0H/eejTCltLdDSTEMzHbnsQ=="], + "get-tsconfig": ["get-tsconfig@4.13.6", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw=="], "giget": ["giget@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.6.0", "pathe": "^2.0.3" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA=="], @@ -311,13 +383,23 @@ "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], - "handlebars": ["handlebars@4.7.9", "", { "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, "optionalDependencies": { "uglify-js": "^3.1.4" }, "bin": { "handlebars": "bin/handlebars" } }, "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ=="], + "grammex": ["grammex@3.1.12", "", {}, "sha512-6ufJOsSA7LcQehIJNCO7HIBykfM7DXQual0Ny780/DEcJIpBlHRvcqEBWGPYd7hrXL2GJ3oJI1MIhaXjWmLQOQ=="], + + "graphmatch": ["graphmatch@1.1.1", "", {}, "sha512-5ykVn/EXM1hF0XCaWh05VbYvEiOL2lY1kBxZtaYsyvjp7cmWOU1XsAdfQBwClraEofXDT197lFbXOEVMHpvQOg=="], - "hookable": ["hookable@6.1.1", "", {}, "sha512-U9LYDy1CwhMCnprUfeAZWZGByVbhd54hwepegYTK7Pi5NvqEj63ifz5z+xukznehT7i6NIZRu89Ay1AZmRsLEQ=="], + "handlebars": ["handlebars@4.7.8", "", { "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, "optionalDependencies": { "uglify-js": "^3.1.4" }, "bin": { "handlebars": "bin/handlebars" } }, "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ=="], + + "hono": ["hono@4.12.18", "", {}, "sha512-RWzP96k/yv0PQfyXnWjs6zot20TqfpfsNXhOnev8d1InAxubW93L11/oNUc3tQqn2G0bSdAOBpX+2uDFHV7kdQ=="], + + "hookable": ["hookable@6.0.1", "", {}, "sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw=="], + + "http-status-codes": ["http-status-codes@2.3.0", "", {}, "sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA=="], + + "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], "human-signals": ["human-signals@8.0.1", "", {}, "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ=="], - "import-without-cache": ["import-without-cache@0.4.0", "", {}, "sha512-NkJQA7oZ4YHQhd2+H3BoRFKF3d/XNsiKpHZCQEMH9pDX27hQQLsTyOocyRgaIVtf8gHX3Nt3LPkR4e5EdtPAGQ=="], + "import-without-cache": ["import-without-cache@0.2.5", "", {}, "sha512-B6Lc2s6yApwnD2/pMzFh/d5AVjdsDXjgkeJ766FmFuJELIGHNycKRj+l3A39yZPM4CchqNCB4RITEAYB1KUM6A=="], "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], @@ -345,8 +427,16 @@ "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], + "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], + "jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], + "locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], + + "make-dir": ["make-dir@3.1.0", "", { "dependencies": { "semver": "^6.0.0" } }, "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw=="], + + "memory-pager": ["memory-pager@1.5.0", "", {}, "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg=="], + "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], "minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="], @@ -357,10 +447,22 @@ "mlly": ["mlly@1.8.0", "", { "dependencies": { "acorn": "^8.15.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.1" } }, "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g=="], + "mongodb": ["mongodb@7.2.0", "", { "dependencies": { "@mongodb-js/saslprep": "^1.3.0", "bson": "^7.2.0", "mongodb-connection-string-url": "^7.0.0" }, "peerDependencies": { "@aws-sdk/credential-providers": "^3.806.0", "@mongodb-js/zstd": "^7.0.0", "gcp-metadata": "^7.0.1", "kerberos": "^7.0.0", "mongodb-client-encryption": ">=7.0.0 <7.1.0", "snappy": "^7.3.2", "socks": "^2.8.6" }, "optionalPeers": ["@aws-sdk/credential-providers", "@mongodb-js/zstd", "gcp-metadata", "kerberos", "mongodb-client-encryption", "snappy", "socks"] }, "sha512-F/2+BMZtLVhY30ioZp0dAmZ+IRZMBqI+nrv6t5+9/1AIwCa8sMRC3jBf81lpxMhnZgqq8CoUD503Z1oZWq1/sw=="], + + "mongodb-connection-string-url": ["mongodb-connection-string-url@7.0.1", "", { "dependencies": { "@types/whatwg-url": "^13.0.0", "whatwg-url": "^14.1.0" } }, "sha512-h0AZ9A7IDVwwHyMxmdMXKy+9oNlF0zFoahHiX3vQ8e3KFcSP3VmsmfvtRSuLPxmyv2vjIDxqty8smTgie/SNRQ=="], + + "mongodb-memory-server": ["mongodb-memory-server@11.1.0", "", { "dependencies": { "mongodb-memory-server-core": "11.1.0", "tslib": "^2.8.1" } }, "sha512-x9psV1KXRgG5t14AmsrfcWCqlNXvPOzcyroMSeRU5vkAm8jxEF5WiLGdGCONLOgeCNjRnpg6igyDum/eTwiooA=="], + + "mongodb-memory-server-core": ["mongodb-memory-server-core@11.1.0", "", { "dependencies": { "async-mutex": "^0.5.0", "camelcase": "^6.3.0", "debug": "^4.4.3", "find-cache-dir": "^3.3.2", "follow-redirects": "^1.16.0", "https-proxy-agent": "^7.0.6", "mongodb": "^7.2.0", "new-find-package-json": "^2.0.0", "semver": "^7.7.3", "tar-stream": "^3.1.8", "tslib": "^2.8.1", "yauzl": "^3.3.0" } }, "sha512-GwpnJVIiUyXdi5BoTsExrvLupSt3sJzCSX5P6fxlr0dCrJkhumiq8SQIqtTBqTu2mMpFMCHdjSS0QMUvFMpbWw=="], + "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="], + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + "neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="], + "new-find-package-json": ["new-find-package-json@2.0.0", "", { "dependencies": { "debug": "^4.3.4" } }, "sha512-lDcBsjBSMlj3LXH2v/FW3txlh2pYTjmbOXPYJD93HI5EwuLzI11tdHSIpUMmfq/IOsldj4Ps8M8flhm+pCK4Ew=="], + "node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="], "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], @@ -369,7 +471,7 @@ "nypm": ["nypm@0.6.5", "", { "dependencies": { "citty": "^0.2.0", "pathe": "^2.0.3", "tinyexec": "^1.0.2" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-K6AJy1GMVyfyMXRVB88700BJqNUkByijGJM8kEHpLdcAt+vSQAVfkWWHYzuRXHSY6xA2sNc5RjTj0p9rE2izVQ=="], - "obug": ["obug@2.1.3", "", {}, "sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg=="], + "obug": ["obug@2.1.1", "", {}, "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ=="], "ofetch": ["ofetch@1.5.1", "", { "dependencies": { "destr": "^2.0.5", "node-fetch-native": "^1.6.7", "ufo": "^1.6.1" } }, "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA=="], @@ -379,26 +481,42 @@ "openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="], - "oxfmt": ["oxfmt@0.56.0", "", { "dependencies": { "tinypool": "2.1.0" }, "optionalDependencies": { "@oxfmt/binding-android-arm-eabi": "0.56.0", "@oxfmt/binding-android-arm64": "0.56.0", "@oxfmt/binding-darwin-arm64": "0.56.0", "@oxfmt/binding-darwin-x64": "0.56.0", "@oxfmt/binding-freebsd-x64": "0.56.0", "@oxfmt/binding-linux-arm-gnueabihf": "0.56.0", "@oxfmt/binding-linux-arm-musleabihf": "0.56.0", "@oxfmt/binding-linux-arm64-gnu": "0.56.0", "@oxfmt/binding-linux-arm64-musl": "0.56.0", "@oxfmt/binding-linux-ppc64-gnu": "0.56.0", "@oxfmt/binding-linux-riscv64-gnu": "0.56.0", "@oxfmt/binding-linux-riscv64-musl": "0.56.0", "@oxfmt/binding-linux-s390x-gnu": "0.56.0", "@oxfmt/binding-linux-x64-gnu": "0.56.0", "@oxfmt/binding-linux-x64-musl": "0.56.0", "@oxfmt/binding-openharmony-arm64": "0.56.0", "@oxfmt/binding-win32-arm64-msvc": "0.56.0", "@oxfmt/binding-win32-ia32-msvc": "0.56.0", "@oxfmt/binding-win32-x64-msvc": "0.56.0" }, "peerDependencies": { "svelte": "^5.0.0", "vite-plus": "*" }, "optionalPeers": ["svelte", "vite-plus"], "bin": { "oxfmt": "bin/oxfmt" } }, "sha512-9Dv0wV3zKiyvhjD7bRKaInKmHQ1sPx3RGOjQkGFJbbdQ16576yf8qhMSO9Q9cvHcs+1NpBsRTkuDDYFFPTJ6gw=="], + "oxfmt": ["oxfmt@0.37.0", "", { "dependencies": { "tinypool": "2.1.0" }, "optionalDependencies": { "@oxfmt/binding-android-arm-eabi": "0.37.0", "@oxfmt/binding-android-arm64": "0.37.0", "@oxfmt/binding-darwin-arm64": "0.37.0", "@oxfmt/binding-darwin-x64": "0.37.0", "@oxfmt/binding-freebsd-x64": "0.37.0", "@oxfmt/binding-linux-arm-gnueabihf": "0.37.0", "@oxfmt/binding-linux-arm-musleabihf": "0.37.0", "@oxfmt/binding-linux-arm64-gnu": "0.37.0", "@oxfmt/binding-linux-arm64-musl": "0.37.0", "@oxfmt/binding-linux-ppc64-gnu": "0.37.0", "@oxfmt/binding-linux-riscv64-gnu": "0.37.0", "@oxfmt/binding-linux-riscv64-musl": "0.37.0", "@oxfmt/binding-linux-s390x-gnu": "0.37.0", "@oxfmt/binding-linux-x64-gnu": "0.37.0", "@oxfmt/binding-linux-x64-musl": "0.37.0", "@oxfmt/binding-openharmony-arm64": "0.37.0", "@oxfmt/binding-win32-arm64-msvc": "0.37.0", "@oxfmt/binding-win32-ia32-msvc": "0.37.0", "@oxfmt/binding-win32-x64-msvc": "0.37.0" }, "bin": { "oxfmt": "bin/oxfmt" } }, "sha512-Kd47gakZAU/i9KkXv3F0EDRoMvSso9O5966kflf9zYto0oZ0NN+Fh5vKKrLwp2Mkt0efYBk5LjCAS0BNC0y0eQ=="], + + "oxlint": ["oxlint@1.52.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.52.0", "@oxlint/binding-android-arm64": "1.52.0", "@oxlint/binding-darwin-arm64": "1.52.0", "@oxlint/binding-darwin-x64": "1.52.0", "@oxlint/binding-freebsd-x64": "1.52.0", "@oxlint/binding-linux-arm-gnueabihf": "1.52.0", "@oxlint/binding-linux-arm-musleabihf": "1.52.0", "@oxlint/binding-linux-arm64-gnu": "1.52.0", "@oxlint/binding-linux-arm64-musl": "1.52.0", "@oxlint/binding-linux-ppc64-gnu": "1.52.0", "@oxlint/binding-linux-riscv64-gnu": "1.52.0", "@oxlint/binding-linux-riscv64-musl": "1.52.0", "@oxlint/binding-linux-s390x-gnu": "1.52.0", "@oxlint/binding-linux-x64-gnu": "1.52.0", "@oxlint/binding-linux-x64-musl": "1.52.0", "@oxlint/binding-openharmony-arm64": "1.52.0", "@oxlint/binding-win32-arm64-msvc": "1.52.0", "@oxlint/binding-win32-ia32-msvc": "1.52.0", "@oxlint/binding-win32-x64-msvc": "1.52.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.15.0" }, "optionalPeers": ["oxlint-tsgolint"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-InLldD+6+3iHJGIrtU1W37UIpsg+xoGCemkZCuSQhxUO3evMX+L872ONvbECyRza9k7ScMCukJIK3Al/2ZMDnQ=="], + + "p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], - "oxlint": ["oxlint@1.71.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.71.0", "@oxlint/binding-android-arm64": "1.71.0", "@oxlint/binding-darwin-arm64": "1.71.0", "@oxlint/binding-darwin-x64": "1.71.0", "@oxlint/binding-freebsd-x64": "1.71.0", "@oxlint/binding-linux-arm-gnueabihf": "1.71.0", "@oxlint/binding-linux-arm-musleabihf": "1.71.0", "@oxlint/binding-linux-arm64-gnu": "1.71.0", "@oxlint/binding-linux-arm64-musl": "1.71.0", "@oxlint/binding-linux-ppc64-gnu": "1.71.0", "@oxlint/binding-linux-riscv64-gnu": "1.71.0", "@oxlint/binding-linux-riscv64-musl": "1.71.0", "@oxlint/binding-linux-s390x-gnu": "1.71.0", "@oxlint/binding-linux-x64-gnu": "1.71.0", "@oxlint/binding-linux-x64-musl": "1.71.0", "@oxlint/binding-openharmony-arm64": "1.71.0", "@oxlint/binding-win32-arm64-msvc": "1.71.0", "@oxlint/binding-win32-ia32-msvc": "1.71.0", "@oxlint/binding-win32-x64-msvc": "1.71.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.22.1", "vite-plus": "*" }, "optionalPeers": ["oxlint-tsgolint", "vite-plus"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-U1m1X+C0vDj7DC1e13IoZULzEcPczE7UOMTs8VlZGHUEIUaSTZKo5qkPsQEfzpgnQ29Pea/w3Xntk62UCecxZw=="], + "p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], + + "p-try": ["p-try@2.2.0", "", {}, "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="], "parse-ms": ["parse-ms@4.0.0", "", {}, "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw=="], + "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "pend": ["pend@1.2.0", "", {}, "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg=="], + "perfect-debounce": ["perfect-debounce@2.1.0", "", {}, "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g=="], - "picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], + "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + + "pkg-dir": ["pkg-dir@4.2.0", "", { "dependencies": { "find-up": "^4.0.0" } }, "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ=="], "pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="], - "posthog-node": ["posthog-node@5.38.2", "", { "dependencies": { "@posthog/core": "^1.35.3" }, "peerDependencies": { "rxjs": "^7.0.0" }, "optionalPeers": ["rxjs"] }, "sha512-eiKpU+vX4hVuHbO/EosvPHsmh2AVIdoVmWss/uUOs1t4b0ViCblw2o8OIFqHxKj3mYRnSOBlX0Dw3wBvcCaYpA=="], + "posthog-node": ["posthog-node@5.28.2", "", { "dependencies": { "@posthog/core": "1.23.4" }, "peerDependencies": { "rxjs": "^7.0.0" }, "optionalPeers": ["rxjs"] }, "sha512-a+unFAKU8Vtez1DAEgCXB/KOZbroQZE+GvnSr9B35u3uMUxtyPO5ulgLJo8AUcZ4prhv6ia8R1Xjr4BrxPfdsA=="], "pretty-ms": ["pretty-ms@9.3.0", "", { "dependencies": { "parse-ms": "^4.0.0" } }, "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ=="], + "proper-lockfile": ["proper-lockfile@4.1.2", "", { "dependencies": { "graceful-fs": "^4.2.4", "retry": "^0.12.0", "signal-exit": "^3.0.2" } }, "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA=="], + + "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], + "quansync": ["quansync@1.0.0", "", {}, "sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA=="], "radash": ["radash@12.1.1", "", {}, "sha512-h36JMxKRqrAxVD8201FrCpyeNuUY9Y5zZwujr20fFO77tpUtGa6EZzfKw/3WaiBX95fq7+MpsuMLNdSnORAwSA=="], @@ -407,11 +525,17 @@ "readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="], + "remeda": ["remeda@2.33.4", "", {}, "sha512-ygHswjlc/opg2VrtiYvUOPLjxjtdKvjGz1/plDhkG66hjNjFr1xmfrs2ClNFo/E6TyUFiwYNh53bKV26oBoMGQ=="], + + "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], + "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], - "rolldown": ["rolldown@1.1.2", "", { "dependencies": { "@oxc-project/types": "=0.137.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.1.2", "@rolldown/binding-darwin-arm64": "1.1.2", "@rolldown/binding-darwin-x64": "1.1.2", "@rolldown/binding-freebsd-x64": "1.1.2", "@rolldown/binding-linux-arm-gnueabihf": "1.1.2", "@rolldown/binding-linux-arm64-gnu": "1.1.2", "@rolldown/binding-linux-arm64-musl": "1.1.2", "@rolldown/binding-linux-ppc64-gnu": "1.1.2", "@rolldown/binding-linux-s390x-gnu": "1.1.2", "@rolldown/binding-linux-x64-gnu": "1.1.2", "@rolldown/binding-linux-x64-musl": "1.1.2", "@rolldown/binding-openharmony-arm64": "1.1.2", "@rolldown/binding-wasm32-wasi": "1.1.2", "@rolldown/binding-win32-arm64-msvc": "1.1.2", "@rolldown/binding-win32-x64-msvc": "1.1.2" }, "bin": { "rolldown": "./bin/cli.mjs" } }, "sha512-x0CrQQqCXWGeI8dTvFfN/Dnv3yMKT9hv5jFjlOreKAx9wqLq9wz7VvLLHyaAXC90/CpggTu9SisSbsJJTPSjNQ=="], + "retry": ["retry@0.12.0", "", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="], - "rolldown-plugin-dts": ["rolldown-plugin-dts@0.26.0", "", { "dependencies": { "@babel/generator": "^8.0.0", "@babel/helper-validator-identifier": "^8.0.0", "@babel/parser": "^8.0.0", "ast-kit": "^3.0.0", "birpc": "^4.0.0", "dts-resolver": "^3.0.0", "get-tsconfig": "5.0.0-beta.5", "obug": "^2.1.3" }, "peerDependencies": { "@ts-macro/tsc": "^0.3.6", "@typescript/native-preview": ">=7.0.0-dev.20260325.1", "rolldown": "^1.0.0", "typescript": "^5.0.0 || ^6.0.0", "vue-tsc": "~3.2.0 || ~3.3.0" }, "optionalPeers": ["@ts-macro/tsc", "@typescript/native-preview", "typescript", "vue-tsc"] }, "sha512-e+kEPtUiDES0htk5iqkSeF4EzAV7R+vugGB44iPDuw1Kw9E+WyL1VG7PaV0IIjGHLiacztMBcMTyrr8ON9CT1Q=="], + "rolldown": ["rolldown@1.0.0-rc.3", "", { "dependencies": { "@oxc-project/types": "=0.112.0", "@rolldown/pluginutils": "1.0.0-rc.3" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-rc.3", "@rolldown/binding-darwin-arm64": "1.0.0-rc.3", "@rolldown/binding-darwin-x64": "1.0.0-rc.3", "@rolldown/binding-freebsd-x64": "1.0.0-rc.3", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.3", "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.3", "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.3", "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.3", "@rolldown/binding-linux-x64-musl": "1.0.0-rc.3", "@rolldown/binding-openharmony-arm64": "1.0.0-rc.3", "@rolldown/binding-wasm32-wasi": "1.0.0-rc.3", "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.3", "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.3" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-Po/YZECDOqVXjIXrtC5h++a5NLvKAQNrd9ggrIG3sbDfGO5BqTUsrI6l8zdniKRp3r5Tp/2JTrXqx4GIguFCMw=="], + + "rolldown-plugin-dts": ["rolldown-plugin-dts@0.22.1", "", { "dependencies": { "@babel/generator": "8.0.0-rc.1", "@babel/helper-validator-identifier": "8.0.0-rc.1", "@babel/parser": "8.0.0-rc.1", "@babel/types": "8.0.0-rc.1", "ast-kit": "^3.0.0-beta.1", "birpc": "^4.0.0", "dts-resolver": "^2.1.3", "get-tsconfig": "^4.13.1", "obug": "^2.1.1" }, "peerDependencies": { "@ts-macro/tsc": "^0.3.6", "@typescript/native-preview": ">=7.0.0-dev.20250601.1", "rolldown": "^1.0.0-rc.3", "typescript": "^5.0.0", "vue-tsc": "~3.2.0" }, "optionalPeers": ["@ts-macro/tsc", "@typescript/native-preview", "typescript", "vue-tsc"] }, "sha512-5E0AiM5RSQhU6cjtkDFWH6laW4IrMu0j1Mo8x04Xo1ALHmaRMs9/7zej7P3RrryVHW/DdZAp85MA7Be55p0iUw=="], "run-applescript": ["run-applescript@7.1.0", "", {}, "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q=="], @@ -429,15 +553,25 @@ "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + "sparse-bitfield": ["sparse-bitfield@3.0.3", "", { "dependencies": { "memory-pager": "^1.0.2" } }, "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ=="], + "std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="], + "streamx": ["streamx@2.25.0", "", { "dependencies": { "events-universal": "^1.0.0", "fast-fifo": "^1.3.2", "text-decoder": "^1.1.0" } }, "sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg=="], + "strip-final-newline": ["strip-final-newline@4.0.0", "", {}, "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw=="], "tagged-tag": ["tagged-tag@1.0.0", "", {}, "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng=="], "tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="], - "tinyexec": ["tinyexec@1.2.4", "", {}, "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg=="], + "tar-stream": ["tar-stream@3.2.0", "", { "dependencies": { "b4a": "^1.6.4", "bare-fs": "^4.5.5", "fast-fifo": "^1.2.0", "streamx": "^2.15.0" } }, "sha512-ojzvCvVaNp6aOTFmG7jaRD0meowIAuPc3cMMhSgKiVWws1GyHbGd/xvnyuRKcKlMpt3qvxx6r0hreCNITP9hIg=="], + + "teex": ["teex@1.0.1", "", { "dependencies": { "streamx": "^2.12.5" } }, "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg=="], + + "text-decoder": ["text-decoder@1.2.7", "", { "dependencies": { "b4a": "^1.6.4" } }, "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ=="], + + "tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="], "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], @@ -445,17 +579,19 @@ "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + "tr46": ["tr46@5.1.1", "", { "dependencies": { "punycode": "^2.3.1" } }, "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw=="], + "tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="], - "trpc-cli": ["trpc-cli@0.15.1", "", { "dependencies": { "commander": "^14.0.0" }, "peerDependencies": { "@orpc/server": "^1.0.0", "@trpc/server": "^10.45.2 || ^11.0.1", "@valibot/to-json-schema": "^1.1.0", "effect": "^3.14.2 || ^4.0.0", "valibot": "^1.1.0", "zod": "^3.24.0 || ^4.0.0" }, "optionalPeers": ["@orpc/server", "@trpc/server", "@valibot/to-json-schema", "effect", "valibot", "zod"], "bin": { "trpc-cli": "dist/bin.js" } }, "sha512-HwXQWABCwEoGwujY0GwH8U1FdEQnFrb9Zb8y+dG4pkry4ALngczVuW33aYRPOg8SiJ4m8qZvTiw3y1FqRxZ7Pg=="], + "trpc-cli": ["trpc-cli@0.12.4", "", { "dependencies": { "commander": "^14.0.0" }, "peerDependencies": { "@orpc/server": "^1.0.0", "@trpc/server": "^10.45.2 || ^11.0.1", "@valibot/to-json-schema": "^1.1.0", "effect": "^3.14.2 || ^4.0.0", "valibot": "^1.1.0", "zod": "^3.24.0 || ^4.0.0" }, "optionalPeers": ["@orpc/server", "@trpc/server", "@valibot/to-json-schema", "effect", "valibot", "zod"], "bin": { "trpc-cli": "dist/bin.js" } }, "sha512-Yo2Ob5J7hUZSWZ2A1M9Kb+0qfSxwmcmYIs3kkQyLd3sn0qU4ryGzNsySfrY3+urqp6FnDnIIdbCSqC9BKxK6Ag=="], - "tsdown": ["tsdown@0.22.3", "", { "dependencies": { "ansis": "^4.3.1", "cac": "^7.0.0", "defu": "^6.1.7", "empathic": "^2.0.1", "hookable": "^6.1.1", "import-without-cache": "^0.4.0", "obug": "^2.1.3", "picomatch": "^4.0.4", "rolldown": "~1.1.1", "rolldown-plugin-dts": "^0.26.0", "semver": "^7.8.4", "tinyexec": "^1.2.4", "tinyglobby": "^0.2.17", "tree-kill": "^1.2.2", "unconfig-core": "^7.5.0" }, "peerDependencies": { "@arethetypeswrong/core": "^0.18.1", "@tsdown/css": "0.22.3", "@tsdown/exe": "0.22.3", "@vitejs/devtools": "*", "publint": "^0.3.8", "tsx": "*", "typescript": "^5.0.0 || ^6.0.0", "unplugin-unused": "^0.5.0", "unrun": "*" }, "optionalPeers": ["@arethetypeswrong/core", "@tsdown/css", "@tsdown/exe", "@vitejs/devtools", "publint", "tsx", "typescript", "unplugin-unused", "unrun"], "bin": { "tsdown": "./dist/run.mjs" } }, "sha512-louqbfA8Qf//B9jTTL0FPtXTNpjCWv1VPkbcmQMph2pTpzs+LnB1tbe4tDDRVpo2BjF5SgUXaTZe45SxB8pWHg=="], + "tsdown": ["tsdown@0.20.3", "", { "dependencies": { "ansis": "^4.2.0", "cac": "^6.7.14", "defu": "^6.1.4", "empathic": "^2.0.0", "hookable": "^6.0.1", "import-without-cache": "^0.2.5", "obug": "^2.1.1", "picomatch": "^4.0.3", "rolldown": "1.0.0-rc.3", "rolldown-plugin-dts": "^0.22.1", "semver": "^7.7.3", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tree-kill": "^1.2.2", "unconfig-core": "^7.4.2", "unrun": "^0.2.27" }, "peerDependencies": { "@arethetypeswrong/core": "^0.18.1", "@vitejs/devtools": "*", "publint": "^0.3.0", "typescript": "^5.0.0", "unplugin-lightningcss": "^0.4.0", "unplugin-unused": "^0.5.0" }, "optionalPeers": ["@arethetypeswrong/core", "@vitejs/devtools", "publint", "typescript", "unplugin-lightningcss", "unplugin-unused"], "bin": { "tsdown": "dist/run.mjs" } }, "sha512-qWOUXSbe4jN8JZEgrkc/uhJpC8VN2QpNu3eZkBWwNuTEjc/Ik1kcc54ycfcQ5QPRHeu9OQXaLfCI3o7pEJgB2w=="], "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], "type-fest": ["type-fest@5.4.4", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-JnTrzGu+zPV3aXIUhnyWJj4z/wigMsdYajGLIYakqyOW1nPllzXEJee0QQbHj+CTIQtXGlAjuK0UY+2xTyjVAw=="], - "typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="], + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], "ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="], @@ -463,12 +599,20 @@ "unconfig-core": ["unconfig-core@7.5.0", "", { "dependencies": { "@quansync/fs": "^1.0.0", "quansync": "^1.0.0" } }, "sha512-Su3FauozOGP44ZmKdHy2oE6LPjk51M/TRRjHv2HNCWiDvfvCoxC2lno6jevMA91MYAdCdwP05QnWdWpSbncX/w=="], - "undici-types": ["undici-types@8.3.0", "", {}, "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ=="], + "undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="], "unicorn-magic": ["unicorn-magic@0.3.0", "", {}, "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA=="], "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], + "unrun": ["unrun@0.2.27", "", { "dependencies": { "rolldown": "1.0.0-rc.3" }, "peerDependencies": { "synckit": "^0.11.11" }, "optionalPeers": ["synckit"], "bin": { "unrun": "dist/cli.mjs" } }, "sha512-Mmur1UJpIbfxasLOhPRvox/QS4xBiDii71hMP7smfRthGcwFL2OAmYRgduLANOAU4LUkvVamuP+02U+c90jlrw=="], + + "valibot": ["valibot@1.2.0", "", { "peerDependencies": { "typescript": ">=5" }, "optionalPeers": ["typescript"] }, "sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg=="], + + "webidl-conversions": ["webidl-conversions@7.0.0", "", {}, "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="], + + "whatwg-url": ["whatwg-url@14.2.0", "", { "dependencies": { "tr46": "^5.1.0", "webidl-conversions": "^7.0.0" } }, "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw=="], + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], "wordwrap": ["wordwrap@1.0.0", "", {}, "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q=="], @@ -479,18 +623,16 @@ "yaml": ["yaml@2.8.2", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A=="], - "yoctocolors": ["yoctocolors@2.1.2", "", {}, "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug=="], + "yauzl": ["yauzl@3.3.0", "", { "dependencies": { "buffer-crc32": "~0.2.3", "pend": "~1.2.0" } }, "sha512-PtGEvEP30p7sbIBJKUBjUnqgTVOyMURc4dLo9iNyAJnNIEz9pm88cCXF21w94Kg3k6RXkeZh5DHOGS0qEONvNQ=="], - "zod": ["zod@4.4.3", "", {}, "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ=="], + "yoctocolors": ["yoctocolors@2.1.2", "", {}, "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug=="], - "@types/fs-extra/@types/node": ["@types/node@25.3.0", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A=="], + "zeptomatch": ["zeptomatch@2.1.0", "", { "dependencies": { "grammex": "^3.1.11", "graphmatch": "^1.1.0" } }, "sha512-KiGErG2J0G82LSpniV0CtIzjlJ10E04j02VOudJsPyPwNZgGnRKQy7I1R7GMyg/QswnE4l7ohSGrQbQbjXPPDA=="], - "@types/jsonfile/@types/node": ["@types/node@25.3.0", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A=="], + "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "c12/defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="], - "changelogen/c12": ["c12@1.11.2", "", { "dependencies": { "chokidar": "^3.6.0", "confbox": "^0.1.7", "defu": "^6.1.4", "dotenv": "^16.4.5", "giget": "^1.2.3", "jiti": "^1.21.6", "mlly": "^1.7.1", "ohash": "^1.1.3", "pathe": "^1.1.2", "perfect-debounce": "^1.0.0", "pkg-types": "^1.2.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "^0.3.4" }, "optionalPeers": ["magicast"] }, "sha512-oBs8a4uvSDO9dm8b7OCFW7+dgtVrwmwnrVXYzLm43ta7ep2jCn/0MhoUFygIWtxhyy6+/MG7/agvpY0U1Iemew=="], "changelogen/pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="], @@ -499,7 +641,7 @@ "fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], - "giget/defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="], + "make-dir/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], @@ -509,30 +651,12 @@ "nypm/citty": ["citty@0.2.1", "", {}, "sha512-kEV95lFBhQgtogAPlQfJJ0WGVSokvLr/UEoFPiKKOXF7pl98HfUVUD0ejsuTCld/9xH9vogSywZ5KqHzXrZpqg=="], - "nypm/tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="], - - "rc9/defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="], - - "tinyglobby/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - - "tsdown/ansis": ["ansis@4.3.1", "", {}, "sha512-BJ8/l4R5LRE7hW9WdSuGYrLSHi2ynxeFpDFbH0K/CgNeY/tyhk+vO6TYxXC5r5CpUhNVX310xzPsN/H9lCdfOA=="], - - "tsdown/cac": ["cac@7.0.0", "", {}, "sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ=="], - - "tsdown/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], - - "tsdown/tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="], - - "@types/fs-extra/@types/node/undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="], - - "@types/jsonfile/@types/node/undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="], + "proper-lockfile/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], "changelogen/c12/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], "changelogen/c12/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], - "changelogen/c12/defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="], - "changelogen/c12/dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="], "changelogen/c12/giget": ["giget@1.2.5", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.5.4", "pathe": "^2.0.3", "tar": "^6.2.1" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-r1ekGw/Bgpi3HLV3h1MRBIlSAdHoIMklpaQ3OQLFcRw9PwAj2rqigvIbg+dBUI51OxVI2jsEtDywDBjSiuf7Ug=="], diff --git a/package.json b/package.json index 44ef254..5017900 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "create-prisma", - "version": "0.7.1", + "version": "0.4.2", "private": false, - "description": "Create Prisma 7 projects with first-party templates and great DX.", + "description": "Create Prisma 8 projects with first-party templates and great DX.", "homepage": "https://github.com/prisma/create-prisma", "bugs": { "url": "https://github.com/prisma/create-prisma/issues" @@ -33,9 +33,12 @@ } }, "scripts": { - "build": "tsdown --config-loader native", - "dev": "tsdown --config-loader native --watch", + "build": "tsdown", + "dev": "tsdown --watch", "start": "bun run ./dist/cli.mjs", + "test": "bun run test:unit && bun run test:e2e", + "test:unit": "bun test ./tests/dependencies.test.ts ./tests/deploy-with-composer.test.ts ./tests/install.test.ts ./tests/node-version.test.ts ./tests/setup-prisma.test.ts ./tests/telemetry.test.ts", + "test:e2e": "bun test --timeout 180000 ./tests/e2e/create-prisma.e2e.test.ts", "check": "bun run format:check && bun run lint", "lint": "oxlint . --deny-warnings", "lint:fix": "oxlint . --fix", @@ -47,28 +50,30 @@ "release-notes": "bunx changelogithub" }, "dependencies": { - "@clack/prompts": "^1.6.0", - "@orpc/server": "^1.14.6", + "@clack/prompts": "^1.7.0", + "@orpc/server": "^1.13.5", "execa": "^9.6.1", - "fs-extra": "^11.3.5", - "handlebars": "^4.7.9", - "posthog-node": "^5.38.2", - "trpc-cli": "^0.15.1", - "zod": "^4.4.3" + "fs-extra": "^11.3.3", + "handlebars": "^4.7.8", + "posthog-node": "^5.28.2", + "trpc-cli": "^0.12.4", + "zod": "^4.3.6" }, "devDependencies": { - "@types/bun": "^1.3.14", + "@prisma/dev": "0.24.7", + "@types/bun": "^1.3.9", "@types/fs-extra": "^11.0.4", - "@types/node": "^26.0.0", + "@types/node": "^25.3.0", "changelogithub": "^14.0.0", - "oxfmt": "^0.56.0", - "oxlint": "^1.71.0", - "tsdown": "^0.22.3", - "typescript": "^6.0.3" + "mongodb-memory-server": "11.1.0", + "oxfmt": "^0.37.0", + "oxlint": "^1.52.0", + "tsdown": "^0.20.3", + "typescript": "^5.9.3" }, "engines": { "bun": ">=1.3.0", - "node": ">=18.0.0" + "node": ">=22.18.0" }, - "packageManager": "bun@1.3.14" + "packageManager": "bun@1.3.9" } diff --git a/src/cli.ts b/src/cli.ts index 618508e..68206ca 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -1,9 +1,11 @@ import { createCreatePrismaCli } from "./index"; -await createCreatePrismaCli().run({ - formatError: (error: unknown) => (error instanceof Error ? error.message : String(error)), +createCreatePrismaCli().run({ + process: { + exit(code): never { + const commandExitCode = + typeof process.exitCode === "number" && process.exitCode !== 0 ? process.exitCode : code; + process.exit(commandExitCode); + }, + }, }); - -if (process.exitCode && process.exitCode !== 0) { - process.exit(process.exitCode); -} diff --git a/src/commands/create.ts b/src/commands/create.ts index 18f51b8..5d96b69 100644 --- a/src/commands/create.ts +++ b/src/commands/create.ts @@ -1,47 +1,27 @@ -import { cancel, intro, isCancel, log, outro, select, spinner, text } from "@clack/prompts"; +import { cancel, intro, isCancel, log, select, spinner, text } from "@clack/prompts"; import fs from "fs-extra"; import path from "node:path"; -import { scaffoldCreateTemplate } from "../templates/render-create-template"; -import { addPackageDependency, writeCreateTemplateDependencies } from "../tasks/install"; -import type { CreateAddonSetupContext } from "../tasks/setup-addons"; +import { + trackCreateCompleted, + trackCreateFailed, + type CreateTelemetryFailureStage, +} from "../telemetry"; +import { scaffoldCreateFrameworkTemplate } from "../templates/render-create-template"; +import { writeCreateTemplateDependencies } from "../tasks/install"; import type { PrismaSetupContext } from "../tasks/setup-prisma"; +import { collectPrismaSetupContext, executePrismaSetupContext } from "../tasks/setup-prisma"; import { CreateCommandInputSchema, CreateTemplateSchema, type CreateCommandInput, type CreateTemplate, - type SchemaPreset, } from "../types"; -import { - collectPrismaSetupInitialContext, - completePrismaSetupContext, - executePrismaSetupContext, -} from "../tasks/setup-prisma"; -import { - collectCreateAddonSetupContext, - executeCreateAddonSetupContext, -} from "../tasks/setup-addons"; -import { - collectComputeDeployContext, - executeComputeDatabaseSetup, - executeComputeDeployContext, - getComputeDeployScriptMap, - type ComputeDatabaseResult, - type ComputeDeployContext, - type ComputeDeployResult, -} from "../tasks/deploy-to-compute"; -import { - trackCreateCompleted, - trackCreateFailed, - type CreateTelemetryFailureStage, -} from "../telemetry"; import { getCreatePrismaIntro } from "../ui/branding"; -import { getRunScriptCommand } from "../utils/package-manager"; +import { getUnsupportedNodeMessage, supportsPrismaNext } from "../utils/node-version"; const DEFAULT_PROJECT_NAME = "my-app"; -const DEFAULT_TEMPLATE: CreateTemplate = "hono"; -const DEFAULT_SCHEMA_PRESET: SchemaPreset = "basic"; +const DEFAULT_TEMPLATE: CreateTemplate = "minimal"; export type CreateTargetPathState = { exists: boolean; @@ -56,9 +36,6 @@ export type CreatePromptContext = { template: CreateTemplate; projectPackageName: string; prismaSetupContext: PrismaSetupContext; - addonSetupContext?: CreateAddonSetupContext; - computeDeployContext?: ComputeDeployContext; - useComputeDatabase: boolean; }; type ExecuteCreateContextResult = @@ -121,50 +98,50 @@ async function promptForCreateTemplate(): Promise { message: "Select template", initialValue: DEFAULT_TEMPLATE, options: [ + { + value: "minimal", + label: "Minimal", + hint: "Script-first Prisma 8 starter with no web framework", + }, { value: "hono", label: "Hono", - hint: "TypeScript API starter", + hint: "Lightweight TypeScript API server", }, { value: "elysia", label: "Elysia", - hint: "TypeScript API starter with Elysia's Node adapter", + hint: "Bun-friendly TypeScript API server", }, { value: "nest", label: "NestJS", - hint: "Official Nest-style API starter with a Prisma service", + hint: "Structured Node API with controllers and services", }, { value: "next", label: "Next.js", - hint: "App Router + TypeScript starter", + hint: "Full-stack React app with App Router", }, { value: "svelte", label: "SvelteKit", - hint: "Official minimal SvelteKit + TypeScript starter", + hint: "Full-stack Svelte 5 app with Vite", }, { value: "astro", label: "Astro", - hint: "Official minimal Astro starter with API route example", + hint: "Content-oriented web app with server routes", }, { value: "nuxt", label: "Nuxt", - hint: "Official minimal Nuxt starter with Nitro API route example", + hint: "Full-stack Vue app with Nitro server routes", }, { value: "tanstack-start", label: "TanStack Start", - hint: "TanStack Start React app with file routes and server functions", - }, - { - value: "turborepo", - label: "Turborepo", - hint: "Monorepo starter with apps + packages/db Prisma package", + hint: "React app with file routes and server functions", }, ], }); @@ -212,6 +189,12 @@ export async function runCreateCommand(rawInput: CreateCommandInput = {}): Promi try { input = CreateCommandInputSchema.parse(rawInput); + if (!supportsPrismaNext()) { + cancel(getUnsupportedNodeMessage()); + process.exitCode = 1; + return; + } + intro(getCreatePrismaIntro()); failureStage = "collect_context"; @@ -223,16 +206,25 @@ export async function runCreateCommand(rawInput: CreateCommandInput = {}): Promi failureStage = "unknown"; const executionResult = await executeCreateContext(context); if (!executionResult.ok) { - failureStage = executionResult.stage; - const error = - executionResult.error instanceof Error - ? executionResult.error - : new Error( - executionResult.error === undefined - ? `Create command failed during ${executionResult.stage}` - : String(executionResult.error), - ); - throw error; + process.exitCode = 1; + if (executionResult.error) { + cancel( + `Create command failed: ${ + executionResult.error instanceof Error + ? executionResult.error.message + : String(executionResult.error) + }`, + ); + } + + await trackCreateFailed({ + input, + context, + durationMs: Date.now() - startedAt, + error: executionResult.error, + stage: executionResult.stage, + }); + return; } await trackCreateCompleted({ @@ -241,28 +233,23 @@ export async function runCreateCommand(rawInput: CreateCommandInput = {}): Promi durationMs: Date.now() - startedAt, }); } catch (error) { - const commandError = error instanceof Error ? error : new Error(String(error)); - cancel(`Create command failed: ${commandError.message}`); - try { - await trackCreateFailed({ - input, - context, - durationMs: Date.now() - startedAt, - error: commandError, - stage: failureStage, - }); - } catch { - // Telemetry is best-effort and must not hide the original command error. - } - throw commandError; + process.exitCode = 1; + cancel(`Create command failed: ${error instanceof Error ? error.message : String(error)}`); + await trackCreateFailed({ + input, + context, + durationMs: Date.now() - startedAt, + error, + stage: failureStage, + }); } } async function collectCreateContext( input: CreateCommandInput, ): Promise { - const useDefaults = input.yes === true; const force = input.force === true; + const useDefaults = input.yes === true; const projectNameInput = input.name ?? (useDefaults ? DEFAULT_PROJECT_NAME : await promptForProjectName()); @@ -302,80 +289,48 @@ async function collectCreateContext( return; } - const prismaSetupInitialContext = await collectPrismaSetupInitialContext(input, { + const prismaSetupContext = await collectPrismaSetupContext(input, { projectDir: targetDirectory, - defaultSchemaPreset: DEFAULT_SCHEMA_PRESET, - }); - if (!prismaSetupInitialContext) { - return; - } - - const projectPackageName = toPackageName(path.basename(targetDirectory)); - const computeDeployContext = await collectComputeDeployContext(input, { - template, - packageManager: prismaSetupInitialContext.packageManager, - useDefaults, - defaultServiceName: projectPackageName, }); - if (computeDeployContext === undefined) { - return; - } - - const prismaSetupContext = await completePrismaSetupContext(input, prismaSetupInitialContext); if (!prismaSetupContext) { return; } - const useComputeDatabase = Boolean( - computeDeployContext && prismaSetupContext.shouldUsePrismaPostgres, - ); - if (useComputeDatabase) { - log.info( - "Prisma Postgres selected: create-prisma will provision a database and write DATABASE_URL to the template env file before deploying.", - ); - } - - const addonSetupContext = await collectCreateAddonSetupContext(input, { - useDefaults, - provider: prismaSetupContext.databaseProvider, - shouldUsePrismaPostgres: prismaSetupContext.shouldUsePrismaPostgres, - shouldUseComputeDeploy: Boolean(computeDeployContext), - }); - if (addonSetupContext === undefined) { - return; - } - return { targetDirectory, targetPathState, force, template, - projectPackageName, + projectPackageName: toPackageName(path.basename(targetDirectory)), prismaSetupContext, - addonSetupContext: addonSetupContext ?? undefined, - computeDeployContext: computeDeployContext ?? undefined, - useComputeDatabase, }; } async function executeCreateContext( context: CreatePromptContext, ): Promise { - const scaffoldSpinner = spinner(); - scaffoldSpinner.start(`Scaffolding ${context.template} project...`); + const createSpinner = context.prismaSetupContext.verbose ? undefined : spinner(); + createSpinner?.start("Creating Prisma 8 project..."); + try { - await scaffoldCreateTemplate({ + if (context.prismaSetupContext.verbose) { + log.step(`Scaffolding ${context.template} starter.`); + } + + await scaffoldCreateFrameworkTemplate({ projectDir: context.targetDirectory, projectName: context.projectPackageName, template: context.template, - schemaPreset: context.prismaSetupContext.schemaPreset, provider: context.prismaSetupContext.databaseProvider, + authoring: context.prismaSetupContext.authoring, packageManager: context.prismaSetupContext.packageManager, - compute: Boolean(context.computeDeployContext), }); - scaffoldSpinner.stop("Project files scaffolded."); + + if (context.prismaSetupContext.verbose) { + log.success("Starter files scaffolded."); + } } catch (error) { - scaffoldSpinner.stop("Could not scaffold project files."); + createSpinner?.error("Could not create Prisma 8 project."); return { ok: false, stage: "scaffold_template", @@ -389,14 +344,8 @@ async function executeCreateContext( packageManager: context.prismaSetupContext.packageManager, projectDir: context.targetDirectory, }); - if (context.computeDeployContext) { - await addPackageDependency({ - scripts: getComputeDeployScriptMap(context.computeDeployContext), - scriptMode: "if-missing", - projectDir: context.targetDirectory, - }); - } } catch (error) { + createSpinner?.error("Could not create Prisma 8 project."); return { ok: false, stage: "scaffold_template", @@ -417,73 +366,32 @@ async function executeCreateContext( const nextSteps = formatPathForDisplay(context.targetDirectory) === "." ? [] - : [`- cd ${formatPathForDisplay(context.targetDirectory)}`]; - if (context.addonSetupContext) { - try { - await executeCreateAddonSetupContext({ - context: context.addonSetupContext, - packageManager: context.prismaSetupContext.packageManager, - projectDir: context.targetDirectory, - verbose: context.prismaSetupContext.verbose, - }); - } catch (error) { - return { - ok: false, - stage: "addons", - error, - }; - } - } - - let computeDatabaseResult: ComputeDatabaseResult | undefined; - if (context.useComputeDatabase && context.computeDeployContext) { - try { - const result = await executeComputeDatabaseSetup({ - context: context.computeDeployContext, - projectDir: context.targetDirectory, - }); - if (!result.ok && !result.cancelled) { - return { - ok: false, - stage: "compute_deploy", - error: result.error, - }; - } - if (result.ok) { - computeDatabaseResult = result.result; - } - } catch (error) { - return { - ok: false, - stage: "compute_deploy", - error, - }; - } - } - - const prismaSetupContext = computeDatabaseResult - ? { - ...context.prismaSetupContext, - databaseUrl: computeDatabaseResult.databaseUrl, - shouldUsePrismaPostgres: false, - } - : context.prismaSetupContext; + : [ + { + command: `cd ${formatPathForDisplay(context.targetDirectory)}`, + description: "Enter your new project directory.", + }, + ]; - let prismaResult: Awaited>; try { - prismaResult = await executePrismaSetupContext(prismaSetupContext, { + const didSetupPrisma = await executePrismaSetupContext(context.prismaSetupContext, { prependNextSteps: nextSteps, projectDir: context.targetDirectory, - includeDevNextStep: !context.useComputeDatabase, + projectName: context.projectPackageName, + template: context.template, + createdProjectPath: context.targetDirectory, + includeDevNextStep: true, + progressSpinner: createSpinner, }); - if (!prismaResult.ok) { + if (!didSetupPrisma) { return { ok: false, stage: "prisma_setup", }; } } catch (error) { + createSpinner?.error("Could not create Prisma 8 project."); return { ok: false, stage: "prisma_setup", @@ -491,51 +399,5 @@ async function executeCreateContext( }; } - let deployResult: ComputeDeployResult | undefined; - if (context.computeDeployContext) { - try { - const result = await executeComputeDeployContext({ - context: context.computeDeployContext, - projectDir: context.targetDirectory, - createProject: !computeDatabaseResult, - }); - if (!result.ok && !result.cancelled) { - return { - ok: false, - stage: "compute_deploy", - error: result.error, - }; - } - if (result.ok) { - deployResult = result.result; - prismaResult.nextSteps.push( - `- ${getRunScriptCommand(context.prismaSetupContext.packageManager, "compute:deploy")}`, - ); - } - } catch (error) { - return { - ok: false, - stage: "compute_deploy", - error, - }; - } - } - - const summaryLines: string[] = []; - summaryLines.push(`Setup complete.${prismaResult.warningSection}`); - if (deployResult) { - const database = computeDatabaseResult?.database ?? deployResult.database; - summaryLines.push( - "", - "Deployed to Prisma Compute:", - ...(deployResult.appUrl ? [`- App URL: ${deployResult.appUrl}`] : []), - `- App: ${deployResult.appName} (${deployResult.appId})`, - `- Deployment: ${deployResult.deploymentId}`, - ...(database ? [`- Database: ${database.name} (${database.id})`] : []), - ); - } - summaryLines.push("", "Next steps:", prismaResult.nextSteps.join("\n")); - outro(summaryLines.join("\n")); - return { ok: true }; } diff --git a/src/constants/db-packages.ts b/src/constants/db-packages.ts index 7e500a6..c03a43d 100644 --- a/src/constants/db-packages.ts +++ b/src/constants/db-packages.ts @@ -1,22 +1,10 @@ -import type { DatabaseProvider, PackageManager } from "../types"; +import type { DatabaseProvider } from "../types"; -export function getDbPackages( - provider: DatabaseProvider, - _packageManager?: PackageManager, -): string { +export function getDbPackages(provider: DatabaseProvider): string { switch (provider) { - case "postgresql": - case "cockroachdb": - return "@prisma/adapter-pg"; - case "mysql": - return "@prisma/adapter-mariadb"; - case "sqlite": - return "@prisma/adapter-libsql"; - case "sqlserver": - return "@prisma/adapter-mssql"; - default: { - const exhaustiveCheck: never = provider; - throw new Error(`Unsupported database provider: ${String(exhaustiveCheck)}`); - } + case "postgres": + return "@prisma/orm-postgres"; + case "mongo": + return "@prisma/orm-mongo"; } } diff --git a/src/constants/dependencies.ts b/src/constants/dependencies.ts index 9115ec2..5f3b11a 100644 --- a/src/constants/dependencies.ts +++ b/src/constants/dependencies.ts @@ -1,89 +1,82 @@ import type { CreateTemplate, PackageManager } from "../types"; -import { usesNodeStyleRuntime } from "../utils/runtime"; export const dependencyVersionMap = { + "@astrojs/node": "^10.0.2", "@elysiajs/node": "^1.4.5", - "@libsql/client": "^0.17.4", - "@prisma/client": "^7.8.0", - "@prisma/adapter-pg": "^7.8.0", - "@prisma/adapter-libsql": "^7.8.0", - "@prisma/adapter-mariadb": "^7.8.0", - "@prisma/adapter-mssql": "^7.8.0", - "@prisma/compute-sdk": "latest", - "@types/node": "^26.0.0", - dotenv: "^17.4.2", - prisma: "^7.8.0", - tsx: "^4.22.4", + "@prisma/cli-engine": "0.2.0", + "@prisma/composer": "0.10.0", + "@prisma/composer-prisma-cloud": "0.10.0", + "@prisma/orm-mongo": "8.0.0-rc.4", + "@prisma/orm-postgres": "8.0.0-rc.4", + "@sveltejs/adapter-node": "^5.3.2", + "@types/node": "^25.6.2", + alchemy: "2.0.0-beta.67", + arktype: "^2.2.3", + esbuild: "^0.28.1", + effect: "4.0.0-beta.103", + mongodb: "^7.1.0", + "mongodb-memory-server": "^11.1.0", + nitro: "^3.0.260610-beta", + tsx: "^4.21.0", + typescript: "^5.9.3", } as const; +export const PRISMA_PLATFORM_CLI_PACKAGE = "prisma@next"; + export type AvailableDependency = keyof typeof dependencyVersionMap; export type CreateTemplateDependencyTarget = { packageJsonPath: string; - dependencies: AvailableDependency[]; - devDependencies: AvailableDependency[]; + dependencies: string[]; + devDependencies: string[]; customDependencies?: Record; }; -const computeConfigTemplates = new Set([ - "hono", - "elysia", - "nest", - "next", - "astro", - "nuxt", - "tanstack-start", - "turborepo", -]); +export function getDependencyVersion(packageName: string): string | undefined { + return dependencyVersionMap[packageName as AvailableDependency]; +} -function getWorkspaceDependencyVersion(packageManager: PackageManager): string { - return packageManager === "npm" ? "*" : "workspace:*"; +function usesEsbuild(template: CreateTemplate): boolean { + return ( + template === "minimal" || template === "hono" || template === "elysia" || template === "nest" + ); } export function getCreateTemplateDependencies( template: CreateTemplate, - packageManager: PackageManager, + _packageManager: PackageManager, ): CreateTemplateDependencyTarget[] { - const targets: CreateTemplateDependencyTarget[] = []; - - if (template === "hono" || template === "elysia" || template === "nest") { - const runtimeDevDependencies: AvailableDependency[] = usesNodeStyleRuntime(packageManager) - ? ["tsx"] - : []; + const dependencies = ["@prisma/composer", "@prisma/composer-prisma-cloud", "alchemy"]; + const devDependencies = ["@prisma/cli-engine"]; - if (template === "elysia" && packageManager !== "deno") { - targets.push({ - packageJsonPath: "package.json", - dependencies: ["@elysiajs/node"], - devDependencies: ["@types/node", ...runtimeDevDependencies], - }); - } else if (runtimeDevDependencies.length > 0) { - targets.push({ - packageJsonPath: "package.json", - dependencies: [], - devDependencies: runtimeDevDependencies, - }); - } + if (usesEsbuild(template)) { + devDependencies.push("esbuild"); } - - if (template === "turborepo") { - targets.push({ - packageJsonPath: "apps/api/package.json", - dependencies: ["dotenv"], - devDependencies: ["tsx"], - customDependencies: { - "@repo/db": getWorkspaceDependencyVersion(packageManager), - }, - }); + if (template === "minimal" || usesEsbuild(template)) { + devDependencies.push("tsx"); } - - if (computeConfigTemplates.has(template)) { - targets.push({ - packageJsonPath: "package.json", - dependencies: [], - devDependencies: ["@prisma/compute-sdk"], - }); + if (template === "minimal") { + devDependencies.push("typescript"); + } + if (template === "elysia") { + dependencies.push("@elysiajs/node"); + devDependencies.push("@types/node"); + } + if (template === "svelte") { + devDependencies.push("@sveltejs/adapter-node"); + } + if (template === "astro") { + dependencies.push("@astrojs/node"); + } + if (template === "tanstack-start") { + devDependencies.push("nitro"); } - return targets; + return [ + { + packageJsonPath: "package.json", + dependencies, + devDependencies, + }, + ]; } diff --git a/src/index.ts b/src/index.ts index 89bc6d7..1b30c01 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,11 +1,31 @@ import { os } from "@orpc/server"; import { createCli } from "trpc-cli"; +import { z } from "zod"; import { runCreateCommand } from "./commands/create"; import { CreateCommandInputSchema, type CreateCommandInput } from "./types"; const CLI_VERSION = process.env.CREATE_PRISMA_CLI_VERSION ?? "0.0.0"; +const CreateCliInputSchema = z.tuple([ + z + .string() + .trim() + .min(1, "Please enter a valid project name") + .optional() + .describe("Project name / directory"), + CreateCommandInputSchema, +]); + +function normalizeCreateCliInput(input: z.infer): CreateCommandInput { + const [projectName, options] = input; + + return { + ...options, + name: options.name ?? projectName, + }; +} + export const router = os.router({ create: os .meta({ @@ -13,9 +33,9 @@ export const router = os.router({ default: true, negateBooleans: true, }) - .input(CreateCommandInputSchema.optional()) + .input(CreateCliInputSchema) .handler(async ({ input }) => { - await runCreateCommand(input ?? {}); + await runCreateCommand(normalizeCreateCliInput(input)); }), }); @@ -33,10 +53,9 @@ export async function create(input: CreateCommandInput = {}): Promise { export type { CreateCommandInput }; export { + AuthoringStyleSchema, CreateCommandInputSchema, CreateTemplateSchema, DatabaseProviderSchema, - DatabaseUrlSchema, PackageManagerSchema, - SchemaPresetSchema, } from "./types"; diff --git a/src/tasks/deploy-to-compute.ts b/src/tasks/deploy-to-compute.ts deleted file mode 100644 index 81aa98e..0000000 --- a/src/tasks/deploy-to-compute.ts +++ /dev/null @@ -1,453 +0,0 @@ -import { cancel, confirm, isCancel, log, spinner } from "@clack/prompts"; -import { execa, type Options as ExecaOptions } from "execa"; - -import { - isComputeDeployableTemplate, - type CreateCommandInput, - type CreateTemplate, - type PackageManager, -} from "../types"; -import { getPackageExecutionArgs, getPackageExecutionCommand } from "../utils/package-manager"; - -const PRISMA_CLI_PACKAGE = "@prisma/cli@latest"; - -const DEPLOY_OPTIONS_BY_TEMPLATE: Partial< - Record< - CreateTemplate, - { - configTarget?: string; - } - > -> = { - hono: {}, - elysia: {}, - nest: {}, - next: {}, - astro: {}, - nuxt: {}, - "tanstack-start": {}, - turborepo: { - configTarget: "api", - }, -}; - -type PrismaCliJsonError = { message?: string; summary?: string; name?: string }; - -type PrismaCliJsonEnvelope = - | { - ok: true; - result: T; - } - | { ok: false; error: PrismaCliJsonError }; - -type AppDeployJsonPayload = { - project: { - id: string; - name: string; - }; - branch: { - name: string; - }; - app: { - id: string; - name: string; - }; - deployment: { - id: string; - status: string; - url: string | null; - }; - branchDatabase?: { - status: "created" | "skipped"; - database?: { - id: string; - name: string; - }; - }; -}; - -type ProjectCreateJsonPayload = { - project: { - id: string; - name: string; - }; -}; - -type DatabaseCreateJsonPayload = { - projectId: string; - projectName: string; - database: { - id: string; - name: string; - }; - connectionString: string; -}; - -export type ComputeDeployContext = { - template: CreateTemplate; - packageManager: PackageManager; - createProjectName: string; - configTarget?: string; -}; - -export type ComputeDeployResult = { - appUrl: string | null; - appId: string; - appName: string; - deploymentId: string; - projectId: string; - projectName: string; - branchName: string; - database?: { - id: string; - name: string; - }; -}; - -export type ComputeDatabaseResult = { - databaseUrl: string; - projectId: string; - projectName: string; - database: { - id: string; - name: string; - }; -}; - -function getPrismaCliCommand(packageManager: PackageManager): string { - return getPackageExecutionCommand(getPrismaCliExecutionPackageManager(packageManager), [ - PRISMA_CLI_PACKAGE, - ]); -} - -function getPrismaCliAppDeployCommand(packageManager: PackageManager): string { - return getPackageExecutionCommand( - getPrismaCliExecutionPackageManager(packageManager), - [PRISMA_CLI_PACKAGE, "app", "deploy"], - { silent: true }, - ); -} - -export function getComputeDeployScriptMap(context: ComputeDeployContext): Record { - const deployArgs = [...getComputeDeployTargetArgs(context), "--prod", "--yes"]; - const deployCommand = [getPrismaCliAppDeployCommand(context.packageManager), ...deployArgs].join( - " ", - ); - - return { - "compute:deploy": deployCommand, - }; -} - -function getComputeDeployTargetArgs(context: ComputeDeployContext): string[] { - return context.configTarget ? [context.configTarget] : []; -} - -function runPrismaCli( - packageManager: PackageManager, - args: string[], - options: ExecaOptions & { silentPackageRunner?: boolean } = {}, -) { - const { silentPackageRunner, ...execaOptions } = options; - const execution = getPackageExecutionArgs( - getPrismaCliExecutionPackageManager(packageManager), - [PRISMA_CLI_PACKAGE, ...args], - { silent: silentPackageRunner }, - ); - return execa(execution.command, execution.args, execaOptions); -} - -function getPrismaCliExecutionPackageManager(packageManager: PackageManager): PackageManager { - // @prisma/cli is a Node CLI; Deno's npm runner currently fails to load its dependencies. - return packageManager === "deno" ? "npm" : packageManager; -} - -async function isAuthenticated(packageManager: PackageManager): Promise { - try { - await runPrismaCli(packageManager, ["project", "list", "--json"], { stdio: "pipe" }); - return true; - } catch { - return false; - } -} - -async function ensurePrismaCliAvailable(packageManager: PackageManager): Promise { - try { - await runPrismaCli(packageManager, ["--help"], { stdio: "pipe" }); - return true; - } catch (error) { - const command = getPrismaCliCommand(packageManager); - const isMissing = - typeof error === "object" && - error !== null && - "code" in error && - (error as { code?: string }).code === "ENOENT"; - if (isMissing) { - log.warn(`Could not find the selected package manager. Re-run ${command} manually.`); - return false; - } - log.warn( - `Could not run ${command}${error instanceof Error ? `: ${redactSecrets(error.message)}` : "."}`, - ); - return false; - } -} - -export async function collectComputeDeployContext( - input: CreateCommandInput, - options: { - template: CreateTemplate; - packageManager: PackageManager; - useDefaults: boolean; - defaultServiceName: string; - }, -): Promise { - if (!isComputeDeployableTemplate(options.template)) { - if (input.deploy === true) { - throw createExplicitDeployError( - `${options.template} is not supported by prisma app deploy yet`, - ); - } - return null; - } - - if (input.deploy === false) { - return null; - } - - let wantsDeploy: boolean; - if (input.deploy === true) { - wantsDeploy = true; - } else if (options.useDefaults) { - return null; - } else { - const confirmed = await confirm({ - message: "Deploy to Prisma Compute now?", - initialValue: false, - }); - if (isCancel(confirmed)) { - cancel("Operation cancelled."); - return undefined; - } - wantsDeploy = confirmed; - } - - if (!wantsDeploy) return null; - - if (!(await ensurePrismaCliAvailable(options.packageManager))) { - if (input.deploy === true) { - throw createExplicitDeployError("the Prisma CLI is not available"); - } - return null; - } - - if (!(await isAuthenticated(options.packageManager))) { - log.info("Authenticating with Prisma..."); - try { - await runPrismaCli(options.packageManager, ["auth", "login"], { stdio: "inherit" }); - } catch (error) { - log.warn( - `Prisma login was not completed${error instanceof Error ? `: ${redactSecrets(error.message)}` : "."}`, - ); - if (input.deploy === true) { - throw createExplicitDeployError("authentication failed", error); - } - return null; - } - } - - const deployOptions = DEPLOY_OPTIONS_BY_TEMPLATE[options.template]; - if (!deployOptions) { - if (input.deploy === true) { - throw createExplicitDeployError( - `${options.template} is not supported by prisma app deploy yet`, - ); - } - return null; - } - - return { - template: options.template, - packageManager: options.packageManager, - createProjectName: options.defaultServiceName, - configTarget: deployOptions.configTarget, - }; -} - -function redactSecrets(message: string): string { - return message - .replace( - /(['"])([A-Z0-9_]*(?:DATABASE_URL|DIRECT_URL|TOKEN|SECRET|PASSWORD|API_KEY|PRIVATE_KEY|ACCESS_KEY)[A-Z0-9_]*=)(.*?)\1/g, - "$1$2$1", - ) - .replace( - /\b([A-Z0-9_]*(?:DATABASE_URL|DIRECT_URL|TOKEN|SECRET|PASSWORD|API_KEY|PRIVATE_KEY|ACCESS_KEY)[A-Z0-9_]*=)[^\s]+/g, - "$1", - ); -} - -function parseJson(stdout: unknown): T | null { - if (typeof stdout !== "string" || stdout.trim().length === 0) { - return null; - } - - try { - return JSON.parse(stdout) as T; - } catch { - return null; - } -} - -function getJsonErrorMessage(error: PrismaCliJsonError | undefined, fallback: string): string { - return error?.summary ?? error?.message ?? error?.name ?? fallback; -} - -function getErrorMessage(error: unknown): string { - return redactSecrets(error instanceof Error ? error.message : String(error)); -} - -function createDeployError(message: string | undefined): Error { - return new Error(redactSecrets(message ?? "unknown error")); -} - -function createExplicitDeployError(reason: string, error?: unknown): Error { - const detail = error instanceof Error ? `: ${redactSecrets(error.message)}` : ""; - return new Error(`Deploy requested but ${reason}${detail}`); -} - -async function runPrismaCliJson(params: { - packageManager: PackageManager; - args: string[]; - cwd: string; - fallbackError: string; - invalidOutputError: string; -}): Promise<{ ok: true; result: T } | { ok: false; error: Error }> { - try { - const { stdout, exitCode } = await runPrismaCli(params.packageManager, params.args, { - cwd: params.cwd, - reject: false, - stdio: ["ignore", "pipe", "pipe"], - silentPackageRunner: true, - }); - - const parsed = parseJson>(stdout); - if (!parsed) { - return { ok: false, error: new Error(params.invalidOutputError) }; - } - if (exitCode !== 0 || !parsed.ok) { - return { - ok: false, - error: createDeployError( - parsed.ok - ? params.fallbackError - : getJsonErrorMessage(parsed.error, params.fallbackError), - ), - }; - } - - return { ok: true, result: parsed.result }; - } catch (error) { - return { ok: false, error: new Error(getErrorMessage(error)) }; - } -} - -function toComputeDeployResult(data: AppDeployJsonPayload): ComputeDeployResult { - return { - appUrl: data.deployment.url, - appId: data.app.id, - appName: data.app.name, - deploymentId: data.deployment.id, - projectId: data.project.id, - projectName: data.project.name, - branchName: data.branch.name, - database: data.branchDatabase?.database, - }; -} - -export async function executeComputeDatabaseSetup(params: { - context: ComputeDeployContext; - projectDir: string; -}): Promise< - { ok: true; result: ComputeDatabaseResult } | { ok: false; cancelled: boolean; error?: unknown } -> { - const projectSpinner = spinner(); - projectSpinner.start("Creating Prisma Compute project..."); - - const projectResult = await runPrismaCliJson({ - packageManager: params.context.packageManager, - args: ["project", "create", params.context.createProjectName, "--json"], - cwd: params.projectDir, - fallbackError: "Prisma project create failed.", - invalidOutputError: "Invalid prisma project create output", - }); - if (!projectResult.ok) { - projectSpinner.error(`Project creation failed: ${projectResult.error.message}`); - return { ok: false, cancelled: false, error: projectResult.error }; - } - projectSpinner.stop("Prisma Compute project created."); - - const databaseSpinner = spinner(); - databaseSpinner.start("Creating Prisma Postgres database..."); - const databaseResult = await runPrismaCliJson({ - packageManager: params.context.packageManager, - args: ["database", "create", "main", "--branch", "main", "--json"], - cwd: params.projectDir, - fallbackError: "Prisma database create failed.", - invalidOutputError: "Invalid prisma database create output", - }); - if (!databaseResult.ok) { - databaseSpinner.error(`Database creation failed: ${databaseResult.error.message}`); - return { ok: false, cancelled: false, error: databaseResult.error }; - } - databaseSpinner.stop("Prisma Postgres database created."); - - return { - ok: true, - result: { - databaseUrl: databaseResult.result.connectionString, - projectId: databaseResult.result.projectId, - projectName: databaseResult.result.projectName, - database: databaseResult.result.database, - }, - }; -} - -export async function executeComputeDeployContext(params: { - context: ComputeDeployContext; - projectDir: string; - createProject?: boolean; -}): Promise< - { ok: true; result: ComputeDeployResult } | { ok: false; cancelled: boolean; error?: unknown } -> { - const deploySpinner = spinner(); - deploySpinner.start("Deploying to Prisma Compute..."); - const args = [ - "app", - "deploy", - ...getComputeDeployTargetArgs(params.context), - "--json", - "--yes", - "--prod", - ...(params.createProject === false - ? [] - : ["--create-project", params.context.createProjectName]), - ]; - - const deployResult = await runPrismaCliJson({ - packageManager: params.context.packageManager, - args, - cwd: params.projectDir, - fallbackError: "Prisma app deploy failed.", - invalidOutputError: "Invalid prisma app deploy output", - }); - if (!deployResult.ok) { - deploySpinner.error(`Deploy failed: ${deployResult.error.message}`); - return { ok: false, cancelled: false, error: deployResult.error }; - } - - deploySpinner.stop("Deployed to Prisma Compute."); - return { - ok: true, - result: toComputeDeployResult(deployResult.result), - }; -} diff --git a/src/tasks/deploy-with-composer.ts b/src/tasks/deploy-with-composer.ts new file mode 100644 index 0000000..e0a7347 --- /dev/null +++ b/src/tasks/deploy-with-composer.ts @@ -0,0 +1,420 @@ +import { cancel, isCancel, log, select, spinner } from "@clack/prompts"; +import { execa } from "execa"; + +import { PRISMA_PLATFORM_CLI_PACKAGE } from "../constants/dependencies"; +import type { PackageManager } from "../types"; +import { + getPackageExecutionArgs, + getPackageExecutionCommand, + getRunScriptArgs, + getRunScriptCommand, +} from "../utils/package-manager"; + +type PrismaCliEnvelope = { + ok: boolean; + result?: Result; + error?: { summary?: string; message?: string; why?: string }; +}; + +type PrismaWorkspace = { + id: string; + name: string | null; +}; + +type WhoamiResult = { + authenticated: boolean; + workspace: PrismaWorkspace | null; + source: "stored" | "environment" | null; +}; + +type WorkspaceListResult = { + items: Array<{ + workspaceId: string; + workspaceName: string | null; + current: boolean; + }>; +}; + +type WorkspaceUseResult = { + workspace: PrismaWorkspace; +}; + +type ProjectShowResult = { + workspace: PrismaWorkspace; + project: { id: string; name: string } | null; +}; + +type ComposerDeployCommandResult = { + summary: { + app: string; + nodes: Array<{ + entities: Array<{ kind: string; id: string; url?: string }>; + }>; + } | null; +}; + +export type ComposerDeployResult = { + appName: string; + appUrl?: string; + workspace?: PrismaWorkspace; + project: { + id?: string; + name: string; + consoleUrl?: string; + }; +}; + +function redactSecrets(message: string): string { + return message + .replace(/\b((?:prisma\+)?postgres(?:ql)?:\/\/)[^\s'"]+/gi, "$1") + .replace( + /\b([A-Z0-9_]*(?:DATABASE_URL|TOKEN|SECRET|PASSWORD|API_KEY|PRIVATE_KEY)[A-Z0-9_]*=)[^\s]+/g, + "$1", + ); +} + +function getErrorMessage(error: unknown): string { + if (error instanceof Error) return redactSecrets(error.message); + return redactSecrets(String(error)); +} + +function stripResourcePrefix(id: string, prefix: "proj" | "wksp"): string { + const marker = `${prefix}_`; + return id.startsWith(marker) ? id.slice(marker.length) : id; +} + +export function getConsoleProjectUrl(workspaceId: string, projectId: string): string { + const consoleWorkspaceId = stripResourcePrefix(workspaceId, "wksp"); + const consoleProjectId = stripResourcePrefix(projectId, "proj"); + return `https://console.prisma.io/${encodeURIComponent( + consoleWorkspaceId, + )}/${encodeURIComponent(consoleProjectId)}`; +} + +export function parsePrismaCliEnvelope( + output: string, +): PrismaCliEnvelope { + const lines = output + .split(/\r?\n/) + .map((line) => line.trim()) + .filter(Boolean) + .reverse(); + + for (const line of lines) { + try { + const parsed = JSON.parse(line) as Record; + const candidate = parsed.kind === "result" ? parsed.envelope : parsed; + if (typeof candidate !== "object" || candidate === null) continue; + if (typeof Reflect.get(candidate, "ok") !== "boolean") continue; + return candidate as PrismaCliEnvelope; + } catch { + // The CLI may print progress frames before its final JSON envelope. + } + } + + throw new Error("Prisma CLI returned output that is not a valid result envelope."); +} + +function getPrismaCliArgs(packageManager: PackageManager, args: string[]) { + return getPackageExecutionArgs(packageManager, [PRISMA_PLATFORM_CLI_PACKAGE, ...args]); +} + +async function runPrismaJsonCommand(options: { + packageManager: PackageManager; + projectDir: string; + args: string[]; + forwardStderr?: boolean; +}): Promise { + const invocation = getPrismaCliArgs(options.packageManager, [ + ...options.args, + "--json", + "--no-interactive", + ]); + const result = await execa(invocation.command, invocation.args, { + cwd: options.projectDir, + env: process.env, + reject: false, + }); + + if (options.forwardStderr && result.stderr) { + process.stderr.write(result.stderr.endsWith("\n") ? result.stderr : `${result.stderr}\n`); + } + + let envelope: PrismaCliEnvelope; + try { + envelope = parsePrismaCliEnvelope(result.stdout); + } catch (error) { + if (result.exitCode !== 0 && result.stderr.trim()) throw new Error(result.stderr.trim()); + throw error; + } + + if (result.exitCode !== 0 || !envelope.ok || envelope.result === undefined) { + const summary = envelope.error?.summary ?? envelope.error?.message; + throw new Error( + [summary, envelope.error?.why].filter(Boolean).join(": ") || + result.stderr.trim() || + "Prisma CLI command failed.", + ); + } + return envelope.result; +} + +async function ensureAuthentication( + packageManager: PackageManager, + projectDir: string, + beforeInteractiveLogin?: () => void, +): Promise { + const whoami = () => + runPrismaJsonCommand({ + packageManager, + projectDir, + args: ["auth", "whoami"], + }); + + const authState = await whoami(); + if (authState.authenticated) return authState; + + const loginCommand = getPackageExecutionCommand(packageManager, [ + PRISMA_PLATFORM_CLI_PACKAGE, + "auth", + "login", + ]); + if (process.stdin.isTTY !== true) { + throw new Error( + `Sign in first with ${loginCommand}, then run ${getRunScriptCommand(packageManager, "deploy")}.`, + ); + } + + beforeInteractiveLogin?.(); + log.info("Sign in to Prisma to deploy."); + const login = getPrismaCliArgs(packageManager, ["auth", "login"]); + await execa(login.command, login.args, { + cwd: projectDir, + env: process.env, + stdio: "inherit", + }); + + const authenticatedState = await whoami(); + if (!authenticatedState.authenticated) { + throw new Error("Prisma sign-in completed without an active workspace session."); + } + return authenticatedState; +} + +function workspaceLabel(workspace: PrismaWorkspace): string { + return workspace.name ?? workspace.id; +} + +async function useWorkspace(options: { + packageManager: PackageManager; + projectDir: string; + workspace: string; +}): Promise { + const result = await runPrismaJsonCommand({ + packageManager: options.packageManager, + projectDir: options.projectDir, + args: ["auth", "workspace", "use", options.workspace], + }); + return result.workspace; +} + +async function selectDeploymentWorkspace(options: { + packageManager: PackageManager; + projectDir: string; + shouldPrompt: boolean; + workspace?: string; + authState: WhoamiResult; + beforePrompt?: () => void; + afterPrompt?: () => void; +}): Promise { + const activeWorkspace = options.authState.workspace; + if (!activeWorkspace) { + throw new Error("The active Prisma credential does not specify a workspace."); + } + + if (options.workspace) { + if (options.authState.source === "environment") { + if (options.workspace === activeWorkspace.id || options.workspace === activeWorkspace.name) { + return activeWorkspace; + } + throw new Error( + `The environment credential is fixed to workspace ${workspaceLabel( + activeWorkspace, + )}. Unset it before using --workspace ${options.workspace}.`, + ); + } + return useWorkspace({ + packageManager: options.packageManager, + projectDir: options.projectDir, + workspace: options.workspace, + }); + } + + if (!options.shouldPrompt || process.stdin.isTTY !== true) return activeWorkspace; + + const available = await runPrismaJsonCommand({ + packageManager: options.packageManager, + projectDir: options.projectDir, + args: ["auth", "workspace", "list"], + }); + if (available.items.length <= 1) return activeWorkspace; + + options.beforePrompt?.(); + const selectedWorkspaceId = await select({ + message: "Select Prisma workspace for deployment", + initialValue: activeWorkspace.id, + options: available.items.map((workspace) => ({ + value: workspace.workspaceId, + label: workspace.workspaceName ?? workspace.workspaceId, + hint: workspace.current ? `${workspace.workspaceId}, current` : workspace.workspaceId, + })), + }); + if (isCancel(selectedWorkspaceId)) { + cancel("Operation cancelled."); + return; + } + options.afterPrompt?.(); + if (selectedWorkspaceId === activeWorkspace.id) return activeWorkspace; + + return useWorkspace({ + packageManager: options.packageManager, + projectDir: options.projectDir, + workspace: selectedWorkspaceId, + }); +} + +export function parseComposerDeployResult(result: ComposerDeployCommandResult): + | { + appName: string; + appUrl?: string; + } + | undefined { + const summary = result.summary; + if (!summary) return; + const computeService = summary.nodes + .flatMap((node) => node.entities) + .find((entity) => entity.kind === "compute-service"); + return { + appName: summary.app, + ...(computeService?.url ? { appUrl: computeService.url.replace(/\/$/, "") } : {}), + }; +} + +async function getProjectDetails(options: { + packageManager: PackageManager; + projectDir: string; + appName: string; +}): Promise | undefined> { + try { + const result = await runPrismaJsonCommand({ + packageManager: options.packageManager, + projectDir: options.projectDir, + args: ["project", "show", "--project", options.appName], + }); + if (!result.project) return; + return { + workspace: result.workspace, + project: { + id: result.project.id, + name: result.project.name, + consoleUrl: getConsoleProjectUrl(result.workspace.id, result.project.id), + }, + }; + } catch { + // Metadata enrichment must not turn a successful deploy into a failure. + return; + } +} + +export async function deployWithComposer(options: { + appName: string; + packageManager: PackageManager; + projectDir: string; + shouldPromptForWorkspace: boolean; + verbose: boolean; + workspace?: string; +}): Promise { + const progress = options.verbose ? undefined : spinner(); + let progressRunning = false; + const showProgress = (message: string) => { + if (!progress) return; + if (progressRunning) { + progress.message(message); + } else { + progress.start(message); + progressRunning = true; + } + }; + const clearProgress = () => { + if (!progress || !progressRunning) return; + progress.clear(); + progressRunning = false; + }; + + try { + showProgress("Checking Prisma account..."); + if (options.verbose) log.step("Checking Prisma account."); + const authState = await ensureAuthentication( + options.packageManager, + options.projectDir, + clearProgress, + ); + + showProgress("Checking Prisma workspace..."); + if (options.verbose) log.step("Checking Prisma workspace."); + const selectedWorkspace = await selectDeploymentWorkspace({ + packageManager: options.packageManager, + projectDir: options.projectDir, + shouldPrompt: options.shouldPromptForWorkspace, + authState, + beforePrompt: clearProgress, + afterPrompt: () => showProgress("Selecting Prisma workspace..."), + ...(options.workspace ? { workspace: options.workspace } : {}), + }); + if (!selectedWorkspace) return; + + showProgress("Building for deployment..."); + if (options.verbose) log.step("Building for deployment."); + const build = getRunScriptArgs(options.packageManager, "build"); + await execa(build.command, build.args, { + cwd: options.projectDir, + env: process.env, + stdio: options.verbose ? "inherit" : "pipe", + }); + + showProgress("Deploying to Prisma..."); + if (options.verbose) log.step("Deploying to Prisma."); + const deployment = parseComposerDeployResult( + await runPrismaJsonCommand({ + packageManager: options.packageManager, + projectDir: options.projectDir, + args: ["composer", "deploy", "module.ts"], + forwardStderr: options.verbose, + }), + ); + const appName = deployment?.appName ?? options.appName; + + showProgress("Loading deployment details..."); + const details = await getProjectDetails({ + packageManager: options.packageManager, + projectDir: options.projectDir, + appName, + }); + + progress?.stop("Deployed to Prisma."); + progressRunning = false; + if (options.verbose) log.success("Deployed to Prisma."); + const workspace = details?.workspace ?? selectedWorkspace; + return { + appName, + ...(deployment?.appUrl ? { appUrl: deployment.appUrl } : {}), + ...(workspace ? { workspace } : {}), + project: details?.project ?? { name: appName }, + }; + } catch (error) { + progress?.error("Deployment failed."); + progressRunning = false; + log.error(`Deploy failed: ${getErrorMessage(error)}`); + return; + } +} diff --git a/src/tasks/install.ts b/src/tasks/install.ts index 8ba6ad5..47a1dd5 100644 --- a/src/tasks/install.ts +++ b/src/tasks/install.ts @@ -2,51 +2,58 @@ import { execa } from "execa"; import fs from "fs-extra"; import path from "node:path"; -import { getDenoPrismaSpecifier } from "../utils/package-manager"; import { - dependencyVersionMap, getCreateTemplateDependencies, - type AvailableDependency, + getDependencyVersion, + PRISMA_PLATFORM_CLI_PACKAGE, } from "../constants/dependencies"; import { getDbPackages } from "../constants/db-packages"; -import type { CreateTemplate, DatabaseProvider, PackageManager } from "../types"; -import { getInstallArgs } from "../utils/package-manager"; -import { requiresDotenvConfigImport } from "../utils/runtime"; - -function getPrismaScriptMap(packageManager: PackageManager) { - if (packageManager === "deno") { - const prismaSpecifier = getDenoPrismaSpecifier(); - const prismaCli = `deno run -A --env-file=.env ${prismaSpecifier}`; - - return { - "db:generate": `${prismaCli} generate`, - "db:push": `${prismaCli} db push`, - "db:migrate": `${prismaCli} migrate dev`, - "db:seed": `${prismaCli} db seed`, - } as const; - } +import type { AuthoringStyle, CreateTemplate, DatabaseProvider, PackageManager } from "../types"; +import { + getInstallArgs, + getPackageExecutionCommand, + getRunScriptCommand, +} from "../utils/package-manager"; - if (packageManager === "bun") { - const prismaCli = "bun --env-file=.env ./node_modules/.bin/prisma"; - - return { - "db:generate": `${prismaCli} generate`, - "db:push": `${prismaCli} db push`, - "db:migrate": `${prismaCli} migrate dev`, - "db:seed": `${prismaCli} db seed`, - } as const; - } +function getPrismaScriptMap(packageManager: PackageManager): Record { + const prismaCommand = (...args: string[]) => + getPackageExecutionCommand(packageManager, [PRISMA_PLATFORM_CLI_PACKAGE, ...args]); return { - "db:generate": "prisma generate", - "db:push": "prisma db push", - "db:migrate": "prisma migrate dev", - "db:seed": "prisma db seed", - } as const; + "contract:emit": prismaCommand("contract", "emit"), + "db:init": prismaCommand("db", "init"), + "db:update": prismaCommand("db", "update"), + "db:verify": prismaCommand("db", "verify"), + "migration:plan": prismaCommand("migration", "plan"), + migrate: prismaCommand("migrate"), + "migration:status": prismaCommand("migration", "status"), + "migration:show": prismaCommand("migration", "show"), + }; } -function getVersion(packageName: string): string | undefined { - return dependencyVersionMap[packageName as AvailableDependency]; +export function getComposerScriptMap(packageManager: PackageManager): Record { + const composerCommand = (subcommand: string, extraArgs: string[] = []) => + getPackageExecutionCommand(packageManager, [ + PRISMA_PLATFORM_CLI_PACKAGE, + "composer", + subcommand, + "module.ts", + ...extraArgs, + ]); + + return { + "composer:dev": composerCommand("dev"), + "composer:deploy": composerCommand("deploy"), + "composer:destroy": composerCommand("destroy", ["--production"]), + deploy: `${getRunScriptCommand(packageManager, "build")} && ${getRunScriptCommand( + packageManager, + "composer:deploy", + )}`, + "dev:composer": `${getRunScriptCommand(packageManager, "build")} && ${getRunScriptCommand( + packageManager, + "composer:dev", + )}`, + }; } function unique(items: string[]): string[] { @@ -57,43 +64,6 @@ function sortRecord(record: Record): Record { return Object.fromEntries(Object.entries(record).sort(([a], [b]) => a.localeCompare(b))); } -async function projectContainsText(projectDir: string, text: string): Promise { - const directories = [projectDir]; - - while (directories.length > 0) { - const currentDirectory = directories.pop(); - if (!currentDirectory) { - continue; - } - - const entries = await fs.readdir(currentDirectory, { withFileTypes: true }); - - for (const entry of entries) { - if (entry.name === "node_modules" || entry.name === ".git") { - continue; - } - - const entryPath = path.join(currentDirectory, entry.name); - - if (entry.isDirectory()) { - directories.push(entryPath); - continue; - } - - if (!entry.isFile() || !/\.(c|m)?[jt]sx?$/.test(entry.name)) { - continue; - } - - const content = await fs.readFile(entryPath, "utf8"); - if (content.includes(text)) { - return true; - } - } - } - - return false; -} - export async function addPackageDependency(opts: { dependencies?: string[]; devDependencies?: string[]; @@ -119,81 +89,53 @@ export async function addPackageDependency(opts: { } const pkgJson = await fs.readJson(pkgJsonPath); - - if (!pkgJson.dependencies) pkgJson.dependencies = {}; - if (!pkgJson.devDependencies) pkgJson.devDependencies = {}; - if (!pkgJson.scripts) pkgJson.scripts = {}; - - for (const pkgName of unique(dependencies)) { - const version = getVersion(pkgName); - if (version) { - pkgJson.dependencies[pkgName] = version; - } else { - console.warn(`Warning: Dependency ${pkgName} not found in version map.`); - } + pkgJson.dependencies ??= {}; + pkgJson.devDependencies ??= {}; + pkgJson.scripts ??= {}; + + for (const packageName of unique(dependencies)) { + const version = getDependencyVersion(packageName); + if (!version) throw new Error(`Dependency ${packageName} is missing from the version map.`); + pkgJson.dependencies[packageName] = version; } - - for (const pkgName of unique(devDependencies)) { - const version = getVersion(pkgName); - if (version) { - pkgJson.devDependencies[pkgName] = version; - } else { - console.warn(`Warning: Dev dependency ${pkgName} not found in version map.`); - } + for (const packageName of unique(devDependencies)) { + const version = getDependencyVersion(packageName); + if (!version) throw new Error(`Dependency ${packageName} is missing from the version map.`); + pkgJson.devDependencies[packageName] = version; } - - for (const [pkgName, version] of Object.entries(customDependencies)) { - pkgJson.dependencies[pkgName] = version; + for (const [packageName, version] of Object.entries(customDependencies)) { + pkgJson.dependencies[packageName] = version; } - for (const [scriptName, command] of Object.entries(scripts)) { - if (scriptMode === "if-missing") { - if ( - typeof pkgJson.scripts[scriptName] !== "string" || - pkgJson.scripts[scriptName].trim().length === 0 - ) { - pkgJson.scripts[scriptName] = command; - } + if ( + scriptMode === "if-missing" && + typeof pkgJson.scripts[scriptName] === "string" && + pkgJson.scripts[scriptName].trim().length > 0 + ) { continue; } - pkgJson.scripts[scriptName] = command; } pkgJson.dependencies = sortRecord(pkgJson.dependencies); pkgJson.devDependencies = sortRecord(pkgJson.devDependencies); - - await fs.writeJson(pkgJsonPath, pkgJson, { - spaces: 2, - }); + pkgJson.scripts = sortRecord(pkgJson.scripts); + await fs.writeJson(pkgJsonPath, pkgJson, { spaces: 2 }); } export async function writePrismaDependencies( provider: DatabaseProvider, packageManager: PackageManager, + _authoring: AuthoringStyle, projectDir = process.cwd(), ): Promise { - const dependencies: string[] = ["@prisma/client"]; - const devDependencies: string[] = ["prisma"]; - dependencies.push(getDbPackages(provider, packageManager)); - if (provider === "sqlite") { - dependencies.push("@libsql/client"); - } - - if ( - requiresDotenvConfigImport(packageManager) || - (await projectContainsText(projectDir, "dotenv/config")) - ) { - dependencies.push("dotenv"); - } - - const prismaScriptMap = getPrismaScriptMap(packageManager); + const dependencies = [getDbPackages(provider)]; + if (provider === "mongo") dependencies.push("arktype", "mongodb"); await addPackageDependency({ dependencies, - devDependencies, - scripts: prismaScriptMap, - scriptMode: "if-missing", + devDependencies: ["@prisma/cli-engine", "@types/node"], + scripts: getPrismaScriptMap(packageManager), projectDir, }); } @@ -204,39 +146,46 @@ export async function writeCreateTemplateDependencies(opts: { projectDir?: string; }): Promise { const { template, packageManager, projectDir = process.cwd() } = opts; - const targets = getCreateTemplateDependencies(template, packageManager); - - for (const dependencyTarget of targets) { - const targetDirectory = path.join(projectDir, path.dirname(dependencyTarget.packageJsonPath)); + for (const target of getCreateTemplateDependencies(template, packageManager)) { await addPackageDependency({ - dependencies: dependencyTarget.dependencies, - devDependencies: dependencyTarget.devDependencies, - customDependencies: dependencyTarget.customDependencies, - projectDir: targetDirectory, + dependencies: target.dependencies, + devDependencies: target.devDependencies, + customDependencies: target.customDependencies, + scripts: getComposerScriptMap(packageManager), + projectDir: path.join(projectDir, path.dirname(target.packageJsonPath)), }); } + + const packageJsonPath = path.join(projectDir, "package.json"); + const packageJson = await fs.readJson(packageJsonPath); + const effectVersion = getDependencyVersion("effect"); + if (!effectVersion) throw new Error("Dependency effect is missing from the version map."); + + if (packageManager === "yarn") { + packageJson.resolutions = { ...packageJson.resolutions, effect: effectVersion }; + } else if (packageManager !== "pnpm") { + packageJson.overrides = { ...packageJson.overrides, effect: effectVersion }; + } + await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 }); } export async function installProjectDependencies( packageManager: PackageManager, projectDir = process.cwd(), - options: { - verbose?: boolean; - } = {}, + options: { verbose?: boolean } = {}, ): Promise { - const verbose = options.verbose === true; const installCommand = getInstallArgs(packageManager); const env = packageManager === "yarn" ? { - ...process.env, YARN_ENABLE_IMMUTABLE_INSTALLS: "false", } : undefined; + await execa(installCommand.command, installCommand.args, { cwd: projectDir, env, - stdio: verbose ? "inherit" : "pipe", + stdio: options.verbose === true ? "inherit" : "pipe", }); } diff --git a/src/tasks/prisma-postgres.ts b/src/tasks/prisma-postgres.ts deleted file mode 100644 index 45392f0..0000000 --- a/src/tasks/prisma-postgres.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { execa } from "execa"; - -import type { PackageManager } from "../types"; -import { getPackageExecutionArgs, getPackageExecutionCommand } from "../utils/package-manager"; - -type CreateDbJsonPayload = { - success?: boolean; - error?: string; - message?: string; - connectionString?: string; - databaseUrl?: string; - claimUrl?: string; - claimURL?: string; -}; - -type PrismaPostgresResult = { - databaseUrl: string; - claimUrl?: string; -}; - -export const PRISMA_POSTGRES_TEMPORARY_NOTICE = - "Prisma Postgres is temporary for 24 hours. Claim this database before it expires using CLAIM_URL."; -const CREATE_DB_COMMAND_ARGS = ["create-db@latest", "--json"] as const; - -function parseCreateDbJson(rawOutput: string): CreateDbJsonPayload { - const trimmed = rawOutput.trim(); - if (!trimmed) { - throw new Error("create-db returned empty output."); - } - - const jsonCandidates = [trimmed]; - const firstBrace = trimmed.indexOf("{"); - const lastBrace = trimmed.lastIndexOf("}"); - if (firstBrace !== -1 && lastBrace > firstBrace) { - jsonCandidates.push(trimmed.slice(firstBrace, lastBrace + 1)); - } - - for (const candidate of jsonCandidates) { - try { - return JSON.parse(candidate) as CreateDbJsonPayload; - } catch { - // Continue trying candidates. - } - } - - throw new Error(`Unable to parse create-db JSON output: ${trimmed}`); -} - -function pickConnectionString(payload: CreateDbJsonPayload): string | undefined { - if (typeof payload.connectionString === "string" && payload.connectionString.length > 0) { - return payload.connectionString; - } - - if (typeof payload.databaseUrl === "string" && payload.databaseUrl.length > 0) { - return payload.databaseUrl; - } - - return undefined; -} - -function extractErrorMessage(payload: CreateDbJsonPayload, fallback: string): string { - if (typeof payload.message === "string" && payload.message.length > 0) { - return payload.message; - } - - if (typeof payload.error === "string" && payload.error.length > 0) { - return payload.error; - } - - return fallback; -} - -export async function provisionPrismaPostgres( - packageManager: PackageManager, - projectDir = process.cwd(), -): Promise { - const command = getPackageExecutionArgs(packageManager, [...CREATE_DB_COMMAND_ARGS]); - const commandString = getCreateDbCommand(packageManager); - - let stdout: string; - try { - const result = await execa(command.command, command.args, { - cwd: projectDir, - stdio: "pipe", - }); - stdout = result.stdout; - } catch (error) { - if (error instanceof Error && "stderr" in error) { - const stderr = String((error as { stderr?: string }).stderr ?? "").trim(); - const message = stderr.length > 0 ? stderr : error.message; - throw new Error(`Failed to run ${commandString}: ${message}`); - } - - throw error; - } - - const payload = parseCreateDbJson(stdout); - if (payload.success === false) { - throw new Error(extractErrorMessage(payload, "create-db reported failure.")); - } - - const databaseUrl = pickConnectionString(payload); - if (!databaseUrl) { - throw new Error("create-db did not return a connection string."); - } - - const claimUrl = - typeof payload.claimUrl === "string" && payload.claimUrl.length > 0 - ? payload.claimUrl - : typeof payload.claimURL === "string" && payload.claimURL.length > 0 - ? payload.claimURL - : undefined; - - return { - databaseUrl, - claimUrl, - }; -} - -export function getCreateDbCommand(packageManager: PackageManager): string { - return getPackageExecutionCommand(packageManager, [...CREATE_DB_COMMAND_ARGS]); -} diff --git a/src/tasks/setup-addons.ts b/src/tasks/setup-addons.ts deleted file mode 100644 index f72951f..0000000 --- a/src/tasks/setup-addons.ts +++ /dev/null @@ -1,635 +0,0 @@ -import { cancel, isCancel, log, multiselect, select, spinner } from "@clack/prompts"; -import { execa } from "execa"; - -import type { - AddonInstallScope, - CreateAddon, - CreateCommandInput, - DatabaseProvider, - ExtensionTarget, - PackageManager, - PrismaSkillName, -} from "../types"; -import { getPackageExecutionArgs } from "../utils/package-manager"; - -export type CreateAddonSetupContext = { - addons: CreateAddon[]; - scope: AddonInstallScope; - skills: PrismaSkillName[]; - skillsAgents: string[]; - mcpAgents: string[]; - extensionTargets: ExtensionTarget[]; -}; - -type AgentOption = { - value: string; - label: string; -}; - -const DEFAULT_ADDON_SCOPE: AddonInstallScope = "project"; -const DEFAULT_SKILLS_AGENTS = ["claude-code", "codex", "cursor"] as const; -const DEFAULT_MCP_AGENTS = ["claude-code", "codex", "cursor"] as const; -const DEFAULT_EXTENSION_TARGETS: ExtensionTarget[] = ["vscode", "cursor"]; -const PRISMA_MCP_SERVER = "https://mcp.prisma.io/mcp"; - -const ADDON_OPTIONS: Array<{ - value: CreateAddon; - label: string; - hint: string; -}> = [ - { - value: "skills", - label: "Skills", - hint: "Install curated Prisma skills to your selected coding agents", - }, - { - value: "mcp", - label: "MCP", - hint: "Configure Prisma MCP server in agent MCP config files", - }, - { - value: "extension", - label: "IDE Extension", - hint: "Install Prisma extension in selected IDEs (VS Code, Cursor, Windsurf)", - }, -]; - -const SKILLS_AGENT_OPTIONS: AgentOption[] = [ - { value: "cursor", label: "Cursor" }, - { value: "claude-code", label: "Claude Code" }, - { value: "cline", label: "Cline" }, - { value: "github-copilot", label: "GitHub Copilot" }, - { value: "codex", label: "Codex" }, - { value: "opencode", label: "OpenCode" }, - { value: "windsurf", label: "Windsurf" }, - { value: "goose", label: "Goose" }, - { value: "roo", label: "Roo Code" }, - { value: "kilo", label: "Kilo Code" }, - { value: "gemini-cli", label: "Gemini CLI" }, - { value: "antigravity", label: "Antigravity" }, - { value: "openhands", label: "OpenHands" }, - { value: "trae", label: "Trae" }, - { value: "amp", label: "Amp" }, - { value: "pi", label: "Pi" }, - { value: "qoder", label: "Qoder" }, - { value: "qwen-code", label: "Qwen Code" }, - { value: "kiro-cli", label: "Kiro CLI" }, - { value: "droid", label: "Droid" }, - { value: "command-code", label: "Command Code" }, - { value: "clawdbot", label: "Clawdbot" }, - { value: "zencoder", label: "Zencoder" }, - { value: "neovate", label: "Neovate" }, - { value: "mcpjam", label: "MCPJam" }, -]; - -const MCP_AGENT_OPTIONS: AgentOption[] = [ - { value: "claude-code", label: "Claude Code" }, - { value: "codex", label: "Codex" }, - { value: "cursor", label: "Cursor" }, - { value: "vscode", label: "VS Code" }, - { value: "github-copilot-cli", label: "GitHub Copilot CLI" }, - { value: "opencode", label: "OpenCode" }, - { value: "gemini-cli", label: "Gemini CLI" }, - { value: "goose", label: "Goose" }, - { value: "zed", label: "Zed" }, - { value: "antigravity", label: "Antigravity" }, - { value: "cline", label: "Cline VS Code Extension" }, - { value: "cline-cli", label: "Cline CLI" }, - { value: "claude-desktop", label: "Claude Desktop" }, - { value: "mcporter", label: "MCPorter" }, -]; - -const SHARED_PRISMA_SKILLS: PrismaSkillName[] = [ - "prisma-cli", - "prisma-client-api", - "prisma-database-setup", - "prisma-upgrade-v7", -]; - -type SkillOption = { - value: PrismaSkillName; - label: string; - hint: string; -}; - -function getAvailablePrismaSkills(provider: DatabaseProvider): PrismaSkillName[] { - const skills: PrismaSkillName[] = [...SHARED_PRISMA_SKILLS, "prisma-compute"]; - - if (provider === "postgresql") { - return [...skills, "prisma-postgres"]; - } - - return skills; -} - -function getSkillOptions(provider: DatabaseProvider): SkillOption[] { - const available = getAvailablePrismaSkills(provider); - const options: Record = { - "prisma-cli": { - value: "prisma-cli", - label: "prisma-cli", - hint: "Prisma CLI reference", - }, - "prisma-client-api": { - value: "prisma-client-api", - label: "prisma-client-api", - hint: "Prisma Client query patterns", - }, - "prisma-compute": { - value: "prisma-compute", - label: "prisma-compute", - hint: "Prisma Compute deploy and hosting workflows", - }, - "prisma-database-setup": { - value: "prisma-database-setup", - label: "prisma-database-setup", - hint: "Database provider setup guides", - }, - "prisma-upgrade-v7": { - value: "prisma-upgrade-v7", - label: "prisma-upgrade-v7", - hint: "v6 to v7 migration guide", - }, - "prisma-postgres": { - value: "prisma-postgres", - label: "prisma-postgres", - hint: "Prisma Postgres workflows", - }, - }; - - return available.map((skill) => options[skill]); -} - -function collectAddonsFromInput(input: CreateCommandInput): CreateAddon[] { - const addons: CreateAddon[] = []; - - if (input.skills === true) { - addons.push("skills"); - } - if (input.mcp === true) { - addons.push("mcp"); - } - if (input.extension === true) { - addons.push("extension"); - } - - return uniqueValues(addons); -} - -const EXTENSION_TARGET_OPTIONS: Array<{ - value: ExtensionTarget; - label: string; - hint: string; -}> = [ - { - value: "vscode", - label: "VS Code", - hint: "Uses the `code` CLI", - }, - { - value: "cursor", - label: "Cursor", - hint: "Uses the `cursor` CLI", - }, - { - value: "windsurf", - label: "Windsurf", - hint: "Uses the `windsurf` CLI", - }, -]; - -function uniqueValues(values: T[]): T[] { - return Array.from(new Set(values)); -} - -function getRecommendedPrismaSkills( - provider: DatabaseProvider, - shouldUsePrismaPostgres: boolean, - shouldUseComputeDeploy: boolean, -): PrismaSkillName[] { - const skills = [...SHARED_PRISMA_SKILLS]; - - if (provider === "postgresql" && shouldUsePrismaPostgres) { - skills.push("prisma-postgres"); - } - - if (shouldUseComputeDeploy) { - skills.push("prisma-compute"); - } - - return uniqueValues(skills); -} - -async function promptForAddons(): Promise { - const selectedAddons = await multiselect({ - message: "Select add-ons (optional)", - options: ADDON_OPTIONS, - required: false, - }); - - if (isCancel(selectedAddons)) { - cancel("Operation cancelled."); - return undefined; - } - - return uniqueValues(selectedAddons as CreateAddon[]); -} - -async function promptForAddonScope(): Promise { - const selectedScope = await select({ - message: "Where should add-ons write config?", - initialValue: DEFAULT_ADDON_SCOPE, - options: [ - { - value: "project", - label: "Project", - hint: "Recommended for teams (checked into the project when applicable)", - }, - { - value: "global", - label: "Global", - hint: "Personal machine-level setup", - }, - ], - }); - - if (isCancel(selectedScope)) { - cancel("Operation cancelled."); - return undefined; - } - - return selectedScope; -} - -async function promptForPrismaSkills( - provider: DatabaseProvider, - recommendedSkills: PrismaSkillName[], -): Promise { - const options = getSkillOptions(provider); - const optionValues = new Set(options.map((option) => option.value)); - const selectedSkills = await multiselect({ - message: "Select Prisma skills", - options, - required: false, - initialValues: recommendedSkills.filter((skill) => optionValues.has(skill)), - }); - - if (isCancel(selectedSkills)) { - cancel("Operation cancelled."); - return undefined; - } - - return uniqueValues(selectedSkills as PrismaSkillName[]); -} - -async function promptForSkillsAgents(): Promise { - const selectedAgents = await multiselect({ - message: "Select agents for skills", - options: SKILLS_AGENT_OPTIONS, - required: false, - initialValues: [...DEFAULT_SKILLS_AGENTS], - }); - - if (isCancel(selectedAgents)) { - cancel("Operation cancelled."); - return undefined; - } - - return uniqueValues(selectedAgents as string[]); -} - -async function promptForMcpAgents(): Promise { - const selectedAgents = await multiselect({ - message: "Select agents for MCP", - options: MCP_AGENT_OPTIONS, - required: false, - initialValues: [...DEFAULT_MCP_AGENTS], - }); - - if (isCancel(selectedAgents)) { - cancel("Operation cancelled."); - return undefined; - } - - return uniqueValues(selectedAgents as string[]); -} - -async function promptForExtensionTargets(): Promise { - const selectedTargets = await multiselect({ - message: "Select IDEs for extension install", - options: EXTENSION_TARGET_OPTIONS, - required: false, - initialValues: DEFAULT_EXTENSION_TARGETS, - }); - - if (isCancel(selectedTargets)) { - cancel("Operation cancelled."); - return undefined; - } - - return uniqueValues(selectedTargets as ExtensionTarget[]); -} - -export async function collectCreateAddonSetupContext( - input: CreateCommandInput, - options: { - useDefaults: boolean; - provider: DatabaseProvider; - shouldUsePrismaPostgres: boolean; - shouldUseComputeDeploy: boolean; - }, -): Promise { - const hasExplicitAddonSelection = - input.skills !== undefined || input.mcp !== undefined || input.extension !== undefined; - const selectedFromInput = collectAddonsFromInput(input); - const selectedAddons = - selectedFromInput.length > 0 - ? selectedFromInput - : hasExplicitAddonSelection - ? [] - : options.useDefaults - ? [] - : await promptForAddons(); - if (!selectedAddons) { - return undefined; - } - - const addons = uniqueValues(selectedAddons); - if (addons.length === 0) { - return null; - } - - const needsScopedConfig = addons.includes("skills") || addons.includes("mcp"); - const scope = needsScopedConfig - ? options.useDefaults - ? DEFAULT_ADDON_SCOPE - : await promptForAddonScope() - : DEFAULT_ADDON_SCOPE; - if (!scope) { - return undefined; - } - - const recommendedSkills = getRecommendedPrismaSkills( - options.provider, - options.shouldUsePrismaPostgres, - options.shouldUseComputeDeploy, - ); - const skills = !addons.includes("skills") - ? [] - : options.useDefaults - ? recommendedSkills - : await promptForPrismaSkills(options.provider, recommendedSkills); - if (!skills) { - return undefined; - } - - const skillsAgents = !addons.includes("skills") - ? [] - : options.useDefaults - ? [...DEFAULT_SKILLS_AGENTS] - : await promptForSkillsAgents(); - if (!skillsAgents) { - return undefined; - } - - const mcpAgents = !addons.includes("mcp") - ? [] - : options.useDefaults - ? [...DEFAULT_MCP_AGENTS] - : await promptForMcpAgents(); - if (!mcpAgents) { - return undefined; - } - - const extensionTargets = !addons.includes("extension") - ? [] - : options.useDefaults - ? [...DEFAULT_EXTENSION_TARGETS] - : await promptForExtensionTargets(); - if (!extensionTargets) { - return undefined; - } - - return { - addons, - scope, - skills, - skillsAgents: uniqueValues(skillsAgents), - mcpAgents: uniqueValues(mcpAgents), - extensionTargets: uniqueValues(extensionTargets), - }; -} - -async function executeExternalCommand(params: { - command: string; - args: string[]; - cwd: string; - verbose: boolean; -}): Promise { - await execa(params.command, params.args, { - cwd: params.cwd, - stdio: params.verbose ? "inherit" : "pipe", - env: { - ...process.env, - CI: "true", - }, - }); -} - -async function installSkillsAddon(params: { - packageManager: PackageManager; - projectDir: string; - scope: AddonInstallScope; - skills: PrismaSkillName[]; - agents: string[]; - verbose: boolean; -}): Promise { - if (params.agents.length === 0 || params.skills.length === 0) { - return "Skipped skills addon because no skills or agents were selected."; - } - - const scopeArgs = params.scope === "global" ? ["-g"] : []; - const skillArgs = params.skills.flatMap((skill) => ["-s", skill]); - const agentArgs = params.agents.flatMap((agent) => ["-a", agent]); - const commandArgs = [ - "skills@latest", - "add", - "prisma/skills", - ...scopeArgs, - ...skillArgs, - ...agentArgs, - "-y", - ]; - const execution = getPackageExecutionArgs(params.packageManager, commandArgs); - - try { - await executeExternalCommand({ - command: execution.command, - args: execution.args, - cwd: params.projectDir, - verbose: params.verbose, - }); - return; - } catch (error) { - return `Skills addon failed: ${error instanceof Error ? error.message : String(error)}`; - } -} - -async function installMcpAddon(params: { - packageManager: PackageManager; - projectDir: string; - scope: AddonInstallScope; - agents: string[]; - verbose: boolean; -}): Promise { - if (params.agents.length === 0) { - return "Skipped MCP addon because no agents were selected."; - } - - const scopeArgs = params.scope === "global" ? ["-g"] : []; - const agentArgs = params.agents.flatMap((agent) => ["-a", agent]); - const commandArgs = [ - "add-mcp@latest", - PRISMA_MCP_SERVER, - ...scopeArgs, - ...agentArgs, - "--name", - "prisma", - "--gitignore", - "-y", - ]; - const execution = getPackageExecutionArgs(params.packageManager, commandArgs); - - try { - await executeExternalCommand({ - command: execution.command, - args: execution.args, - cwd: params.projectDir, - verbose: params.verbose, - }); - return; - } catch (error) { - return `MCP addon failed: ${error instanceof Error ? error.message : String(error)}`; - } -} - -function getExtensionInstallBinary(target: ExtensionTarget): string { - switch (target) { - case "vscode": - return "code"; - case "cursor": - return "cursor"; - case "windsurf": - return "windsurf"; - default: { - const exhaustiveCheck: never = target; - throw new Error(`Unsupported extension target: ${String(exhaustiveCheck)}`); - } - } -} - -async function installExtensionAddon(params: { - projectDir: string; - verbose: boolean; - targets: ExtensionTarget[]; -}): Promise { - if (params.targets.length === 0) { - return ["Skipped extension addon because no IDE targets were selected."]; - } - - const warnings: string[] = []; - - for (const target of params.targets) { - const binary = getExtensionInstallBinary(target); - - try { - await executeExternalCommand({ - command: binary, - args: ["--version"], - cwd: params.projectDir, - verbose: false, - }); - } catch { - warnings.push( - `Skipped ${target} extension install because the \`${binary}\` CLI is not available.`, - ); - continue; - } - - try { - await executeExternalCommand({ - command: binary, - args: ["--install-extension", "Prisma.prisma", "--force"], - cwd: params.projectDir, - verbose: params.verbose, - }); - } catch (error) { - warnings.push( - `${target} extension install failed: ${ - error instanceof Error ? error.message : String(error) - }`, - ); - } - } - - return warnings; -} - -export async function executeCreateAddonSetupContext(params: { - context: CreateAddonSetupContext; - packageManager: PackageManager; - projectDir: string; - verbose: boolean; -}): Promise { - const { context, packageManager, projectDir, verbose } = params; - const addonSpinner = spinner(); - addonSpinner.start("Applying selected add-ons..."); - - const warnings: string[] = []; - - if (context.addons.includes("skills")) { - const warning = await installSkillsAddon({ - packageManager, - projectDir, - scope: context.scope, - skills: context.skills, - agents: context.skillsAgents, - verbose, - }); - if (warning) { - warnings.push(warning); - } - } - - if (context.addons.includes("mcp")) { - const warning = await installMcpAddon({ - packageManager, - projectDir, - scope: context.scope, - agents: context.mcpAgents, - verbose, - }); - if (warning) { - warnings.push(warning); - } - } - - if (context.addons.includes("extension")) { - const extensionWarnings = await installExtensionAddon({ - projectDir, - verbose, - targets: context.extensionTargets, - }); - warnings.push(...extensionWarnings); - } - - if (warnings.length > 0) { - addonSpinner.stop("Add-ons applied with warnings."); - for (const warning of warnings) { - log.warn(warning); - } - return; - } - - addonSpinner.stop("Add-ons applied."); -} diff --git a/src/tasks/setup-prisma.ts b/src/tasks/setup-prisma.ts index 9a8bcc7..bc9556b 100644 --- a/src/tasks/setup-prisma.ts +++ b/src/tasks/setup-prisma.ts @@ -1,894 +1,395 @@ -import { cancel, confirm, isCancel, log, select, spinner } from "@clack/prompts"; +import { cancel, confirm, isCancel, log, note, outro, select, spinner } from "@clack/prompts"; import { execa } from "execa"; import fs from "fs-extra"; import path from "node:path"; -import { escapeRegExp } from "../utils/regexp"; -import { installProjectDependencies, writePrismaDependencies } from "./install"; -import { - getCreateDbCommand, - PRISMA_POSTGRES_TEMPORARY_NOTICE, - provisionPrismaPostgres, -} from "./prisma-postgres"; +import { PRISMA_PLATFORM_CLI_PACKAGE } from "../constants/dependencies"; +import { scaffoldCreateSharedTemplates } from "../templates/render-create-template"; import { + AuthoringStyleSchema, DatabaseProviderSchema, PackageManagerSchema, + type AuthoringStyle, + type CreateTemplate, type DatabaseProvider, - type PrismaSetupCommandInput, type PackageManager, - type SchemaPreset, + type PrismaSetupCommandInput, } from "../types"; import { detectPackageManager, getInstallCommand, - getPrismaCliArgs, - getRunScriptArgs, + getPackageExecutionArgs, getRunScriptCommand, } from "../utils/package-manager"; +import { deployWithComposer, type ComposerDeployResult } from "./deploy-with-composer"; +import { installProjectDependencies, writePrismaDependencies } from "./install"; -type EnvWriteMode = "keep-existing" | "upsert"; +const DEFAULT_DATABASE_PROVIDER: DatabaseProvider = "postgres"; +const DEFAULT_AUTHORING: AuthoringStyle = "psl"; + +type NextStep = { + command: string; + description: string; +}; type PrismaSetupRunOptions = { - prependNextSteps?: string[]; + prependNextSteps?: NextStep[]; projectDir?: string; + projectName?: string; + template?: CreateTemplate; + createdProjectPath?: string; includeDevNextStep?: boolean; - includeMigrationAndSeedNextSteps?: boolean; -}; - -type PrismaPostgresProvisionResult = { - databaseUrl?: string; - claimUrl?: string; - warning?: string; -}; - -type PrismaGenerateResult = { - didGenerateClient: boolean; - warning?: string; + progressSpinner?: ReturnType; }; export type PrismaSetupContext = { projectDir: string; verbose: boolean; - shouldGenerate: boolean; databaseProvider: DatabaseProvider; - schemaPreset: SchemaPreset; - databaseUrl?: string; - shouldUsePrismaPostgres: boolean; + authoring: AuthoringStyle; packageManager: PackageManager; - shouldInstall: boolean; - shouldMigrateAndSeed: boolean; + shouldDeploy: boolean; + shouldPromptForWorkspace: boolean; + workspace?: string; }; -export type PrismaSetupInitialContext = Omit< - PrismaSetupContext, - "shouldUsePrismaPostgres" | "shouldMigrateAndSeed" ->; - -type FinalizePrismaOptions = { - provider: DatabaseProvider; - databaseUrl?: string; - claimUrl?: string; - projectDir?: string; -}; - -const DEFAULT_DATABASE_PROVIDER: DatabaseProvider = "postgresql"; -const DEFAULT_SCHEMA_PRESET: SchemaPreset = "empty"; -const DEFAULT_PRISMA_POSTGRES = true; -const DEFAULT_INSTALL = true; -const DEFAULT_GENERATE = true; -const DEFAULT_MIGRATE_AND_SEED = true; -const PRISMA_POSTGRES_MIGRATION_DELAY_MS = 2000; - -const requiredPrismaFileGroups = [ - ["prisma/schema.prisma", "packages/db/prisma/schema.prisma"], - ["prisma/seed.ts", "packages/db/prisma/seed.ts"], - ["prisma.config.ts", "packages/db/prisma.config.ts"], - [ - "src/lib/prisma.ts", - "src/lib/prisma.server.ts", - "src/lib/server/prisma.ts", - "server/utils/prisma.ts", - "packages/db/src/client.ts", - ], -] as const; - -async function resolvePrismaProjectDir(projectDir: string): Promise { - const monorepoDbDir = path.join(projectDir, "packages/db"); - if (await fs.pathExists(path.join(monorepoDbDir, "prisma/schema.prisma"))) { - return monorepoDbDir; - } - - return projectDir; -} - async function promptForDatabaseProvider(): Promise { const databaseProvider = await select({ message: "Select your database", initialValue: DEFAULT_DATABASE_PROVIDER, options: [ - { value: "postgresql", label: "PostgreSQL", hint: "Default" }, - { value: "mysql", label: "MySQL" }, - { value: "sqlite", label: "SQLite" }, - { value: "sqlserver", label: "SQL Server" }, - { value: "cockroachdb", label: "CockroachDB" }, + { value: "postgres", label: "PostgreSQL", hint: "Prisma Postgres with Composer" }, + { value: "mongo", label: "MongoDB", hint: "Connect an existing MongoDB database" }, ], }); - if (isCancel(databaseProvider)) { cancel("Operation cancelled."); - return undefined; + return; } - return DatabaseProviderSchema.parse(databaseProvider); } -function getPackageManagerHint( - option: PackageManager, - detected: PackageManager, -): string | undefined { - if (option === detected) { - return "Detected"; - } - - if (option === "bun") { - return "Fast runtime + package manager"; - } - - if (option === "deno") { - return "Runtime + package manager"; +async function promptForAuthoringStyle(): Promise { + const authoring = await select({ + message: "Choose contract authoring style", + initialValue: DEFAULT_AUTHORING, + options: [ + { value: "psl", label: "PSL", hint: "Prisma schema syntax" }, + { value: "typescript", label: "TypeScript", hint: "TypeScript contract builder" }, + ], + }); + if (isCancel(authoring)) { + cancel("Operation cancelled."); + return; } + return AuthoringStyleSchema.parse(authoring); +} - return undefined; +function getPackageManagerHint(option: PackageManager, detected: PackageManager) { + const hints = { + npm: "Node.js default", + pnpm: "Fast, disk-efficient package manager", + yarn: "Yarn package manager", + bun: "Fast runtime and package manager", + } satisfies Record; + return option === detected ? `Detected; ${hints[option]}` : hints[option]; } async function promptForPackageManager( - detectedPackageManager: PackageManager, + detected: PackageManager, ): Promise { const packageManager = await select({ message: "Choose package manager", - initialValue: detectedPackageManager, - options: [ - { - value: "npm", - label: "npm", - hint: getPackageManagerHint("npm", detectedPackageManager), - }, - { - value: "pnpm", - label: "pnpm", - hint: getPackageManagerHint("pnpm", detectedPackageManager), - }, - { - value: "yarn", - label: "yarn", - hint: getPackageManagerHint("yarn", detectedPackageManager), - }, - { - value: "bun", - label: "bun", - hint: getPackageManagerHint("bun", detectedPackageManager), - }, - { - value: "deno", - label: "deno", - hint: getPackageManagerHint("deno", detectedPackageManager), - }, - ], + initialValue: detected, + options: (["npm", "pnpm", "yarn", "bun"] as const).map((value) => ({ + value, + label: value, + hint: getPackageManagerHint(value, detected), + })), }); - if (isCancel(packageManager)) { cancel("Operation cancelled."); - return undefined; + return; } - return PackageManagerSchema.parse(packageManager); } -async function promptForDependencyInstall( - packageManager: PackageManager, -): Promise { - const installCommand = getInstallCommand(packageManager); - const shouldInstall = await confirm({ - message: `Install dependencies now with ${installCommand}?`, - initialValue: true, - }); - - if (isCancel(shouldInstall)) { - cancel("Operation cancelled."); - return undefined; - } - - return Boolean(shouldInstall); -} - -async function promptForMigrateAndSeed(): Promise { - const shouldMigrateAndSeed = await confirm({ - message: "Run an initial migration and seed your database now?", - initialValue: DEFAULT_MIGRATE_AND_SEED, - }); - - if (isCancel(shouldMigrateAndSeed)) { - cancel("Operation cancelled."); - return undefined; - } - - return Boolean(shouldMigrateAndSeed); -} - -async function promptForPrismaPostgres(): Promise { - const shouldUsePrismaPostgres = await confirm({ - message: "Use Prisma Postgres and write DATABASE_URL automatically?", +async function promptForDeployment(): Promise { + const shouldDeploy = await confirm({ + message: "Deploy to Prisma now?", initialValue: true, }); - - if (isCancel(shouldUsePrismaPostgres)) { + if (isCancel(shouldDeploy)) { cancel("Operation cancelled."); - return undefined; - } - - return Boolean(shouldUsePrismaPostgres); -} - -function getCommandErrorMessage(error: unknown): string { - if (error instanceof Error && "stderr" in error) { - const stderr = String((error as { stderr?: string }).stderr ?? "").trim(); - if (stderr.length > 0) { - return stderr; - } + return; } - - return error instanceof Error ? error.message : String(error); + return Boolean(shouldDeploy); } export async function collectPrismaSetupContext( input: PrismaSetupCommandInput, - options: { - projectDir?: string; - defaultSchemaPreset?: SchemaPreset; - skipPrismaPostgresProvisioning?: boolean; - skipMigrateAndSeedPrompt?: boolean; - } = {}, + options: { projectDir?: string } = {}, ): Promise { - const initialContext = await collectPrismaSetupInitialContext(input, options); - if (!initialContext) { - return; - } - - return completePrismaSetupContext(input, initialContext, { - useComputePostgres: options.skipPrismaPostgresProvisioning, - skipMigrateAndSeedPrompt: options.skipMigrateAndSeedPrompt, - }); -} - -export async function collectPrismaSetupInitialContext( - input: PrismaSetupCommandInput, - options: { - projectDir?: string; - defaultSchemaPreset?: SchemaPreset; - } = {}, -): Promise { const projectDir = path.resolve(options.projectDir ?? process.cwd()); const useDefaults = input.yes === true; - const verbose = input.verbose === true; - const shouldGenerate = input.generate ?? DEFAULT_GENERATE; const databaseProvider = input.provider ?? (useDefaults ? DEFAULT_DATABASE_PROVIDER : await promptForDatabaseProvider()); - if (!databaseProvider) { - return; - } + if (!databaseProvider) return; - const schemaPreset = input.schemaPreset ?? options.defaultSchemaPreset ?? DEFAULT_SCHEMA_PRESET; + const authoring = + input.authoring ?? (useDefaults ? DEFAULT_AUTHORING : await promptForAuthoringStyle()); + if (!authoring) return; - const databaseUrl = input.databaseUrl; const detectedPackageManager = await detectPackageManager(projectDir); const packageManager = input.packageManager ?? (useDefaults ? detectedPackageManager : await promptForPackageManager(detectedPackageManager)); - if (!packageManager) { - return; - } + if (!packageManager) return; - const shouldInstall = - input.install ?? - (useDefaults ? DEFAULT_INSTALL : await promptForDependencyInstall(packageManager)); - if (shouldInstall === undefined) { - return; - } + const shouldDeploy = input.deploy ?? (useDefaults ? false : await promptForDeployment()); + if (shouldDeploy === undefined) return; return { projectDir, - verbose, - shouldGenerate, + verbose: input.verbose === true, databaseProvider, - schemaPreset, - databaseUrl, + authoring, packageManager, - shouldInstall, + shouldDeploy, + shouldPromptForWorkspace: !useDefaults, + ...(input.workspace ? { workspace: input.workspace } : {}), }; } -export async function completePrismaSetupContext( - input: PrismaSetupCommandInput, - context: PrismaSetupInitialContext, - options: { - useComputePostgres?: boolean; - skipMigrateAndSeedPrompt?: boolean; - } = {}, -): Promise { - const useDefaults = input.yes === true; - let shouldUsePrismaPostgres = false; - const shouldUseComputePostgres = - context.databaseProvider === "postgresql" && - !context.databaseUrl && - options.useComputePostgres === true; - - if ( - context.databaseProvider === "postgresql" && - !context.databaseUrl && - !shouldUseComputePostgres - ) { - const prismaPostgresChoice = - input.prismaPostgres ?? - (useDefaults ? DEFAULT_PRISMA_POSTGRES : await promptForPrismaPostgres()); - if (prismaPostgresChoice === undefined) { - return; - } - - shouldUsePrismaPostgres = prismaPostgresChoice; - } - - // Migrate + seed needs installed deps and a generated client. - const canMigrateAndSeed = - context.shouldInstall && - context.shouldGenerate && - !(shouldUseComputePostgres && options.skipMigrateAndSeedPrompt); - const shouldMigrateAndSeed = !canMigrateAndSeed - ? false - : (input.migrateAndSeed ?? - (useDefaults ? DEFAULT_MIGRATE_AND_SEED : await promptForMigrateAndSeed())); - if (shouldMigrateAndSeed === undefined) { - return; +function getCommandErrorMessage(error: unknown): string { + if (error instanceof Error && "stderr" in error) { + const stderr = String((error as { stderr?: string }).stderr ?? "").trim(); + if (stderr) return stderr; } - - return { - ...context, - shouldUsePrismaPostgres, - shouldMigrateAndSeed, - }; + return error instanceof Error ? error.message : String(error); } -function getDefaultDatabaseUrl(provider: DatabaseProvider): string { - switch (provider) { - case "postgresql": - return "postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"; - case "cockroachdb": - return "postgresql://johndoe:randompassword@localhost:26257/mydb?schema=public"; - case "mysql": - return "mysql://johndoe:randompassword@localhost:3306/mydb"; - case "sqlite": - return "file:./dev.db"; - case "sqlserver": - return "sqlserver://localhost:1433;database=mydb;user=SA;password=randompassword;"; - default: { - const exhaustiveCheck: never = provider; - throw new Error(`Unsupported provider: ${String(exhaustiveCheck)}`); - } - } +function getContractPath(authoring: AuthoringStyle) { + return `src/prisma/contract${authoring === "typescript" ? ".ts" : ".prisma"}`; } -function escapeEnvValue(value: string): string { - if (/[\r\n]/.test(value)) { - throw new Error("Environment variable values must be single-line."); - } - - return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"'); +function getInitTarget(provider: DatabaseProvider): "postgres" | "mongodb" { + return provider === "mongo" ? "mongodb" : "postgres"; } -function hasEnvVar(content: string, envVarName: string): boolean { - const escapedName = escapeRegExp(envVarName); - return new RegExp(`(^|\\n)\\s*${escapedName}\\s*=`).test(content); +function getPrismaCliInvocation(packageManager: PackageManager, args: string[]) { + return getPackageExecutionArgs(packageManager, [PRISMA_PLATFORM_CLI_PACKAGE, ...args]); } -function hasEnvComment(content: string, comment: string): boolean { - const escapedComment = escapeRegExp(comment); - return new RegExp(`(^|\\n)\\s*#\\s*${escapedComment}\\s*(?=\\n|$)`).test(content); +async function runPrismaInit(context: PrismaSetupContext, projectDir: string): Promise { + const args = [ + "orm", + "init", + "--yes", + "--no-interactive", + "--target", + getInitTarget(context.databaseProvider), + "--authoring", + context.authoring, + "--schema-path", + getContractPath(context.authoring), + "--skip-install", + "--skip-skills", + ]; + const invocation = getPrismaCliInvocation(context.packageManager, args); + if (context.verbose) log.step(`Running ${[invocation.command, ...invocation.args].join(" ")}`); + await execa(invocation.command, invocation.args, { + cwd: projectDir, + stdio: context.verbose ? "inherit" : "pipe", + env: { ...process.env, CI: "1" }, + }); } -async function ensureEnvVarInEnv( - projectDir: string, - envVarName: string, - envVarValue: string, - opts: { - mode: EnvWriteMode; - comment?: string; - }, -): Promise { - const envPath = path.join(projectDir, ".env"); - const envLine = `${envVarName}="${escapeEnvValue(envVarValue)}"`; - - if (!(await fs.pathExists(envPath))) { - const content = opts.comment ? `# ${opts.comment}\n${envLine}\n` : `${envLine}\n`; - await fs.writeFile(envPath, content, "utf8"); - return; - } - - const existingContent = await fs.readFile(envPath, "utf8"); - if (hasEnvVar(existingContent, envVarName)) { - if (opts.mode === "keep-existing") { - return; - } - - const escapedName = escapeRegExp(envVarName); - const lineRegex = new RegExp(`(^|\\n)\\s*${escapedName}\\s*=.*(?=\\n|$)`, "gm"); - const updatedContent = existingContent.replace(lineRegex, `$1${envLine}`); - if (updatedContent === existingContent) { - return; - } - - await fs.writeFile(envPath, updatedContent, "utf8"); - return; - } - - const separator = existingContent.endsWith("\n") ? "" : "\n"; - const commentLine = opts.comment ? `\n# ${opts.comment}\n` : "\n"; - const insertion = `${separator}${commentLine}${envLine}\n`; - await fs.appendFile(envPath, insertion, "utf8"); +async function ensureGitignoreEntry(projectDir: string, entry: string): Promise { + const gitignorePath = path.join(projectDir, ".gitignore"); + const existing = (await fs.pathExists(gitignorePath)) + ? await fs.readFile(gitignorePath, "utf8") + : ""; + const lines = existing.split(/\r?\n/).map((line) => line.trim()); + if (lines.includes(entry) || lines.includes(`/${entry}`)) return; + const separator = existing.length > 0 && !existing.endsWith("\n") ? "\n" : ""; + await fs.writeFile(gitignorePath, `${existing}${separator}${entry}\n`, "utf8"); } -async function ensureEnvComment(projectDir: string, comment: string): Promise { +async function ensureMongoEnvironment(projectDir: string): Promise { const envPath = path.join(projectDir, ".env"); - const commentLine = `# ${comment}`; - if (!(await fs.pathExists(envPath))) { - await fs.writeFile(envPath, `${commentLine}\n`, "utf8"); - return; - } - - const existingContent = await fs.readFile(envPath, "utf8"); - if (hasEnvComment(existingContent, comment)) { - return; + await fs.writeFile( + envPath, + 'DATABASE_URL="mongodb://localhost:27017/mydb?replicaSet=rs0&directConnection=true"\n', + "utf8", + ); } - - const separator = existingContent.endsWith("\n") ? "" : "\n"; - await fs.appendFile(envPath, `${separator}${commentLine}\n`, "utf8"); -} - -function hasGitignoreEntry(content: string, entry: string): boolean { - const escapedEntry = escapeRegExp(entry); - const escapedWithLeadingSlash = escapeRegExp(`/${entry}`); - const escapedWithTrailingSlash = escapeRegExp(`${entry}/`); - const escapedWithLeadingAndTrailingSlash = escapeRegExp(`/${entry}/`); - return new RegExp( - `(^|\\n)\\s*(?:${escapedEntry}|${escapedWithLeadingSlash}|${escapedWithTrailingSlash}|${escapedWithLeadingAndTrailingSlash})\\s*(?=\\n|$)`, - ).test(content); + await ensureGitignoreEntry(projectDir, ".env"); } -async function ensureGitignoreEntry(projectDir: string, entry: string): Promise { - const gitignorePath = path.join(projectDir, ".gitignore"); - - if (!(await fs.pathExists(gitignorePath))) { - await fs.writeFile(gitignorePath, `${entry}\n`, "utf8"); - return; +async function ensureComposerTypeScriptOptions(projectDir: string): Promise { + const tsconfigPath = path.join(projectDir, "tsconfig.json"); + const tsconfig = await fs.readFile(tsconfigPath, "utf8"); + const additions: string[] = []; + if (!/"allowImportingTsExtensions"\s*:/.test(tsconfig)) { + additions.push(' "allowImportingTsExtensions": true,'); } - - const existingContent = await fs.readFile(gitignorePath, "utf8"); - if (hasGitignoreEntry(existingContent, entry)) { - return; + if (!/"noEmit"\s*:/.test(tsconfig)) { + additions.push(' "noEmit": true,'); } + if (additions.length === 0) return; - const separator = existingContent.endsWith("\n") ? "" : "\n"; - await fs.appendFile(gitignorePath, `${separator}${entry}\n`, "utf8"); -} - -async function ensureRequiredPrismaFiles(projectDir: string): Promise { - const missingFiles: string[] = []; - - for (const candidates of requiredPrismaFileGroups) { - let foundCandidate = false; - - for (const relativePath of candidates) { - const absolutePath = path.join(projectDir, relativePath); - if (await fs.pathExists(absolutePath)) { - foundCandidate = true; - break; - } - } - - if (!foundCandidate) { - missingFiles.push(candidates.join(" or ")); - } - } - - if (missingFiles.length > 0) { - throw new Error(`Template is missing required Prisma files: ${missingFiles.join(", ")}`); + const updated = tsconfig.replace( + /"compilerOptions"\s*:\s*\{/, + (match) => `${match}\n${additions.join("\n")}`, + ); + if (updated === tsconfig) { + throw new Error("tsconfig.json is missing compilerOptions."); } + await fs.writeFile(tsconfigPath, updated, "utf8"); } -async function finalizePrismaFiles(options: FinalizePrismaOptions): Promise { - const projectDir = options.projectDir ?? process.cwd(); - const prismaProjectDir = await resolvePrismaProjectDir(projectDir); - - await ensureRequiredPrismaFiles(projectDir); - const generatedDir = (await fs.pathExists(path.join(prismaProjectDir, "server/utils/prisma.ts"))) - ? "server/generated" - : "src/generated"; - - const databaseUrl = options.databaseUrl ?? getDefaultDatabaseUrl(options.provider); - await ensureEnvVarInEnv(prismaProjectDir, "DATABASE_URL", databaseUrl, { - mode: options.databaseUrl ? "upsert" : "keep-existing", - comment: "Added by create-prisma", - }); - - if (options.claimUrl) { - await ensureEnvVarInEnv(prismaProjectDir, "CLAIM_URL", options.claimUrl, { - mode: "upsert", - comment: PRISMA_POSTGRES_TEMPORARY_NOTICE, - }); - await ensureEnvComment(prismaProjectDir, PRISMA_POSTGRES_TEMPORARY_NOTICE); +async function emitContract(context: PrismaSetupContext, projectDir: string): Promise { + const invocation = getPrismaCliInvocation(context.packageManager, ["contract", "emit"]); + if (context.verbose) { + log.step([invocation.command, ...invocation.args].join(" ")); } - - await ensureGitignoreEntry(prismaProjectDir, generatedDir); + await execa(invocation.command, invocation.args, { + cwd: projectDir, + stdio: context.verbose ? "inherit" : "pipe", + }); } -async function provisionPrismaPostgresIfNeeded( - context: PrismaSetupContext, - projectDir: string, -): Promise { - if (!context.shouldUsePrismaPostgres) { - return { - databaseUrl: context.databaseUrl, - }; - } - - const createDbCommand = getCreateDbCommand(context.packageManager); - const prismaPostgresSpinner = spinner(); - prismaPostgresSpinner.start(`Provisioning Prisma Postgres with ${createDbCommand}...`); - - try { - const prismaPostgresResult = await provisionPrismaPostgres(context.packageManager, projectDir); - - prismaPostgresSpinner.stop("Prisma Postgres database provisioned."); - return { - databaseUrl: prismaPostgresResult.databaseUrl, - claimUrl: prismaPostgresResult.claimUrl, - }; - } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error); - prismaPostgresSpinner.stop("Could not provision Prisma Postgres."); - - return { - databaseUrl: context.databaseUrl, - warning: `Prisma Postgres provisioning failed: ${errorMessage}`, - }; - } +function formatNextSteps(steps: NextStep[]): string { + return steps.map((step) => `${step.command}\n ${step.description}`).join("\n\n"); } -async function writeDependenciesForContext( - context: PrismaSetupContext, - projectDir: string, -): Promise { - const prismaProjectDir = await resolvePrismaProjectDir(projectDir); - try { - await writePrismaDependencies( - context.databaseProvider, - context.packageManager, - prismaProjectDir, - ); - return true; - } catch (error) { - cancel(getCommandErrorMessage(error)); - return false; - } +function formatPlatformTarget(name: string | null, id: string): string { + return name ? `${name} (${id})` : id; } -async function installDependenciesForContext( - context: PrismaSetupContext, - projectDir: string, -): Promise { - if (!context.shouldInstall) { - return true; +function formatProjectSummary(options: { + createdProjectPath?: string; + deployment?: ComposerDeployResult; +}): string { + const lines: string[] = []; + if (options.createdProjectPath) { + lines.push(`Path: ${path.resolve(options.createdProjectPath)}`); + } + if (options.deployment?.workspace) { + lines.push( + `Workspace: ${formatPlatformTarget( + options.deployment.workspace.name, + options.deployment.workspace.id, + )}`, + ); } - - const installCommand = getInstallCommand(context.packageManager); - if (context.verbose) { - log.step(`Running ${installCommand}`); - try { - await installProjectDependencies(context.packageManager, projectDir, { - verbose: context.verbose, - }); - log.success("Dependencies installed."); - return true; - } catch (error) { - cancel(`Failed to run ${installCommand}: ${getCommandErrorMessage(error)}`); - return false; + if (options.deployment) { + lines.push( + `Project: ${ + options.deployment.project.id + ? formatPlatformTarget(options.deployment.project.name, options.deployment.project.id) + : options.deployment.project.name + }`, + ); + lines.push(`App: ${options.deployment.appUrl ?? options.deployment.appName}`); + if (options.deployment.project.consoleUrl) { + lines.push(`Console: ${options.deployment.project.consoleUrl}`); } } - - const installSpinner = spinner(); - installSpinner.start(`Running ${installCommand}...`); - try { - await installProjectDependencies(context.packageManager, projectDir, { - verbose: context.verbose, - }); - installSpinner.stop("Dependencies installed."); - return true; - } catch (error) { - installSpinner.stop("Could not install dependencies."); - cancel(`Failed to run ${installCommand}: ${getCommandErrorMessage(error)}`); - return false; - } + return lines.join("\n"); } -async function finalizePrismaFilesForContext( - context: PrismaSetupContext, - projectDir: string, - provisionResult: PrismaPostgresProvisionResult, -): Promise { - const initSpinner = spinner(); - initSpinner.start("Preparing Prisma files..."); - - try { - await finalizePrismaFiles({ - provider: context.databaseProvider, - databaseUrl: provisionResult.databaseUrl, - claimUrl: provisionResult.claimUrl, - projectDir, +function buildNextSteps(context: PrismaSetupContext, options: PrismaSetupRunOptions): NextStep[] { + const nextSteps = [...(options.prependNextSteps ?? [])]; + if (context.databaseProvider === "mongo") { + nextSteps.push({ + command: "Set MONGODB_URL in your environment", + description: "Composer uses this secret when deploying the MongoDB template.", }); - - initSpinner.stop("Prisma files ready."); - return true; - } catch (error) { - initSpinner.stop("Could not prepare Prisma files."); - cancel(getCommandErrorMessage(error)); - return false; - } -} - -async function generatePrismaClientForContext( - context: PrismaSetupContext, - projectDir: string, -): Promise { - const prismaProjectDir = await resolvePrismaProjectDir(projectDir); - if (!context.shouldGenerate) { - return { - didGenerateClient: false, - }; - } - - const generateCommand = getRunScriptCommand(context.packageManager, "db:generate"); - if (context.verbose) { - log.step(`Running ${generateCommand}`); - } - - const generateSpinner = context.verbose ? undefined : spinner(); - generateSpinner?.start("Generating Prisma Client..."); - try { - const generateArgs = getRunScriptArgs(context.packageManager, "db:generate"); - await execa(generateArgs.command, generateArgs.args, { - cwd: prismaProjectDir, - stdio: context.verbose ? "inherit" : "pipe", - }); - if (context.verbose) { - log.success("Prisma Client generated."); - } else { - generateSpinner?.stop("Prisma Client generated."); - } - - return { - didGenerateClient: true, - }; - } catch (error) { - if (context.verbose) { - log.warn("Could not generate Prisma Client."); - } else { - generateSpinner?.stop("Could not generate Prisma Client."); - } - - return { - didGenerateClient: false, - warning: `Prisma generate failed: ${getCommandErrorMessage(error)}`, - }; - } -} - -function buildWarningLines( - provisionWarning: string | undefined, - generateWarning: string | undefined, - migrateAndSeedWarning?: string, -): string[] { - const warningLines: string[] = []; - - if (provisionWarning) { - warningLines.push(`- ${provisionWarning}`); - } - if (generateWarning) { - warningLines.push(`- ${generateWarning}`); - } - if (migrateAndSeedWarning) { - warningLines.push(`- ${migrateAndSeedWarning}`); - } - - return warningLines; -} - -function buildNextStepsForContext(opts: { - context: PrismaSetupContext; - options: PrismaSetupRunOptions; - didGenerateClient: boolean; - didMigrate: boolean; - didSeed: boolean; -}): string[] { - const { context, options, didGenerateClient, didMigrate, didSeed } = opts; - const nextSteps: string[] = [...(options.prependNextSteps ?? [])]; - - if (!context.shouldInstall) { - nextSteps.push(`- ${getInstallCommand(context.packageManager)}`); - } - if (!didGenerateClient || !context.shouldGenerate) { - nextSteps.push(`- ${getRunScriptCommand(context.packageManager, "db:generate")}`); - } - if (options.includeMigrationAndSeedNextSteps !== false && !didMigrate) { - nextSteps.push(`- ${getRunScriptCommand(context.packageManager, "db:migrate")}`); - } - if (options.includeMigrationAndSeedNextSteps !== false && !didSeed) { - nextSteps.push(`- ${getRunScriptCommand(context.packageManager, "db:seed")}`); } if (options.includeDevNextStep) { - nextSteps.push(`- ${getRunScriptCommand(context.packageManager, "dev")}`); + nextSteps.push({ + command: getRunScriptCommand(context.packageManager, "dev:composer"), + description: "Build and start the app with Prisma Composer locally.", + }); } - + nextSteps.push({ + command: getRunScriptCommand(context.packageManager, "deploy"), + description: "Build and deploy the app with Prisma Composer.", + }); return nextSteps; } -export type PrismaSetupResult = - | { ok: false } - | { - ok: true; - nextSteps: string[]; - warningSection: string; - databaseUrl?: string; - }; - export async function executePrismaSetupContext( context: PrismaSetupContext, options: PrismaSetupRunOptions = {}, -): Promise { +): Promise { const projectDir = path.resolve(options.projectDir ?? context.projectDir); - const provisionResult = await provisionPrismaPostgresIfNeeded(context, projectDir); - if (!provisionResult) { - return { ok: false }; - } - - const didWriteDependencies = await writeDependenciesForContext(context, projectDir); - if (!didWriteDependencies) { - return { ok: false }; - } - - const dependenciesInstalled = await installDependenciesForContext(context, projectDir); - if (!dependenciesInstalled) { - return { ok: false }; - } - - const didFinalizePrismaFiles = await finalizePrismaFilesForContext( - context, - projectDir, - provisionResult, - ); - if (!didFinalizePrismaFiles) { - return { ok: false }; - } - - const databaseUrl = - provisionResult.databaseUrl ?? - context.databaseUrl ?? - getDefaultDatabaseUrl(context.databaseProvider); - - const generateResult = await generatePrismaClientForContext(context, projectDir); - - const migrateAndSeedResult = await migrateAndSeedIfRequested(context, projectDir, { - databaseUrl, - didGenerateClient: generateResult.didGenerateClient, - }); - - const warningLines = buildWarningLines( - provisionResult.warning, - generateResult.warning, - migrateAndSeedResult.warning, - ); - const nextSteps = buildNextStepsForContext({ - context, - options, - didGenerateClient: generateResult.didGenerateClient, - didMigrate: migrateAndSeedResult.didMigrate, - didSeed: migrateAndSeedResult.didSeed, - }); - - const warningSection = warningLines.length > 0 ? `\n\n${warningLines.join("\n")}` : ""; + const projectName = options.projectName ?? path.basename(projectDir); + const template = options.template ?? "minimal"; + const progress = context.verbose ? undefined : (options.progressSpinner ?? spinner()); + const ownsProgress = progress !== undefined && !options.progressSpinner; + if (ownsProgress) progress.start("Creating Prisma 8 project..."); - return { - ok: true, - nextSteps, - warningSection, - databaseUrl: provisionResult.databaseUrl ?? context.databaseUrl, - }; -} - -async function migrateAndSeedIfRequested( - context: PrismaSetupContext, - projectDir: string, - options: { databaseUrl?: string; didGenerateClient: boolean }, -): Promise<{ didMigrate: boolean; didSeed: boolean; warning?: string }> { - const prismaProjectDir = await resolvePrismaProjectDir(projectDir); - - if (!context.shouldMigrateAndSeed) { - return { didMigrate: false, didSeed: false }; - } - if (!options.didGenerateClient) { - return { - didMigrate: false, - didSeed: false, - warning: "Skipped migrate + seed because the Prisma Client was not generated.", - }; - } - if (!options.databaseUrl) { - return { - didMigrate: false, - didSeed: false, - warning: "Skipped migrate + seed because no DATABASE_URL is available.", - }; - } + try { + progress?.message("Preparing Prisma 8 project files..."); + await runPrismaInit(context, projectDir); - const migrateInvocation = getPrismaCliArgs(context.packageManager, [ - "migrate", - "dev", - "--name", - "init", - ]); - const seedInvocation = getPrismaCliArgs(context.packageManager, ["db", "seed"]); + await scaffoldCreateSharedTemplates({ + projectDir, + projectName, + template, + provider: context.databaseProvider, + authoring: context.authoring, + packageManager: context.packageManager, + }); + await writePrismaDependencies( + context.databaseProvider, + context.packageManager, + context.authoring, + projectDir, + ); + await ensureComposerTypeScriptOptions(projectDir); + if (context.databaseProvider === "mongo") await ensureMongoEnvironment(projectDir); - const migrateSpinner = spinner(); - migrateSpinner.start("Creating and applying initial migration..."); - let didMigrate = false; - try { - if (context.shouldUsePrismaPostgres) { - // Newly provisioned Prisma Postgres databases can briefly reject the first migration. - // TODO(2026-04-26): replace this grace period with an explicit readiness probe. - await new Promise((resolve) => setTimeout(resolve, PRISMA_POSTGRES_MIGRATION_DELAY_MS)); - } - await execa(migrateInvocation.command, migrateInvocation.args, { - cwd: prismaProjectDir, - stdio: context.verbose ? "inherit" : "pipe", + progress?.message( + `Installing dependencies with ${getInstallCommand(context.packageManager)}...`, + ); + await installProjectDependencies(context.packageManager, projectDir, { + verbose: context.verbose, }); - migrateSpinner.stop("Initial migration applied."); - didMigrate = true; + + progress?.message("Generating Prisma 8 contract artifacts..."); + await emitContract(context, projectDir); + progress?.stop("Prisma 8 project ready."); } catch (error) { - migrateSpinner.stop(`Migration failed${error instanceof Error ? `: ${error.message}` : "."}`); - return { - didMigrate: false, - didSeed: false, - warning: `Migration failed; run \`${getRunScriptCommand(context.packageManager, "db:migrate")}\` manually.`, - }; + progress?.error("Could not create Prisma 8 project."); + cancel(getCommandErrorMessage(error)); + return false; } - const seedSpinner = spinner(); - seedSpinner.start("Seeding database..."); - let didSeed = false; - try { - await execa(seedInvocation.command, seedInvocation.args, { - cwd: prismaProjectDir, - stdio: context.verbose ? "inherit" : "pipe", + let deployment: ComposerDeployResult | undefined; + if (context.shouldDeploy) { + deployment = await deployWithComposer({ + appName: projectName, + packageManager: context.packageManager, + projectDir, + shouldPromptForWorkspace: context.shouldPromptForWorkspace, + verbose: context.verbose, + ...(context.workspace ? { workspace: context.workspace } : {}), }); - seedSpinner.stop("Database seeded."); - didSeed = true; - } catch (error) { - seedSpinner.stop(`Seed failed${error instanceof Error ? `: ${error.message}` : "."}`); - return { - didMigrate, - didSeed: false, - warning: `Seed failed; run \`${getRunScriptCommand(context.packageManager, "db:seed")}\` manually.`, - }; + if (!deployment) return false; } - return { didMigrate, didSeed }; + const projectSummary = formatProjectSummary({ + createdProjectPath: options.createdProjectPath, + deployment, + }); + if (projectSummary) note(projectSummary, context.shouldDeploy ? "Deployment" : "Project"); + note(formatNextSteps(buildNextSteps(context, options)), "Next steps"); + outro(context.shouldDeploy ? "Prisma 8 app deployed." : "Prisma 8 project ready."); + return true; } diff --git a/src/telemetry/create.ts b/src/telemetry/create.ts index b6c9b8a..dac7a42 100644 --- a/src/telemetry/create.ts +++ b/src/telemetry/create.ts @@ -3,31 +3,16 @@ import type { CreateCommandInput } from "../types"; import { trackCliTelemetry } from "./client"; +export const CREATE_PRISMA_NEXT_COMPLETED_EVENT = "cli:create_prisma_next_command_completed"; +export const CREATE_PRISMA_NEXT_FAILED_EVENT = "cli:create_prisma_next_command_failed"; + export type CreateTelemetryFailureStage = | "validate_input" | "collect_context" | "scaffold_template" - | "addons" | "prisma_setup" - | "compute_deploy" | "unknown"; -function getRequestedAddons(input: CreateCommandInput): string[] { - const addons: string[] = []; - - if (input.skills === true) { - addons.push("skills"); - } - if (input.mcp === true) { - addons.push("mcp"); - } - if (input.extension === true) { - addons.push("extension"); - } - - return addons; -} - function getTargetDirectoryState(context: CreatePromptContext): string { if (!context.targetPathState.exists) { return "new"; @@ -44,8 +29,6 @@ function getBaseCreateProperties( input: CreateCommandInput, context?: CreatePromptContext, ): Record { - const resolvedAddons = context?.addonSetupContext?.addons ?? getRequestedAddons(input); - return { command: "create", "uses-defaults": input.yes === true, @@ -53,19 +36,9 @@ function getBaseCreateProperties( force: input.force === true, template: context?.template ?? input.template ?? null, "database-provider": context?.prismaSetupContext.databaseProvider ?? input.provider ?? null, + "authoring-style": context?.prismaSetupContext.authoring ?? input.authoring ?? null, "package-manager": context?.prismaSetupContext.packageManager ?? input.packageManager ?? null, - "schema-preset": context?.prismaSetupContext.schemaPreset ?? input.schemaPreset ?? null, - "should-install": context?.prismaSetupContext.shouldInstall ?? input.install ?? null, - "should-generate": context?.prismaSetupContext.shouldGenerate ?? input.generate ?? null, - "uses-prisma-postgres": - context?.prismaSetupContext.shouldUsePrismaPostgres ?? input.prismaPostgres ?? null, - addons: resolvedAddons, - "addon-count": resolvedAddons.length, - "addon-scope": context?.addonSetupContext?.scope ?? null, - "skills-count": context?.addonSetupContext?.skills.length ?? null, - "skills-agents-count": context?.addonSetupContext?.skillsAgents.length ?? null, - "mcp-agents-count": context?.addonSetupContext?.mcpAgents.length ?? null, - "extension-target-count": context?.addonSetupContext?.extensionTargets.length ?? null, + "should-deploy": context?.prismaSetupContext.shouldDeploy ?? input.deploy ?? null, "target-directory-state": context ? getTargetDirectoryState(context) : null, }; } @@ -97,7 +70,7 @@ export async function trackCreateCompleted(params: { context: CreatePromptContext; durationMs: number; }): Promise { - await trackCliTelemetry("cli:create_command_completed", { + await trackCliTelemetry(CREATE_PRISMA_NEXT_COMPLETED_EVENT, { ...getBaseCreateProperties(params.input, params.context), "duration-ms": params.durationMs, }); @@ -110,7 +83,7 @@ export async function trackCreateFailed(params: { error?: unknown; stage: CreateTelemetryFailureStage; }): Promise { - await trackCliTelemetry("cli:create_command_failed", { + await trackCliTelemetry(CREATE_PRISMA_NEXT_FAILED_EVENT, { ...getBaseCreateProperties(params.input, params.context), "duration-ms": params.durationMs, "failure-stage": params.stage, diff --git a/src/templates/render-create-template.ts b/src/templates/render-create-template.ts index 2d2bdae..fe4cd98 100644 --- a/src/templates/render-create-template.ts +++ b/src/templates/render-create-template.ts @@ -1,121 +1,80 @@ -import fs from "fs-extra"; -import path from "node:path"; - -import type { CreateTemplate, DatabaseProvider, PackageManager, SchemaPreset } from "../types"; -import { escapeRegExp } from "../utils/regexp"; +import type { AuthoringStyle, CreateTemplate, DatabaseProvider, PackageManager } from "../types"; import { renderTemplateTree, resolveTemplatesDir } from "./shared"; type CreateTemplateContext = { projectName: string; + template: CreateTemplate; provider: DatabaseProvider; - schemaPreset: SchemaPreset; + authoring: AuthoringStyle; packageManager?: PackageManager; - compute: boolean; }; function getCreateTemplateDir(template: CreateTemplate): string { return resolveTemplatesDir(`templates/create/${template}`); } +function getCreateSharedTemplateDir(): string { + return resolveTemplatesDir("templates/create/_shared"); +} + function createTemplateContext( projectName: string, + template: CreateTemplate, provider: DatabaseProvider, - schemaPreset: SchemaPreset, - packageManager: PackageManager | undefined, - compute: boolean, + authoring: AuthoringStyle, + packageManager?: PackageManager, ): CreateTemplateContext { return { projectName, + template, provider, - schemaPreset, + authoring, packageManager, - compute, }; } -const pnpmAllowedBuilds = [ - "@prisma/engines", - "@parcel/watcher", - "esbuild", - "prisma", - "sharp", - "unrs-resolver", -] as const; - -function renderPnpmAllowBuildLine(packageName: string): string { - const key = packageName.startsWith("@") ? JSON.stringify(packageName) : packageName; - return ` ${key}: true`; -} - -function renderPnpmAllowBuilds(): string { - return ["allowBuilds:", ...pnpmAllowedBuilds.map(renderPnpmAllowBuildLine)].join("\n"); -} - -function hasPnpmAllowBuild(content: string, packageName: string): boolean { - const key = escapeRegExp(packageName); - return new RegExp(`^\\s*["']?${key}["']?\\s*:\\s*true\\s*$`, "m").test(content); -} - -function mergePnpmAllowBuilds(content: string): string { - const missingBuilds = pnpmAllowedBuilds.filter( - (packageName) => !hasPnpmAllowBuild(content, packageName), - ); - if (missingBuilds.length === 0) { - return content; - } - - const missingLines = missingBuilds.map(renderPnpmAllowBuildLine); - const trimmedContent = content.trimEnd(); - const lines = trimmedContent.length > 0 ? trimmedContent.split("\n") : []; - const allowBuildsIndex = lines.findIndex((line) => /^allowBuilds:\s*$/.test(line)); - if (allowBuildsIndex === -1) { - const allowBuilds = ["allowBuilds:", ...missingLines].join("\n"); - return trimmedContent.length > 0 ? `${trimmedContent}\n\n${allowBuilds}\n` : `${allowBuilds}\n`; - } - - lines.splice(allowBuildsIndex + 1, 0, ...missingLines); - return `${lines.join("\n")}\n`; +export async function scaffoldCreateSharedTemplates(opts: { + projectDir: string; + projectName: string; + template: CreateTemplate; + provider: DatabaseProvider; + authoring: AuthoringStyle; + packageManager?: PackageManager; +}): Promise { + const { projectDir, projectName, template, provider, authoring, packageManager } = opts; + await renderTemplateTree({ + templateRoot: getCreateSharedTemplateDir(), + outputDir: projectDir, + context: createTemplateContext(projectName, template, provider, authoring, packageManager), + }); } -async function ensurePnpmWorkspaceAllowBuilds(projectDir: string): Promise { - const workspacePath = path.join(projectDir, "pnpm-workspace.yaml"); - - if (!(await fs.pathExists(workspacePath))) { - await fs.writeFile(workspacePath, `${renderPnpmAllowBuilds()}\n`, "utf8"); - return; - } - - const existingContent = await fs.readFile(workspacePath, "utf8"); - const nextContent = mergePnpmAllowBuilds(existingContent); - if (nextContent !== existingContent) { - await fs.writeFile(workspacePath, nextContent, "utf8"); - } +export async function scaffoldCreateTemplate(opts: { + projectDir: string; + projectName: string; + template: CreateTemplate; + provider: DatabaseProvider; + authoring: AuthoringStyle; + packageManager?: PackageManager; +}): Promise { + await scaffoldCreateFrameworkTemplate(opts); + await scaffoldCreateSharedTemplates(opts); } -export async function scaffoldCreateTemplate(opts: { +export async function scaffoldCreateFrameworkTemplate(opts: { projectDir: string; projectName: string; template: CreateTemplate; provider: DatabaseProvider; - schemaPreset: SchemaPreset; + authoring: AuthoringStyle; packageManager?: PackageManager; - compute?: boolean; }): Promise { - const { projectDir, projectName, template, provider, schemaPreset, packageManager } = opts; + const { projectDir, projectName, template, provider, authoring, packageManager } = opts; const templateRoot = getCreateTemplateDir(template); - const context = createTemplateContext( - projectName, - provider, - schemaPreset, - packageManager, - opts.compute === true, - ); + const context = createTemplateContext(projectName, template, provider, authoring, packageManager); await renderTemplateTree({ templateRoot, outputDir: projectDir, context, }); - if (packageManager === "pnpm") { - await ensurePnpmWorkspaceAllowBuilds(projectDir); - } } diff --git a/src/templates/shared.ts b/src/templates/shared.ts index 0a05001..cc0126f 100644 --- a/src/templates/shared.ts +++ b/src/templates/shared.ts @@ -4,51 +4,12 @@ import { existsSync } from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; -import { dependencyVersionMap } from "../constants/dependencies"; import type { PackageManager } from "../types"; import { getPackageManagerManifestValue, - getRunScriptInDirectoryCommand, getRuntimeScriptCommand, getRunScriptCommand, } from "../utils/package-manager"; -import { requiresDotenvConfigImport, requiresPrismaConfigDotenvImport } from "../utils/runtime"; - -function getOptionalHashString( - hash: Handlebars.HelperOptions["hash"], - key: string, -): string | undefined { - const value = hash[key]; - return typeof value === "string" && value.length > 0 ? value : undefined; -} - -function getOptionalHashStringList(hash: Handlebars.HelperOptions["hash"], key: string): string[] { - return getOptionalHashString(hash, key)?.split(" ") ?? []; -} - -function getSeedCommand(packageManager: PackageManager | undefined): string { - if (packageManager === "deno") { - return "deno run -A --env-file=.env ./prisma/seed.ts"; - } - - if (packageManager === "bun") { - return "bun ./prisma/seed.ts"; - } - - return "tsx ./prisma/seed.ts"; -} - -function getPrismaCommand(packageManager: PackageManager | undefined, subcommand: string): string { - if (packageManager === "deno") { - return `deno run -A --env-file=.env npm:prisma@${dependencyVersionMap.prisma} ${subcommand}`; - } - - if (packageManager === "bun") { - return `bun --env-file=.env ./node_modules/.bin/prisma ${subcommand}`; - } - - return `prisma ${subcommand}`; -} Handlebars.registerHelper("eq", (left: unknown, right: unknown) => left === right); Handlebars.registerHelper( @@ -56,34 +17,11 @@ Handlebars.registerHelper( (packageManager: PackageManager | undefined, scriptName: string) => packageManager ? getRunScriptCommand(packageManager, scriptName) : "", ); -Handlebars.registerHelper( - "runScriptInDirectoryCommand", - (packageManager: PackageManager | undefined, directory: string, scriptName: string) => - packageManager ? getRunScriptInDirectoryCommand(packageManager, directory, scriptName) : "", -); Handlebars.registerHelper( "packageManagerManifestValue", (packageManager: PackageManager | undefined) => getPackageManagerManifestValue(packageManager) ?? "", ); -Handlebars.registerHelper( - "requiresDotenvConfigImport", - (packageManager: PackageManager | undefined) => requiresDotenvConfigImport(packageManager), -); -Handlebars.registerHelper( - "requiresPrismaConfigDotenvImport", - (packageManager: PackageManager | undefined) => requiresPrismaConfigDotenvImport(packageManager), -); -Handlebars.registerHelper("sqliteAdapterPackage", () => "@prisma/adapter-libsql"); -Handlebars.registerHelper("sqliteAdapterClass", () => "PrismaLibSql"); -Handlebars.registerHelper("seedCommand", (packageManager: PackageManager | undefined) => - getSeedCommand(packageManager), -); -Handlebars.registerHelper( - "prismaCommand", - (packageManager: PackageManager | undefined, subcommand: string) => - getPrismaCommand(packageManager, subcommand), -); Handlebars.registerHelper( "runtimeScript", ( @@ -91,18 +29,14 @@ Handlebars.registerHelper( kind: "dev" | "build" | "start", sourceEntrypoint: string, builtEntrypoint: string | undefined, - options: Handlebars.HelperOptions, + _options: Handlebars.HelperOptions, ) => { if (!packageManager) { return ""; } - const hash = options.hash; - return getRuntimeScriptCommand(packageManager, kind, { sourceEntrypoint, builtEntrypoint, - denoFlags: getOptionalHashStringList(hash, "denoFlags"), - emit: hash.emit === true, }); }, ); diff --git a/src/types.ts b/src/types.ts index 2e973e0..c259164 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,16 +1,12 @@ import { z } from "zod"; -export const databaseProviders = [ - "postgresql", - "mysql", - "sqlite", - "sqlserver", - "cockroachdb", -] as const; +export const databaseProviders = ["postgres", "mongo"] as const; +export const databaseProviderInputs = ["postgres", "postgresql", "mongo", "mongodb"] as const; -export const packageManagers = ["npm", "pnpm", "yarn", "bun", "deno"] as const; -export const schemaPresets = ["empty", "basic"] as const; +export const packageManagers = ["npm", "pnpm", "yarn", "bun"] as const; +export const authoringStyles = ["psl", "typescript"] as const; export const createTemplates = [ + "minimal", "hono", "elysia", "nest", @@ -19,38 +15,32 @@ export const createTemplates = [ "astro", "nuxt", "tanstack-start", - "turborepo", -] as const; -export const createAddons = ["skills", "mcp", "extension"] as const; -export const addonInstallScopes = ["project", "global"] as const; -export const extensionTargets = ["vscode", "cursor", "windsurf"] as const; -export const prismaSkillNames = [ - "prisma-cli", - "prisma-client-api", - "prisma-compute", - "prisma-database-setup", - "prisma-upgrade-v7", - "prisma-postgres", ] as const; -export const DatabaseProviderSchema = z.enum(databaseProviders); +type NormalizedDatabaseProvider = (typeof databaseProviders)[number]; +type DatabaseProviderInput = (typeof databaseProviderInputs)[number]; + +function normalizeDatabaseProvider(value: DatabaseProviderInput): NormalizedDatabaseProvider { + if (value === "postgresql") { + return "postgres"; + } + if (value === "mongodb") { + return "mongo"; + } + + return value; +} + +export const DatabaseProviderSchema = z + .enum(databaseProviderInputs) + .transform(normalizeDatabaseProvider); export type DatabaseProvider = z.infer; export const PackageManagerSchema = z.enum(packageManagers); export type PackageManager = z.infer; -export const SchemaPresetSchema = z.enum(schemaPresets); -export type SchemaPreset = z.infer; +export const AuthoringStyleSchema = z.enum(authoringStyles); +export type AuthoringStyle = z.infer; export const CreateTemplateSchema = z.enum(createTemplates); export type CreateTemplate = z.infer; -export const CreateAddonSchema = z.enum(createAddons); -export type CreateAddon = z.infer; -export const AddonInstallScopeSchema = z.enum(addonInstallScopes); -export type AddonInstallScope = z.infer; -export const ExtensionTargetSchema = z.enum(extensionTargets); -export type ExtensionTarget = z.infer; -export const PrismaSkillNameSchema = z.enum(prismaSkillNames); -export type PrismaSkillName = z.infer; - -export const DatabaseUrlSchema = z.string().trim().min(1, "Please enter a valid database URL"); export const CommonCommandOptionsSchema = z.object({ yes: z.boolean().optional().describe("Skip prompts and accept default choices"), @@ -58,24 +48,20 @@ export const CommonCommandOptionsSchema = z.object({ }); export const PrismaSetupOptionsSchema = z.object({ - provider: DatabaseProviderSchema.optional().describe("Database provider"), + provider: DatabaseProviderSchema.optional().describe( + "Prisma 8 database target: PostgreSQL relational models or MongoDB document models", + ), + authoring: AuthoringStyleSchema.optional().describe("Contract authoring style"), packageManager: PackageManagerSchema.optional().describe( "Package manager used for dependency installation", ), - prismaPostgres: z - .boolean() - .optional() - .describe("Use Prisma Postgres when provider is postgresql"), - databaseUrl: DatabaseUrlSchema.optional().describe("DATABASE_URL value"), - install: z.boolean().optional().describe("Install dependencies with selected package manager"), - generate: z.boolean().optional().describe("Generate Prisma Client after scaffolding"), - migrateAndSeed: z - .boolean() + deploy: z.boolean().optional().describe("Deploy the generated app to Prisma immediately"), + workspace: z + .string() + .trim() + .min(1, "Please enter a valid workspace id or name") .optional() - .describe("Run an initial migration and seed after Prisma Client generation"), - schemaPreset: SchemaPresetSchema.optional().describe( - "Schema preset to scaffold in prisma/schema.prisma", - ), + .describe("Prisma workspace id or name to deploy into"), }); export const PrismaSetupCommandInputSchema = CommonCommandOptionsSchema.extend( @@ -91,28 +77,9 @@ export const CreateScaffoldOptionsSchema = z.object({ .optional() .describe("Project name / directory"), template: CreateTemplateSchema.optional().describe("Project template"), - skills: z.boolean().optional().describe("Enable skills addon"), - mcp: z.boolean().optional().describe("Enable MCP addon"), - extension: z.boolean().optional().describe("Enable extension addon"), - deploy: z.boolean().optional().describe("Deploy the scaffolded project to Prisma Compute"), force: z.boolean().optional().describe("Allow scaffolding into a non-empty target directory"), }); -export const COMPUTE_DEPLOYABLE_TEMPLATES: ReadonlySet = new Set([ - "hono", - "elysia", - "nest", - "next", - "astro", - "nuxt", - "tanstack-start", - "turborepo", -]); - -export function isComputeDeployableTemplate(template: CreateTemplate): boolean { - return COMPUTE_DEPLOYABLE_TEMPLATES.has(template); -} - export const CreateCommandInputSchema = PrismaSetupCommandInputSchema.extend( CreateScaffoldOptionsSchema.shape, ); diff --git a/src/ui/branding.ts b/src/ui/branding.ts index 43ceff1..4c9a835 100644 --- a/src/ui/branding.ts +++ b/src/ui/branding.ts @@ -1,9 +1,10 @@ import { styleText } from "node:util"; -const prismaTitle = `${styleText(["bold", "cyan"], "Create")} ${styleText( - ["bold", "magenta"], - "Prisma", -)}`; +const prismaMark = styleText(["bold", "cyanBright"], "â—­"); +const createLabel = styleText(["bold", "cyanBright"], "Create"); +const prismaLabel = styleText(["bold", "magentaBright"], "Prisma"); +const versionLabel = styleText(["bold", "blueBright"], "8"); +const prismaTitle = `${prismaMark} ${createLabel} ${prismaLabel} ${versionLabel}`; export function getCreatePrismaIntro(): string { return prismaTitle; diff --git a/src/utils/node-version.ts b/src/utils/node-version.ts new file mode 100644 index 0000000..dbdf2f3 --- /dev/null +++ b/src/utils/node-version.ts @@ -0,0 +1,23 @@ +const MINIMUM_NODE_VERSION = [22, 18, 0] as const; + +function parseVersion(version: string): [number, number, number] { + const [major = "0", minor = "0", patch = "0"] = version.replace(/^v/, "").split("."); + return [Number(major), Number(minor), Number.parseInt(patch, 10)]; +} + +export function supportsPrismaNext(nodeVersion = process.versions.node): boolean { + const current = parseVersion(nodeVersion); + for (let index = 0; index < MINIMUM_NODE_VERSION.length; index += 1) { + if (current[index]! > MINIMUM_NODE_VERSION[index]!) return true; + if (current[index]! < MINIMUM_NODE_VERSION[index]!) return false; + } + return true; +} + +export function getUnsupportedNodeMessage(nodeVersion = process.versions.node): string { + return [ + `Node.js ${nodeVersion} is unsupported by create-prisma@next.`, + "Required: Node.js 22.18 or newer.", + "Update Node.js and run the command again.", + ].join("\n"); +} diff --git a/src/utils/package-manager.ts b/src/utils/package-manager.ts index 3df22b5..4f60d70 100644 --- a/src/utils/package-manager.ts +++ b/src/utils/package-manager.ts @@ -1,7 +1,6 @@ import fs from "fs-extra"; import path from "node:path"; -import { dependencyVersionMap } from "../constants/dependencies"; import { PackageManagerSchema, type PackageManager } from "../types"; type CommandAndArgs = { @@ -13,18 +12,13 @@ type RuntimeScriptKind = "dev" | "build" | "start"; type RuntimeScriptOptions = { sourceEntrypoint: string; builtEntrypoint?: string; - denoFlags?: string[]; - // When true, `build` compiles to `dist` instead of only type-checking. - // Templates that deploy a compiled artifact (e.g. NestJS) need this; bun and - // deno otherwise run TypeScript directly and skip emit. - emit?: boolean; }; const packageManagerManifestValues = { - npm: "npm@11.17.0", - pnpm: "pnpm@11.8.0", - yarn: "yarn@4.17.0", - bun: "bun@1.3.14", + npm: "npm@10.9.0", + pnpm: "pnpm@11.21.0", + yarn: "yarn@4.13.0", + bun: "bun@1.3.9", } as const; function parseUserAgent(userAgent: string | undefined): PackageManager | null { @@ -40,10 +34,6 @@ function parseUserAgent(userAgent: string | undefined): PackageManager | null { return "bun"; } - if (userAgent?.startsWith("deno")) { - return "deno"; - } - if (userAgent?.startsWith("npm")) { return "npm"; } @@ -71,18 +61,6 @@ async function detectFromPackageJson(projectDir: string): Promise { - const configCandidates = ["deno.json", "deno.jsonc"]; - - for (const configFile of configCandidates) { - if (await fs.pathExists(path.join(projectDir, configFile))) { - return "deno"; - } - } - - return null; -} - async function detectFromLockfile(projectDir: string): Promise { const lockfileChecks: Array<{ manager: PackageManager; lockfile: string }> = [ { manager: "pnpm", lockfile: "pnpm-lock.yaml" }, @@ -91,7 +69,6 @@ async function detectFromLockfile(projectDir: string): Promise): string { - return parts.filter((part) => typeof part === "string" && part.length > 0).join(" "); -} - export function getRuntimeScriptCommand( packageManager: PackageManager, kind: RuntimeScriptKind, options: RuntimeScriptOptions, ): string { - const { sourceEntrypoint, builtEntrypoint, denoFlags = [], emit = false } = options; - - if (packageManager === "deno") { - switch (kind) { - case "dev": - return joinCommandParts([ - "deno", - "run", - "-A", - "--env-file=.env", - ...denoFlags, - "--watch", - sourceEntrypoint, - ]); - case "build": - // Deno runs TypeScript directly; there is no node-style compiled - // artifact to emit here (the Deno nest variant uses Deno APIs and is - // not built for the node-based Compute runtime). - return `deno check ${sourceEntrypoint}`; - case "start": - return joinCommandParts([ - "deno", - "run", - "-A", - "--env-file=.env", - ...denoFlags, - sourceEntrypoint, - ]); - } - } + const { sourceEntrypoint, builtEntrypoint } = options; if (packageManager === "bun") { switch (kind) { case "dev": return `bun --watch ${sourceEntrypoint}`; case "build": - return emit ? "tsc" : "tsc --noEmit"; + return "tsc --noEmit"; case "start": return `bun ${sourceEntrypoint}`; } @@ -278,13 +156,6 @@ export function getRuntimeScriptCommand( } export function getInstallArgs(packageManager: PackageManager): CommandAndArgs { - if (packageManager === "deno") { - return { - command: "deno", - args: ["install", `--allow-scripts=${getDenoAllowedScriptSpecifiers()}`], - }; - } - return { command: packageManager, args: ["install"], @@ -294,89 +165,81 @@ export function getInstallArgs(packageManager: PackageManager): CommandAndArgs { export function getPackageExecutionArgs( packageManager: PackageManager, commandArgs: string[], - options: { - silent?: boolean; - } = {}, ): CommandAndArgs { switch (packageManager) { case "pnpm": - return { - command: "pnpm", - args: [...(options.silent ? ["--silent"] : []), "dlx", ...commandArgs], - }; + return { command: "pnpm", args: ["dlx", ...commandArgs] }; case "yarn": - return { - command: "yarn", - args: ["dlx", ...(options.silent ? ["--quiet"] : []), ...commandArgs], - }; + return { command: "yarn", args: ["dlx", ...commandArgs] }; case "bun": - return { command: "bunx", args: [...(options.silent ? ["--silent"] : []), ...commandArgs] }; - case "deno": { - const [packageName, ...args] = commandArgs; - if (!packageName) { - throw new Error("Package execution requires a package name."); - } - - return { - command: "deno", - args: ["run", "-A", `npm:${packageName}`, ...args], - }; - } + return { command: "bunx", args: [...commandArgs] }; case "npm": default: - // npx has no true silent flag. --yes skips prompts, while --no-update-notifier - // avoids npm notices around otherwise JSON-only command output. - return { - command: "npx", - args: [...(options.silent ? ["--yes", "--no-update-notifier"] : []), ...commandArgs], - }; + return { command: "npx", args: ["--yes", ...commandArgs] }; } } export function getPackageExecutionCommand( packageManager: PackageManager, commandArgs: string[], - options: { - silent?: boolean; - } = {}, ): string { - const execution = getPackageExecutionArgs(packageManager, commandArgs, options); + const execution = getPackageExecutionArgs(packageManager, commandArgs); return [execution.command, ...execution.args].join(" "); } -export function getPrismaCliArgs( +export function getLocalPackageBinaryArgs( packageManager: PackageManager, - prismaArgs: string[], + binaryName: string, + binaryArgs: string[], ): CommandAndArgs { - if (packageManager === "deno") { - return { - command: "deno", - args: ["run", "-A", "--env-file=.env", getDenoPrismaSpecifier(), ...prismaArgs], - }; + switch (packageManager) { + case "pnpm": + return { command: "pnpm", args: ["exec", binaryName, ...binaryArgs] }; + case "yarn": + return { command: "yarn", args: [binaryName, ...binaryArgs] }; + case "bun": + return { command: "bun", args: [binaryName, ...binaryArgs] }; + case "npm": + default: + return { command: "npm", args: ["exec", binaryName, "--", ...binaryArgs] }; } +} + +export function getLocalPackageBinaryCommand( + packageManager: PackageManager, + binaryName: string, + binaryArgs: string[], +): string { + const execution = getLocalPackageBinaryArgs(packageManager, binaryName, binaryArgs); + return [execution.command, ...execution.args].join(" "); +} +export function getPrismaCliArgs( + packageManager: PackageManager, + prismaArgs: string[], +): CommandAndArgs { if (packageManager === "bun") { - return { - command: "bun", - args: ["--env-file=.env", "./node_modules/.bin/prisma", ...prismaArgs], - }; + return getPackageExecutionArgs(packageManager, ["--bun", "prisma", ...prismaArgs]); } - if (packageManager === "pnpm") { - return { - command: "pnpm", - args: ["exec", "prisma", ...prismaArgs], - }; - } + return getPackageExecutionArgs(packageManager, ["prisma", ...prismaArgs]); +} - if (packageManager === "yarn") { - return { - command: "yarn", - args: ["exec", "prisma", ...prismaArgs], - }; +export function getRunScriptArgs( + packageManager: PackageManager, + scriptName: string, +): CommandAndArgs { + switch (packageManager) { + case "bun": + return { command: "bun", args: ["run", scriptName] }; + case "pnpm": + return { command: "pnpm", args: ["run", scriptName] }; + case "yarn": + return { command: "yarn", args: ["run", scriptName] }; + case "npm": + default: + return { command: "npm", args: ["run", scriptName] }; } - - return getPackageExecutionArgs(packageManager, ["prisma", ...prismaArgs]); } export function getPrismaCliCommand(packageManager: PackageManager, prismaArgs: string[]): string { diff --git a/src/utils/regexp.ts b/src/utils/regexp.ts deleted file mode 100644 index 6f0fedc..0000000 --- a/src/utils/regexp.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Escape regex metacharacters before interpolating dynamic values into RegExp. -export function escapeRegExp(value: string): string { - return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); -} diff --git a/src/utils/runtime.ts b/src/utils/runtime.ts deleted file mode 100644 index edd7e0b..0000000 --- a/src/utils/runtime.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { PackageManager } from "../types"; - -export function usesNodeStyleRuntime(packageManager: PackageManager | undefined): boolean { - return packageManager !== undefined && packageManager !== "bun" && packageManager !== "deno"; -} - -export function requiresDotenvConfigImport(packageManager: PackageManager | undefined): boolean { - return usesNodeStyleRuntime(packageManager); -} - -export function requiresPrismaConfigDotenvImport( - packageManager: PackageManager | undefined, -): boolean { - return packageManager !== "deno"; -} diff --git a/templates/create/_shared/.gitattributes.hbs b/templates/create/_shared/.gitattributes.hbs new file mode 100644 index 0000000..fe00c01 --- /dev/null +++ b/templates/create/_shared/.gitattributes.hbs @@ -0,0 +1,11 @@ +{{#if (eq authoring "typescript")}} +src/prisma/generated/contract.json linguist-generated +src/prisma/generated/contract.d.ts linguist-generated +{{else}} +src/prisma/contract.json linguist-generated +src/prisma/contract.d.ts linguist-generated +{{/if}} +src/prisma/ops.json linguist-generated +src/prisma/migration.json linguist-generated +migrations/snapshots/**/contract.json linguist-generated +migrations/snapshots/**/contract.d.ts linguist-generated diff --git a/templates/create/_shared/README.md.hbs b/templates/create/_shared/README.md.hbs new file mode 100644 index 0000000..fedd25d --- /dev/null +++ b/templates/create/_shared/README.md.hbs @@ -0,0 +1,39 @@ +# {{projectName}} + +A minimal {{template}} app with Prisma 8 and Prisma Composer. + +## Run locally + +```bash +{{runScriptCommand packageManager "dev:composer"}} +``` + +This builds the app and starts it with Composer. PostgreSQL projects get a local Prisma Postgres database and apply the contract automatically. + +## Deploy + +```bash +{{runScriptCommand packageManager "deploy"}} +``` + +The deploy script builds the framework output, provisions Prisma Postgres when selected, applies migrations, and deploys the app to Prisma Compute. + +The starter users are inserted idempotently from `src/prisma/seed.ts` on the first database query through the Composer service binding. + +{{#if (eq provider "mongo")}} +MongoDB is not provisioned by Composer. Set `MONGODB_URL` before running Composer locally or deploying. +{{/if}} + +## Prisma + +- Contract: `src/prisma/contract{{#if (eq authoring "typescript")}}.ts{{else}}.prisma{{/if}}` +- Prisma and Composer config: `prisma.config.ts` +- Composer app: `module.ts` and `service.ts` + +After changing the contract, run: + +```bash +{{runScriptCommand packageManager "contract:emit"}} +``` + +To use the framework's development server directly, run `{{runScriptCommand packageManager "dev"}}`. This direct mode requires `DATABASE_URL`. diff --git a/templates/create/_shared/module.ts.hbs b/templates/create/_shared/module.ts.hbs new file mode 100644 index 0000000..754484b --- /dev/null +++ b/templates/create/_shared/module.ts.hbs @@ -0,0 +1,28 @@ +import { module } from "@prisma/composer"; +{{#if (eq provider "postgres")}} +import { pnPostgres } from "@prisma/composer-prisma-cloud/prisma-next"; + +import { appContract } from "./src/prisma/composer.ts"; +{{else}} +import { envSecret } from "@prisma/composer-prisma-cloud"; +{{/if}} +import app from "./service.ts"; + +export default module("{{projectName}}", ({ provision }) => { +{{#if (eq provider "postgres")}} + const database = provision( + pnPostgres({ + name: "database", + contract: appContract, + config: "./prisma.config.ts", + }), + { id: "database" }, + ); + + provision(app, { deps: { database } }); +{{else}} + provision(app, { + input: { databaseUrl: envSecret("MONGODB_URL") }, + }); +{{/if}} +}); diff --git a/templates/create/_shared/pnpm-workspace.yaml.hbs b/templates/create/_shared/pnpm-workspace.yaml.hbs new file mode 100644 index 0000000..5236efa --- /dev/null +++ b/templates/create/_shared/pnpm-workspace.yaml.hbs @@ -0,0 +1,16 @@ +{{#if (eq packageManager "pnpm")}} +allowBuilds: + esbuild: true + msgpackr-extract: true +{{#if (eq template "next")}} + sharp: true + unrs-resolver: true +{{else if (eq template "astro")}} + sharp: true +{{/if}} + workerd: true +minimumReleaseAgeExclude: + - "@prisma/*" +overrides: + effect: "4.0.0-beta.103" +{{/if}} diff --git a/templates/create/_shared/prisma-composer.config.ts.hbs b/templates/create/_shared/prisma-composer.config.ts.hbs new file mode 100644 index 0000000..e2561e2 --- /dev/null +++ b/templates/create/_shared/prisma-composer.config.ts.hbs @@ -0,0 +1,11 @@ +import { defineConfig } from "@prisma/composer/config"; +import { nodeBuild } from "@prisma/composer/node/control"; +{{#if (eq template "next")}} +import { nextjsBuild } from "@prisma/composer/nextjs/control"; +{{/if}} +import { prismaCloud, prismaState } from "@prisma/composer-prisma-cloud/control"; + +export default defineConfig({ + extensions: [prismaCloud(), nodeBuild(){{#if (eq template "next")}}, nextjsBuild(){{/if}}], + state: prismaState(), +}); diff --git a/templates/create/_shared/prisma.config.ts.hbs b/templates/create/_shared/prisma.config.ts.hbs new file mode 100644 index 0000000..4fdf962 --- /dev/null +++ b/templates/create/_shared/prisma.config.ts.hbs @@ -0,0 +1,17 @@ +import { definePrismaConfig } from "@prisma/cli-engine"; +import { defineConfig as ormConfig } from "@prisma/orm-{{#if (eq provider "postgres")}}postgres{{else}}mongo{{/if}}/config"; + +export default definePrismaConfig({ + orm: ormConfig({ + contract: "./src/prisma/contract{{#if (eq authoring "typescript")}}.ts{{else}}.prisma{{/if}}", +{{#if (eq authoring "typescript")}} + output: "./src/prisma/generated", +{{/if}} + db: { + connection: process.env.{{#if (eq provider "postgres")}}DATABASE_URL{{else}}MONGODB_URL{{/if}}!, + }, + }), + composer: { + configPath: "./prisma-composer.config.ts", + }, +}); diff --git a/templates/create/_shared/service.ts.hbs b/templates/create/_shared/service.ts.hbs new file mode 100644 index 0000000..9265e86 --- /dev/null +++ b/templates/create/_shared/service.ts.hbs @@ -0,0 +1,42 @@ +{{#if (eq template "next")}} +import nextjs from "@prisma/composer/nextjs"; +{{else}} +import node from "@prisma/composer/node"; +{{/if}} +{{#if (eq provider "mongo")}} +import { secretString } from "@prisma/composer/arktype"; +import { type } from "arktype"; +{{/if}} +import { compute } from "@prisma/composer-prisma-cloud"; +{{#if (eq provider "postgres")}} +import { pnPostgres } from "@prisma/composer-prisma-cloud/prisma-next"; + +import { appContract } from "./src/prisma/composer.ts"; +{{/if}} + +export default compute({ + name: "app", + deps: { +{{#if (eq provider "postgres")}} + database: pnPostgres(appContract), +{{/if}} + }, +{{#if (eq provider "mongo")}} + input: type({ + databaseUrl: secretString(), + }), +{{/if}} +{{#if (eq template "next")}} + build: nextjs({ module: import.meta.url, appDir: "." }), +{{else if (eq template "svelte")}} + build: node({ module: import.meta.url, dir: "./build", entry: "index.js" }), +{{else if (eq template "astro")}} + build: node({ module: import.meta.url, dir: "./dist", entry: "server/entry.mjs" }), +{{else if (eq template "nuxt")}} + build: node({ module: import.meta.url, dir: "./.output", entry: "server/index.mjs" }), +{{else if (eq template "tanstack-start")}} + build: node({ module: import.meta.url, dir: "./.output", entry: "server/index.mjs" }), +{{else}} + build: node({ module: import.meta.url, entry: "./dist/server.mjs" }), +{{/if}} +}); diff --git a/templates/create/_shared/src/prisma/composer.ts.hbs b/templates/create/_shared/src/prisma/composer.ts.hbs new file mode 100644 index 0000000..71ee7fe --- /dev/null +++ b/templates/create/_shared/src/prisma/composer.ts.hbs @@ -0,0 +1,8 @@ +{{#if (eq provider "postgres")}} +import { pnContract } from "@prisma/composer-prisma-cloud/prisma-next"; + +import type { Contract } from "./{{#if (eq authoring "typescript")}}generated/{{/if}}contract.d.ts"; +import contractJson from "./{{#if (eq authoring "typescript")}}generated/{{/if}}contract.json" with { type: "json" }; + +export const appContract = pnContract(contractJson); +{{/if}} diff --git a/templates/create/_shared/src/prisma/db.ts.hbs b/templates/create/_shared/src/prisma/db.ts.hbs new file mode 100644 index 0000000..eb9ccf3 --- /dev/null +++ b/templates/create/_shared/src/prisma/db.ts.hbs @@ -0,0 +1,51 @@ +{{#if (eq provider "postgres")}} +import postgres from "@prisma/orm-postgres/runtime"; + +import service from "../../service.ts"; +import type { Contract } from "./{{#if (eq authoring "typescript")}}generated/{{/if}}contract.d.ts"; +import contractJson from "./{{#if (eq authoring "typescript")}}generated/{{/if}}contract.json" with { type: "json" }; + +function loadComposerDatabase() { + try { + return service.load().database.client; + } catch { + return undefined; + } +} + +export const db = + loadComposerDatabase() ?? + (process.env.DATABASE_URL + ? postgres({ contractJson, url: process.env.DATABASE_URL }) + : postgres({ contractJson })); +{{else}} +import mongo from "@prisma/orm-mongo/runtime"; + +import service from "../../service.ts"; +import type { Contract } from "./{{#if (eq authoring "typescript")}}generated/{{/if}}contract.d.ts"; +import contractJson from "./{{#if (eq authoring "typescript")}}generated/{{/if}}contract.json" with { type: "json" }; + +function getDatabaseUrl(): string | undefined { + try { + return service.input().databaseUrl.expose(); + } catch { + return process.env.DATABASE_URL; + } +} + +const databaseUrl = getDatabaseUrl(); + +export const db = databaseUrl + ? mongo({ contractJson, url: databaseUrl }) + : mongo({ contractJson }); +{{/if}} + +let connection: Promise | undefined; + +export function connectDatabase(): Promise { + connection ??= db.connect().then(() => undefined).catch((error: unknown) => { + connection = undefined; + throw error; + }); + return connection; +} diff --git a/templates/create/_shared/src/prisma/seed.ts.hbs b/templates/create/_shared/src/prisma/seed.ts.hbs new file mode 100644 index 0000000..8ad1eb9 --- /dev/null +++ b/templates/create/_shared/src/prisma/seed.ts.hbs @@ -0,0 +1,36 @@ +import { connectDatabase, db } from "./db.ts"; + +const users = [ + { email: "alice@prisma.io", username: "alice", name: "Alice" }, + { email: "bob@prisma.io", username: "bob", name: "Bob" }, + { email: "carol@prisma.io", username: "carol", name: "Carol" }, +]; + +let pendingSeed: Promise | undefined; + +async function runSeed(): Promise { + await connectDatabase(); + +{{#if (eq provider "mongo")}} + for (const user of users) { + const existingUser = await db.orm.users.where({ email: user.email }).first(); + if (!existingUser) await db.orm.users.create(user); + } +{{else}} + for (const user of users) { + await db.orm.public.User.upsert({ + create: user, + update: {}, + conflictOn: { email: user.email }, + }); + } +{{/if}} +} + +export function seed(): Promise { + pendingSeed ??= runSeed().catch((error: unknown) => { + pendingSeed = undefined; + throw error; + }); + return pendingSeed; +} diff --git a/templates/create/_shared/src/prisma/users.ts.hbs b/templates/create/_shared/src/prisma/users.ts.hbs new file mode 100644 index 0000000..470b7f2 --- /dev/null +++ b/templates/create/_shared/src/prisma/users.ts.hbs @@ -0,0 +1,35 @@ +import { db } from "./db.ts"; +import { seed } from "./seed.ts"; + +export { db }; + +export async function listUsers(limit = 10) { + await seed(); +{{#if (eq provider "mongo")}} + const users = []; + + for await (const user of db.orm.users.select("_id", "email", "username", "name").take(limit).all()) { + users.push({ + id: String(user._id), + email: user.email, + username: user.username ?? null, + name: user.name ?? null, + createdAt: null as Date | null, + }); + } + + return users; +{{else}} + const users = await db.orm.public.User.select("id", "email", "username", "name", "createdAt").take(limit).all(); + + return users.map((user) => ({ + id: String(user.id), + email: user.email, + username: user.username ?? null, + name: user.name ?? null, + createdAt: user.createdAt, + })); +{{/if}} +} + +export type StarterUser = Awaited>[number]; diff --git a/templates/create/astro/README.md.hbs b/templates/create/astro/README.md.hbs deleted file mode 100644 index b0c885e..0000000 --- a/templates/create/astro/README.md.hbs +++ /dev/null @@ -1,47 +0,0 @@ -# {{projectName}} - -Generated by `create-prisma` with the Astro template. - -## Scripts - -- `{{runScriptCommand packageManager "dev"}}` - start the Astro dev server -- `{{runScriptCommand packageManager "build"}}` - build for production -- `{{runScriptCommand packageManager "preview"}}` - preview the production build -- `{{runScriptCommand packageManager "astro"}}` - run Astro CLI commands -{{#if compute}} -- `{{runScriptCommand packageManager "compute:deploy"}}` - redeploy to Prisma Compute with environment variables from `.env` -{{/if}} - -## Prisma - -Prisma setup is scaffolded automatically in: - -- `prisma/schema.prisma` -- `prisma/seed.ts` -- `src/lib/prisma.ts` -- `src/pages/api/users.ts` -- `prisma.config.ts` -- `prisma.compute.ts` -- `src/generated/prisma` - -Database helper scripts are added to `package.json`: - -- `db:generate` -- `db:push` -- `db:migrate` -- `db:seed` -{{#if (eq schemaPreset "basic")}} - -The starter page queries a basic `User` model in `src/pages/index.astro`, and `src/pages/api/users.ts` shows an Astro API route backed by the same Prisma client. -{{else}} - -The starter page keeps the official Astro minimal structure and points you to `prisma/schema.prisma` for your first model. -{{/if}} -{{#if compute}} - -## Prisma Compute - -This project includes a Prisma Compute deploy script and deploy defaults in `prisma.compute.ts`. Deploys load environment variables from `.env`; if setup created a Prisma Postgres database, its `DATABASE_URL` is already written there. - -After local changes, run `{{runScriptCommand packageManager "compute:deploy"}}` to redeploy. -{{/if}} diff --git a/templates/create/astro/astro.config.mjs b/templates/create/astro/astro.config.mjs new file mode 100644 index 0000000..c0028f0 --- /dev/null +++ b/templates/create/astro/astro.config.mjs @@ -0,0 +1,9 @@ +// @ts-check +import node from "@astrojs/node"; +import { defineConfig } from "astro/config"; + +// https://astro.build/config +export default defineConfig({ + output: "server", + adapter: node({ mode: "standalone" }), +}); diff --git a/templates/create/astro/astro.config.mjs.hbs b/templates/create/astro/astro.config.mjs.hbs deleted file mode 100644 index 2b3edb2..0000000 --- a/templates/create/astro/astro.config.mjs.hbs +++ /dev/null @@ -1,21 +0,0 @@ -// @ts-check -import { defineConfig } from "astro/config"; -import node from "@astrojs/node"; - -// https://astro.build/config -export default defineConfig({ - output: "server", - adapter: node({ mode: "standalone" }), - server: { host: true }, - vite: { - ssr: { - // Bundle SSR dependencies into the server entry. Astro's standalone - // build emits `import { parse, serialize } from "cookie"`, and the Bun - // runtime on Prisma Compute cannot resolve those named exports from - // cookie's CommonJS build at runtime (SyntaxError: Export named 'parse' - // not found). Bundling resolves the imports at build time. Remove once - // the Bun/cookie CJS named-export interop is fixed upstream. - noExternal: true, - }, - }, -}); diff --git a/templates/create/astro/deno.json.hbs b/templates/create/astro/deno.json.hbs deleted file mode 100644 index 360f2ea..0000000 --- a/templates/create/astro/deno.json.hbs +++ /dev/null @@ -1,5 +0,0 @@ -{{#if (eq packageManager "deno")}} -{ - "nodeModulesDir": "auto" -} -{{/if}} diff --git a/templates/create/astro/package.json.hbs b/templates/create/astro/package.json.hbs index f434754..355ac7c 100644 --- a/templates/create/astro/package.json.hbs +++ b/templates/create/astro/package.json.hbs @@ -12,12 +12,12 @@ "astro": "astro" }, "dependencies": { - "@astrojs/node": "^11.0.0", - "astro": "^7.0.0" + "astro": "^6.3.3" }, "devDependencies": { - "@types/node": "^26.0.0", - "tsx": "^4.22.4", - "typescript": "^6.0.3" + "@types/node": "^24.3.0", + "tsx": "^4.7.1", + "typescript": "^5.9.3", + "vite": "^8.1.2" } } diff --git a/templates/create/astro/prisma.compute.ts.hbs b/templates/create/astro/prisma.compute.ts.hbs deleted file mode 100644 index e5e2175..0000000 --- a/templates/create/astro/prisma.compute.ts.hbs +++ /dev/null @@ -1,10 +0,0 @@ -import { defineComputeConfig } from "@prisma/compute-sdk/config"; - -export default defineComputeConfig({ - app: { - name: "{{projectName}}", - framework: "astro", - httpPort: 4321, - env: ".env", - }, -}); diff --git a/templates/create/astro/prisma.config.ts.hbs b/templates/create/astro/prisma.config.ts.hbs deleted file mode 100644 index a33e79e..0000000 --- a/templates/create/astro/prisma.config.ts.hbs +++ /dev/null @@ -1,15 +0,0 @@ -{{#if (requiresPrismaConfigDotenvImport this.packageManager)}} -import "dotenv/config"; -{{/if}} -import { defineConfig, env } from "prisma/config"; - -export default defineConfig({ - schema: "prisma/schema.prisma", - migrations: { - path: "prisma/migrations", - seed: "{{seedCommand this.packageManager}}", - }, - datasource: { - url: env("DATABASE_URL"), - }, -}); diff --git a/templates/create/astro/prisma/schema.prisma.hbs b/templates/create/astro/prisma/schema.prisma.hbs deleted file mode 100644 index cea58dd..0000000 --- a/templates/create/astro/prisma/schema.prisma.hbs +++ /dev/null @@ -1,21 +0,0 @@ -generator client { - provider = "prisma-client" - output = "../src/generated/prisma" -{{#if (eq packageManager "deno")}} - runtime = "deno" -{{/if}} -} - -datasource db { - provider = "{{provider}}" -} -{{#if (eq schemaPreset "basic")}} - -model User { - id String @id @default(cuid()) - email String @unique - name String? - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt -} -{{/if}} diff --git a/templates/create/astro/prisma/seed.ts.hbs b/templates/create/astro/prisma/seed.ts.hbs deleted file mode 100644 index dc3d64c..0000000 --- a/templates/create/astro/prisma/seed.ts.hbs +++ /dev/null @@ -1,38 +0,0 @@ -import prisma from "../src/lib/prisma{{#if (eq packageManager "deno")}}.ts{{/if}}"; - -async function main() { -{{#if (eq schemaPreset "basic")}} - const users = await Promise.all([ - prisma.user.upsert({ - where: { email: "alice@prisma.io" }, - update: { name: "Alice" }, - create: { - email: "alice@prisma.io", - name: "Alice", - }, - }), - prisma.user.upsert({ - where: { email: "bob@prisma.io" }, - update: { name: "Bob" }, - create: { - email: "bob@prisma.io", - name: "Bob", - }, - }), - ]); - - console.log(`Seeded ${users.length} users.`); -{{else}} - console.log("No seed data defined for the empty schema preset."); -{{/if}} -} - -main() - .then(async () => { - await prisma.$disconnect(); - }) - .catch(async (error) => { - console.error(error); - await prisma.$disconnect(); - process.exit(1); - }); diff --git a/templates/create/astro/src/lib/prisma.ts.hbs b/templates/create/astro/src/lib/prisma.ts.hbs deleted file mode 100644 index 7152881..0000000 --- a/templates/create/astro/src/lib/prisma.ts.hbs +++ /dev/null @@ -1,55 +0,0 @@ -{{#if (requiresDotenvConfigImport this.packageManager)}} -import "dotenv/config"; -{{/if}} -import { PrismaClient } from "../generated/prisma/client{{#if (eq packageManager "deno")}}.ts{{/if}}"; -{{#if (eq provider "postgresql")}} -import { PrismaPg } from "@prisma/adapter-pg"; -{{/if}} -{{#if (eq provider "cockroachdb")}} -import { PrismaPg } from "@prisma/adapter-pg"; -{{/if}} -{{#if (eq provider "mysql")}} -import { PrismaMariaDb } from "@prisma/adapter-mariadb"; -{{/if}} -{{#if (eq provider "sqlite")}} -import { {{sqliteAdapterClass this.packageManager}} } from "{{sqliteAdapterPackage this.packageManager}}"; -{{/if}} -{{#if (eq provider "sqlserver")}} -import { PrismaMssql } from "@prisma/adapter-mssql"; -{{/if}} - -const rawDatabaseUrl = {{#if (eq packageManager "deno")}}process.env.DATABASE_URL{{else}}import.meta.env?.DATABASE_URL ?? process.env.DATABASE_URL{{/if}}; -{{#if (eq provider "sqlite")}} -const databaseUrl = (rawDatabaseUrl ?? "").trim() || "file:./dev.db"; -{{else}} -const databaseUrl = (rawDatabaseUrl ?? "").trim(); -if (!databaseUrl) { - throw new Error("DATABASE_URL is required"); -} -{{/if}} - -{{#if (eq provider "postgresql")}} -const adapter = new PrismaPg({ - connectionString: databaseUrl, -}); -{{/if}} -{{#if (eq provider "cockroachdb")}} -const adapter = new PrismaPg({ - connectionString: databaseUrl, -}); -{{/if}} -{{#if (eq provider "mysql")}} -const adapter = new PrismaMariaDb(databaseUrl); -{{/if}} -{{#if (eq provider "sqlite")}} -const adapter = new {{sqliteAdapterClass this.packageManager}}({ - url: databaseUrl, -}); -{{/if}} -{{#if (eq provider "sqlserver")}} -const adapter = new PrismaMssql(databaseUrl); -{{/if}} - -const prisma = new PrismaClient({ adapter }); - -export default prisma; diff --git a/templates/create/astro/src/pages/api/users.ts.hbs b/templates/create/astro/src/pages/api/users.ts.hbs index e45b225..604a8d5 100644 --- a/templates/create/astro/src/pages/api/users.ts.hbs +++ b/templates/create/astro/src/pages/api/users.ts.hbs @@ -1,19 +1,12 @@ import type { APIRoute } from "astro"; -{{#if (eq schemaPreset "basic")}} -import prisma from "../../lib/prisma"; + +import { listUsers } from "../../prisma/users"; export const GET: APIRoute = async () => { - const users = await prisma.user - .findMany({ - take: 10, - orderBy: { - createdAt: "desc", - }, - }) - .catch((error) => { - console.error("Failed to query users:", error); - return undefined; - }); + const users = await listUsers(10).catch((error) => { + console.error("Failed to query users:", error); + return undefined; + }); if (!users) { return new Response(JSON.stringify({ error: "Could not query users yet." }), { @@ -30,13 +23,3 @@ export const GET: APIRoute = async () => { }, }); }; -{{else}} - -export const GET: APIRoute = async () => { - return new Response(JSON.stringify([]), { - headers: { - "Content-Type": "application/json", - }, - }); -}; -{{/if}} diff --git a/templates/create/astro/src/pages/index.astro.hbs b/templates/create/astro/src/pages/index.astro.hbs index e8e5810..cb6cec7 100644 --- a/templates/create/astro/src/pages/index.astro.hbs +++ b/templates/create/astro/src/pages/index.astro.hbs @@ -1,21 +1,14 @@ --- -{{#if (eq schemaPreset "basic")}} -import prisma from "../lib/prisma"; + +import { listUsers } from "../prisma/users"; const formatter = new Intl.DateTimeFormat("en", { dateStyle: "medium", timeStyle: "short", }); -const users = await prisma.user - .findMany({ - take: 10, - orderBy: { - createdAt: "desc", - }, - }) - .catch(() => undefined); -{{/if}} +const users = await listUsers(10).catch(() => undefined); + --- @@ -29,12 +22,12 @@ const users = await prisma.user
-

Astro + Prisma 7

-{{#if (eq schemaPreset "basic")}} +

Astro + Prisma 8

+

Users from your database, loaded on the server.

- This page reads from src/pages/index.astro using the Prisma instance in - src/lib/prisma.ts. An Astro API route is also scaffolded in + This page reads from src/pages/index.astro using the Prisma 8 helper in + src/prisma/users.ts. An Astro API route is also scaffolded in src/pages/api/users.ts.

@@ -47,63 +40,32 @@ const users = await prisma.user {!users ? (

- Could not query users yet. Run db:migrate, then db:seed, + Could not query users yet. Run contract:emit and apply your schema, then refresh.

) : users.length === 0 ? ( -

No users yet. Run db:seed after your first migration.

+

No users found.

) : (
    {users.map((user) => (
  • {user.name ?? "Unnamed user"} -

    {user.email}

    +

    {user.username ? `@${user.username}` : user.email}

    - + {user.createdAt ? ( + + ) : ( + No timestamp + )}
  • ))}
)} -{{else}} -

Your Astro app is ready.

-

- Edit prisma/schema.prisma, run db:migrate, then load your data - in Astro pages or API routes with the Prisma instance in src/lib/prisma.ts. -

- -
-
-

What's included

- Starter kit -
- -
    -
  • -
    - Prisma client -

    Use the shared instance from src/lib/prisma.ts.

    -
    -
  • -
  • -
    - API route example -

    See src/pages/api/users.ts for an Astro server endpoint.

    -
    -
  • -
  • -
    - Seed script -

    Run db:seed after your first migration.

    -
    -
  • -
-
-{{/if}}
@@ -171,6 +133,7 @@ const users = await prisma.user .panel-header span, .empty, + .muted, time { color: #888; font-size: 0.8rem; diff --git a/templates/create/astro/tsconfig.json b/templates/create/astro/tsconfig.json index 8bf91d3..7bb947c 100644 --- a/templates/create/astro/tsconfig.json +++ b/templates/create/astro/tsconfig.json @@ -1,5 +1,8 @@ { "extends": "astro/tsconfigs/strict", + "compilerOptions": { + "types": ["astro/client", "node"] + }, "include": [".astro/types.d.ts", "**/*"], "exclude": ["dist"] } diff --git a/templates/create/elysia/README.md.hbs b/templates/create/elysia/README.md.hbs deleted file mode 100644 index 8235621..0000000 --- a/templates/create/elysia/README.md.hbs +++ /dev/null @@ -1,43 +0,0 @@ -# {{projectName}} - -Generated by `create-prisma` with the Elysia template. - -## Scripts - -- `{{runScriptCommand packageManager "dev"}}` - start local dev server with hot reload -- `{{runScriptCommand packageManager "build"}}` - {{#if (eq packageManager "deno")}}type-check the app with Deno{{else}}{{#if (eq packageManager "bun")}}type-check the app for Bun{{else}}typecheck and compile{{/if}}{{/if}} -- `{{runScriptCommand packageManager "start"}}` - {{#if (eq packageManager "deno")}}run the server directly from `src/index.ts` with Deno{{else}}{{#if (eq packageManager "bun")}}run the server directly from `src/index.ts` with Bun{{else}}run compiled server from `dist/`{{/if}}{{/if}} -{{#if compute}} -- `{{runScriptCommand packageManager "compute:deploy"}}` - redeploy to Prisma Compute with environment variables from `.env` -{{/if}} - -## Prisma - -1. Make sure dependencies are installed. -2. Generate Prisma Client: - -`{{runScriptCommand packageManager "db:generate"}}` - -3. Run your first migration: - -`{{runScriptCommand packageManager "db:migrate"}}` - -4. Seed the database: - -`{{runScriptCommand packageManager "db:seed"}}` - -5. Use the Prisma client from `src/lib/prisma.ts`. - -Generated Prisma files are written to `src/generated/prisma`. Prisma Compute deploy defaults are written to `prisma.compute.ts`. -{{#if (eq schemaPreset "basic")}} - -The template includes a basic `User` model, a sample `GET /users` endpoint, and seed data in `prisma/seed.ts`. -{{/if}} -{{#if compute}} - -## Prisma Compute - -This project includes a Prisma Compute deploy script and deploy defaults in `prisma.compute.ts`. Deploys load environment variables from `.env`; if setup created a Prisma Postgres database, its `DATABASE_URL` is already written there. - -After local changes, run `{{runScriptCommand packageManager "compute:deploy"}}` to redeploy. -{{/if}} diff --git a/templates/create/elysia/deno.json.hbs b/templates/create/elysia/deno.json.hbs deleted file mode 100644 index 360f2ea..0000000 --- a/templates/create/elysia/deno.json.hbs +++ /dev/null @@ -1,5 +0,0 @@ -{{#if (eq packageManager "deno")}} -{ - "nodeModulesDir": "auto" -} -{{/if}} diff --git a/templates/create/elysia/package.json.hbs b/templates/create/elysia/package.json.hbs index 18eeb79..81f76b4 100644 --- a/templates/create/elysia/package.json.hbs +++ b/templates/create/elysia/package.json.hbs @@ -5,19 +5,17 @@ "packageManager": "{{packageManagerManifestValue packageManager}}", {{/if}} "type": "module", - "main": "src/index.ts", "scripts": { - "dev": "{{runtimeScript packageManager "dev" "src/index.ts" "dist/src/index.js" denoFlags="--unstable-net"}}", - "build": "{{runtimeScript packageManager "build" "src/index.ts" "dist/src/index.js"}}", - "start": "{{runtimeScript packageManager "start" "src/index.ts" "dist/src/index.js" denoFlags="--unstable-net"}}" + "dev": "tsx watch src/index.ts", + "build": "esbuild src/index.ts --bundle --platform=node --format=esm --outfile=dist/server.mjs", + "start": "node dist/server.mjs" }, "dependencies": { - "@sinclair/typebox": "^0.34.49", - "elysia": "^1.4.29", + "@sinclair/typebox": "^0.34.48", + "elysia": "^1.4.28", "openapi-types": "^12.1.3" }, "devDependencies": { - "@types/node": "^26.0.0", - "typescript": "^6.0.3" + "typescript": "^5.9.3" } } diff --git a/templates/create/elysia/prisma.compute.ts.hbs b/templates/create/elysia/prisma.compute.ts.hbs deleted file mode 100644 index f829d25..0000000 --- a/templates/create/elysia/prisma.compute.ts.hbs +++ /dev/null @@ -1,11 +0,0 @@ -import { defineComputeConfig } from "@prisma/compute-sdk/config"; - -export default defineComputeConfig({ - app: { - name: "{{projectName}}", - framework: "bun", - entry: "src/index.ts", - httpPort: 8080, - env: ".env", - }, -}); diff --git a/templates/create/elysia/prisma.config.ts.hbs b/templates/create/elysia/prisma.config.ts.hbs deleted file mode 100644 index a33e79e..0000000 --- a/templates/create/elysia/prisma.config.ts.hbs +++ /dev/null @@ -1,15 +0,0 @@ -{{#if (requiresPrismaConfigDotenvImport this.packageManager)}} -import "dotenv/config"; -{{/if}} -import { defineConfig, env } from "prisma/config"; - -export default defineConfig({ - schema: "prisma/schema.prisma", - migrations: { - path: "prisma/migrations", - seed: "{{seedCommand this.packageManager}}", - }, - datasource: { - url: env("DATABASE_URL"), - }, -}); diff --git a/templates/create/elysia/prisma/schema.prisma.hbs b/templates/create/elysia/prisma/schema.prisma.hbs deleted file mode 100644 index 2c3e85e..0000000 --- a/templates/create/elysia/prisma/schema.prisma.hbs +++ /dev/null @@ -1,25 +0,0 @@ -generator client { - provider = "prisma-client" - output = "../src/generated/prisma" -{{#if (eq packageManager "deno")}} - runtime = "deno" -{{else}} -{{#if (eq packageManager "bun")}} - runtime = "bun" -{{/if}} -{{/if}} -} - -datasource db { - provider = "{{provider}}" -} -{{#if (eq schemaPreset "basic")}} - -model User { - id String @id @default(cuid()) - email String @unique - name String? - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt -} -{{/if}} diff --git a/templates/create/elysia/prisma/seed.ts.hbs b/templates/create/elysia/prisma/seed.ts.hbs deleted file mode 100644 index dc3d64c..0000000 --- a/templates/create/elysia/prisma/seed.ts.hbs +++ /dev/null @@ -1,38 +0,0 @@ -import prisma from "../src/lib/prisma{{#if (eq packageManager "deno")}}.ts{{/if}}"; - -async function main() { -{{#if (eq schemaPreset "basic")}} - const users = await Promise.all([ - prisma.user.upsert({ - where: { email: "alice@prisma.io" }, - update: { name: "Alice" }, - create: { - email: "alice@prisma.io", - name: "Alice", - }, - }), - prisma.user.upsert({ - where: { email: "bob@prisma.io" }, - update: { name: "Bob" }, - create: { - email: "bob@prisma.io", - name: "Bob", - }, - }), - ]); - - console.log(`Seeded ${users.length} users.`); -{{else}} - console.log("No seed data defined for the empty schema preset."); -{{/if}} -} - -main() - .then(async () => { - await prisma.$disconnect(); - }) - .catch(async (error) => { - console.error(error); - await prisma.$disconnect(); - process.exit(1); - }); diff --git a/templates/create/elysia/src/index.ts.hbs b/templates/create/elysia/src/index.ts.hbs index 2c1b875..2e22f31 100644 --- a/templates/create/elysia/src/index.ts.hbs +++ b/templates/create/elysia/src/index.ts.hbs @@ -1,43 +1,34 @@ -{{#if (requiresDotenvConfigImport packageManager)}} -import "dotenv/config"; -{{/if}} -{{#if (eq packageManager "deno")}} -{{else}} import { node } from "@elysiajs/node"; -{{/if}} import { Elysia } from "elysia"; -{{#if (eq schemaPreset "basic")}} -import { prisma } from "./lib/prisma{{#if (eq packageManager "deno")}}.ts{{/if}}"; -{{/if}} -const rawPort = ({{#if (eq packageManager "deno")}}Deno.env.get("PORT"){{else}}process.env.PORT{{/if}} ?? "").trim(); +import { listUsers } from "./prisma/users"; + +const rawPort = (process.env.PORT ?? "").trim(); const parsedPort = rawPort.length > 0 ? Number(rawPort) : Number.NaN; const port = - Number.isInteger(parsedPort) && parsedPort >= 0 && parsedPort <= 65535 ? parsedPort : 8080; + Number.isInteger(parsedPort) && parsedPort >= 0 && parsedPort <= 65535 ? parsedPort : 3000; -const app = new Elysia({{#if (eq packageManager "deno")}}{{else}}{ adapter: node() }{{/if}}) +const app = new Elysia({ adapter: "Bun" in globalThis ? undefined : node() }) .get("/", () => { return { message: "hello from create-prisma + elysia", }; }) -{{#if (eq schemaPreset "basic")}} - .get("/users", async () => { - return prisma.user.findMany({ - take: 10, - orderBy: { - createdAt: "desc", - }, + + .get("/users", async ({ set }) => { + const users = await listUsers(10).catch((error) => { + console.error("Failed to query users:", error); + return undefined; }); + + if (!users) { + set.status = 500; + return { error: "Could not query users yet. Run contract:emit and apply your schema first." }; + } + + return users; }) -{{/if}} -{{#if (eq packageManager "deno")}} - ; -Deno.serve({ port }, app.fetch); -console.log(`Server running at http://localhost:${port}`); -{{else}} - .listen(port); + .listen({ port, hostname: "0.0.0.0" }); console.log(`Server running at http://localhost:${app.server?.port ?? port}`); -{{/if}} diff --git a/templates/create/elysia/src/lib/prisma.ts.hbs b/templates/create/elysia/src/lib/prisma.ts.hbs deleted file mode 100644 index 6193f37..0000000 --- a/templates/create/elysia/src/lib/prisma.ts.hbs +++ /dev/null @@ -1,56 +0,0 @@ -{{#if (requiresDotenvConfigImport packageManager)}} -import "dotenv/config"; -{{/if}} -import { PrismaClient } from "../generated/prisma/client{{#if (eq packageManager "deno")}}.ts{{/if}}"; -{{#if (eq provider "postgresql")}} -import { PrismaPg } from "@prisma/adapter-pg"; -{{/if}} -{{#if (eq provider "cockroachdb")}} -import { PrismaPg } from "@prisma/adapter-pg"; -{{/if}} -{{#if (eq provider "mysql")}} -import { PrismaMariaDb } from "@prisma/adapter-mariadb"; -{{/if}} -{{#if (eq provider "sqlite")}} -import { {{sqliteAdapterClass packageManager}} } from "{{sqliteAdapterPackage packageManager}}"; -{{/if}} -{{#if (eq provider "sqlserver")}} -import { PrismaMssql } from "@prisma/adapter-mssql"; -{{/if}} - -const rawDatabaseUrl = process.env.DATABASE_URL; -{{#if (eq provider "sqlite")}} -const databaseUrl = (rawDatabaseUrl ?? "").trim() || "file:./dev.db"; -{{else}} -const databaseUrl = (rawDatabaseUrl ?? "").trim(); -if (!databaseUrl) { - throw new Error("DATABASE_URL is required"); -} -{{/if}} - -{{#if (eq provider "postgresql")}} -const adapter = new PrismaPg({ - connectionString: databaseUrl, -}); -{{/if}} -{{#if (eq provider "cockroachdb")}} -const adapter = new PrismaPg({ - connectionString: databaseUrl, -}); -{{/if}} -{{#if (eq provider "mysql")}} -const adapter = new PrismaMariaDb(databaseUrl); -{{/if}} -{{#if (eq provider "sqlite")}} -const adapter = new {{sqliteAdapterClass packageManager}}({ - url: databaseUrl, -}); -{{/if}} -{{#if (eq provider "sqlserver")}} -const adapter = new PrismaMssql(databaseUrl); -{{/if}} - -const prisma = new PrismaClient({ adapter }); - -export { prisma }; -export default prisma; diff --git a/templates/create/elysia/tsconfig.json b/templates/create/elysia/tsconfig.json index cb7f4c1..f85f59d 100644 --- a/templates/create/elysia/tsconfig.json +++ b/templates/create/elysia/tsconfig.json @@ -3,13 +3,14 @@ "target": "ES2022", "module": "ESNext", "moduleResolution": "Bundler", + "resolveJsonModule": true, "verbatimModuleSyntax": true, "strict": true, "esModuleInterop": true, "skipLibCheck": true, - "types": ["node"], "forceConsistentCasingInFileNames": true, "outDir": "dist", - "rootDir": "." + "rootDir": ".", + "types": ["node"] } } diff --git a/templates/create/hono/README.md.hbs b/templates/create/hono/README.md.hbs deleted file mode 100644 index 0d1e456..0000000 --- a/templates/create/hono/README.md.hbs +++ /dev/null @@ -1,43 +0,0 @@ -# {{projectName}} - -Generated by `create-prisma` with the Hono template. - -## Scripts - -- `{{runScriptCommand packageManager "dev"}}` - start local dev server -- `{{runScriptCommand packageManager "build"}}` - {{#if (eq packageManager "deno")}}type-check the app with Deno{{else}}{{#if (eq packageManager "bun")}}type-check the app for Bun{{else}}typecheck and compile{{/if}}{{/if}} -- `{{runScriptCommand packageManager "start"}}` - {{#if (eq packageManager "deno")}}run the server directly from `src/index.ts` with Deno{{else}}{{#if (eq packageManager "bun")}}run the server directly from `src/index.ts` with Bun{{else}}run compiled server from `dist/`{{/if}}{{/if}} -{{#if compute}} -- `{{runScriptCommand packageManager "compute:deploy"}}` - redeploy to Prisma Compute with environment variables from `.env` -{{/if}} - -## Prisma - -1. Make sure dependencies are installed. -2. Generate Prisma Client: - -`{{runScriptCommand packageManager "db:generate"}}` - -3. Run your first migration: - -`{{runScriptCommand packageManager "db:migrate"}}` - -4. Seed the database: - -`{{runScriptCommand packageManager "db:seed"}}` - -5. Use the Prisma client from `src/lib/prisma.ts`. - -Generated Prisma files are written to `src/generated/prisma`. Prisma Compute deploy defaults are written to `prisma.compute.ts`. -{{#if (eq schemaPreset "basic")}} - -The template includes a basic `User` model, a sample `GET /users` endpoint, and seed data in `prisma/seed.ts`. -{{/if}} -{{#if compute}} - -## Prisma Compute - -This project includes a Prisma Compute deploy script and deploy defaults in `prisma.compute.ts`. Deploys load environment variables from `.env`; if setup created a Prisma Postgres database, its `DATABASE_URL` is already written there. - -After local changes, run `{{runScriptCommand packageManager "compute:deploy"}}` to redeploy. -{{/if}} diff --git a/templates/create/hono/deno.json.hbs b/templates/create/hono/deno.json.hbs deleted file mode 100644 index 360f2ea..0000000 --- a/templates/create/hono/deno.json.hbs +++ /dev/null @@ -1,5 +0,0 @@ -{{#if (eq packageManager "deno")}} -{ - "nodeModulesDir": "auto" -} -{{/if}} diff --git a/templates/create/hono/package.json.hbs b/templates/create/hono/package.json.hbs index 9f3b78d..4cf510d 100644 --- a/templates/create/hono/package.json.hbs +++ b/templates/create/hono/package.json.hbs @@ -5,18 +5,17 @@ "packageManager": "{{packageManagerManifestValue packageManager}}", {{/if}} "type": "module", - "main": "src/index.ts", "scripts": { "dev": "{{runtimeScript packageManager "dev" "src/index.ts" "dist/src/index.js"}}", - "build": "{{runtimeScript packageManager "build" "src/index.ts" "dist/src/index.js"}}", - "start": "{{runtimeScript packageManager "start" "src/index.ts" "dist/src/index.js"}}" + "build": "esbuild src/index.ts --bundle --platform=node --format=esm --outfile=dist/server.mjs", + "start": "node dist/server.mjs" }, "dependencies": { - "@hono/node-server": "^2.0.6", - "hono": "^4.12.27" + "@hono/node-server": "^1.19.9", + "hono": "^4.12.2" }, "devDependencies": { - "@types/node": "^26.0.0", - "typescript": "^6.0.3" + "@types/node": "^20.11.17", + "typescript": "^5.9.3" } } diff --git a/templates/create/hono/prisma.compute.ts.hbs b/templates/create/hono/prisma.compute.ts.hbs deleted file mode 100644 index 711b2a2..0000000 --- a/templates/create/hono/prisma.compute.ts.hbs +++ /dev/null @@ -1,10 +0,0 @@ -import { defineComputeConfig } from "@prisma/compute-sdk/config"; - -export default defineComputeConfig({ - app: { - name: "{{projectName}}", - framework: "hono", - httpPort: 8080, - env: ".env", - }, -}); diff --git a/templates/create/hono/prisma.config.ts.hbs b/templates/create/hono/prisma.config.ts.hbs deleted file mode 100644 index a33e79e..0000000 --- a/templates/create/hono/prisma.config.ts.hbs +++ /dev/null @@ -1,15 +0,0 @@ -{{#if (requiresPrismaConfigDotenvImport this.packageManager)}} -import "dotenv/config"; -{{/if}} -import { defineConfig, env } from "prisma/config"; - -export default defineConfig({ - schema: "prisma/schema.prisma", - migrations: { - path: "prisma/migrations", - seed: "{{seedCommand this.packageManager}}", - }, - datasource: { - url: env("DATABASE_URL"), - }, -}); diff --git a/templates/create/hono/prisma/schema.prisma.hbs b/templates/create/hono/prisma/schema.prisma.hbs deleted file mode 100644 index 2c3e85e..0000000 --- a/templates/create/hono/prisma/schema.prisma.hbs +++ /dev/null @@ -1,25 +0,0 @@ -generator client { - provider = "prisma-client" - output = "../src/generated/prisma" -{{#if (eq packageManager "deno")}} - runtime = "deno" -{{else}} -{{#if (eq packageManager "bun")}} - runtime = "bun" -{{/if}} -{{/if}} -} - -datasource db { - provider = "{{provider}}" -} -{{#if (eq schemaPreset "basic")}} - -model User { - id String @id @default(cuid()) - email String @unique - name String? - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt -} -{{/if}} diff --git a/templates/create/hono/prisma/seed.ts.hbs b/templates/create/hono/prisma/seed.ts.hbs deleted file mode 100644 index dc3d64c..0000000 --- a/templates/create/hono/prisma/seed.ts.hbs +++ /dev/null @@ -1,38 +0,0 @@ -import prisma from "../src/lib/prisma{{#if (eq packageManager "deno")}}.ts{{/if}}"; - -async function main() { -{{#if (eq schemaPreset "basic")}} - const users = await Promise.all([ - prisma.user.upsert({ - where: { email: "alice@prisma.io" }, - update: { name: "Alice" }, - create: { - email: "alice@prisma.io", - name: "Alice", - }, - }), - prisma.user.upsert({ - where: { email: "bob@prisma.io" }, - update: { name: "Bob" }, - create: { - email: "bob@prisma.io", - name: "Bob", - }, - }), - ]); - - console.log(`Seeded ${users.length} users.`); -{{else}} - console.log("No seed data defined for the empty schema preset."); -{{/if}} -} - -main() - .then(async () => { - await prisma.$disconnect(); - }) - .catch(async (error) => { - console.error(error); - await prisma.$disconnect(); - process.exit(1); - }); diff --git a/templates/create/hono/src/index.ts.hbs b/templates/create/hono/src/index.ts.hbs index 2858833..0918fbe 100644 --- a/templates/create/hono/src/index.ts.hbs +++ b/templates/create/hono/src/index.ts.hbs @@ -1,11 +1,7 @@ -{{#if (requiresDotenvConfigImport packageManager)}} -import "dotenv/config"; -{{/if}} import { serve } from "@hono/node-server"; import { Hono } from "hono"; -{{#if (eq schemaPreset "basic")}} -import { prisma } from "./lib/prisma{{#if (eq packageManager "deno")}}.ts{{/if}}"; -{{/if}} + +import { listUsers } from "./prisma/users"; const app = new Hono(); @@ -14,24 +10,24 @@ app.get("/", (c) => { message: "hello from create-prisma + hono", }); }); -{{#if (eq schemaPreset "basic")}} app.get("/users", async (c) => { - const users = await prisma.user.findMany({ - take: 10, - orderBy: { - createdAt: "desc", - }, + const users = await listUsers(10).catch((error) => { + console.error("Failed to query users:", error); + return undefined; }); + if (!users) { + return c.json({ error: "Could not query users yet. Run contract:emit and apply your schema first." }, 500); + } + return c.json(users); }); -{{/if}} -const rawPort = ({{#if (eq packageManager "deno")}}Deno.env.get("PORT"){{else}}process.env.PORT{{/if}} ?? "").trim(); +const rawPort = (process.env.PORT ?? "").trim(); const parsedPort = rawPort.length > 0 ? Number(rawPort) : Number.NaN; const port = - Number.isInteger(parsedPort) && parsedPort >= 0 && parsedPort <= 65535 ? parsedPort : 8080; + Number.isInteger(parsedPort) && parsedPort >= 0 && parsedPort <= 65535 ? parsedPort : 3000; serve({ fetch: app.fetch, port, diff --git a/templates/create/hono/src/lib/prisma.ts.hbs b/templates/create/hono/src/lib/prisma.ts.hbs deleted file mode 100644 index 6193f37..0000000 --- a/templates/create/hono/src/lib/prisma.ts.hbs +++ /dev/null @@ -1,56 +0,0 @@ -{{#if (requiresDotenvConfigImport packageManager)}} -import "dotenv/config"; -{{/if}} -import { PrismaClient } from "../generated/prisma/client{{#if (eq packageManager "deno")}}.ts{{/if}}"; -{{#if (eq provider "postgresql")}} -import { PrismaPg } from "@prisma/adapter-pg"; -{{/if}} -{{#if (eq provider "cockroachdb")}} -import { PrismaPg } from "@prisma/adapter-pg"; -{{/if}} -{{#if (eq provider "mysql")}} -import { PrismaMariaDb } from "@prisma/adapter-mariadb"; -{{/if}} -{{#if (eq provider "sqlite")}} -import { {{sqliteAdapterClass packageManager}} } from "{{sqliteAdapterPackage packageManager}}"; -{{/if}} -{{#if (eq provider "sqlserver")}} -import { PrismaMssql } from "@prisma/adapter-mssql"; -{{/if}} - -const rawDatabaseUrl = process.env.DATABASE_URL; -{{#if (eq provider "sqlite")}} -const databaseUrl = (rawDatabaseUrl ?? "").trim() || "file:./dev.db"; -{{else}} -const databaseUrl = (rawDatabaseUrl ?? "").trim(); -if (!databaseUrl) { - throw new Error("DATABASE_URL is required"); -} -{{/if}} - -{{#if (eq provider "postgresql")}} -const adapter = new PrismaPg({ - connectionString: databaseUrl, -}); -{{/if}} -{{#if (eq provider "cockroachdb")}} -const adapter = new PrismaPg({ - connectionString: databaseUrl, -}); -{{/if}} -{{#if (eq provider "mysql")}} -const adapter = new PrismaMariaDb(databaseUrl); -{{/if}} -{{#if (eq provider "sqlite")}} -const adapter = new {{sqliteAdapterClass packageManager}}({ - url: databaseUrl, -}); -{{/if}} -{{#if (eq provider "sqlserver")}} -const adapter = new PrismaMssql(databaseUrl); -{{/if}} - -const prisma = new PrismaClient({ adapter }); - -export { prisma }; -export default prisma; diff --git a/templates/create/hono/tsconfig.json b/templates/create/hono/tsconfig.json index cb7f4c1..f85f59d 100644 --- a/templates/create/hono/tsconfig.json +++ b/templates/create/hono/tsconfig.json @@ -3,13 +3,14 @@ "target": "ES2022", "module": "ESNext", "moduleResolution": "Bundler", + "resolveJsonModule": true, "verbatimModuleSyntax": true, "strict": true, "esModuleInterop": true, "skipLibCheck": true, - "types": ["node"], "forceConsistentCasingInFileNames": true, "outDir": "dist", - "rootDir": "." + "rootDir": ".", + "types": ["node"] } } diff --git a/templates/create/turborepo/packages/db/.gitignore b/templates/create/minimal/.gitignore similarity index 78% rename from templates/create/turborepo/packages/db/.gitignore rename to templates/create/minimal/.gitignore index fc59393..e272fb5 100644 --- a/templates/create/turborepo/packages/db/.gitignore +++ b/templates/create/minimal/.gitignore @@ -1,4 +1,5 @@ -src/generated node_modules dist +.DS_Store .env +src/generated diff --git a/templates/create/turborepo/.yarnrc.yml.hbs b/templates/create/minimal/.yarnrc.yml.hbs similarity index 100% rename from templates/create/turborepo/.yarnrc.yml.hbs rename to templates/create/minimal/.yarnrc.yml.hbs diff --git a/templates/create/minimal/package.json.hbs b/templates/create/minimal/package.json.hbs new file mode 100644 index 0000000..d801711 --- /dev/null +++ b/templates/create/minimal/package.json.hbs @@ -0,0 +1,15 @@ +{ + "name": "{{projectName}}", + "private": true, + {{#if (packageManagerManifestValue packageManager)}} + "packageManager": "{{packageManagerManifestValue packageManager}}", + {{/if}} + "type": "module", + "scripts": { + "dev": "tsx watch src/index.ts", + "build": "esbuild src/index.ts --bundle --platform=node --format=esm --outfile=dist/server.mjs", + "start": "node dist/server.mjs" + }, + "dependencies": {}, + "devDependencies": {} +} diff --git a/templates/create/minimal/src/index.ts.hbs b/templates/create/minimal/src/index.ts.hbs new file mode 100644 index 0000000..fe17f17 --- /dev/null +++ b/templates/create/minimal/src/index.ts.hbs @@ -0,0 +1,19 @@ +import { createServer } from "node:http"; + +import { listUsers } from "./prisma/users"; + +const port = Number(process.env.PORT ?? 3000); + +createServer(async (_request, response) => { + try { + const users = await listUsers(); + response.writeHead(200, { "content-type": "application/json" }); + response.end(JSON.stringify({ users })); + } catch (error) { + console.error("Failed to query users:", error); + response.writeHead(500, { "content-type": "application/json" }); + response.end(JSON.stringify({ error: "Could not query users yet." })); + } +}).listen(port, "0.0.0.0", () => { + console.log(`Server running at http://localhost:${port}`); +}); diff --git a/templates/create/turborepo/apps/api/tsconfig.json b/templates/create/minimal/tsconfig.json similarity index 82% rename from templates/create/turborepo/apps/api/tsconfig.json rename to templates/create/minimal/tsconfig.json index 7c7028e..b4edbd2 100644 --- a/templates/create/turborepo/apps/api/tsconfig.json +++ b/templates/create/minimal/tsconfig.json @@ -3,14 +3,13 @@ "target": "ES2022", "module": "ESNext", "moduleResolution": "Bundler", + "resolveJsonModule": true, "verbatimModuleSyntax": true, "strict": true, "esModuleInterop": true, "skipLibCheck": true, - "types": ["node"], "forceConsistentCasingInFileNames": true, - "outDir": "dist", - "rootDir": "." + "types": ["node"] }, "include": ["src/**/*.ts"] } diff --git a/templates/create/nest/README.md.hbs b/templates/create/nest/README.md.hbs deleted file mode 100644 index bc18c4f..0000000 --- a/templates/create/nest/README.md.hbs +++ /dev/null @@ -1,43 +0,0 @@ -# {{projectName}} - -Generated by `create-prisma` with the NestJS template. - -## Scripts - -- `{{runScriptCommand packageManager "dev"}}` - start the Nest dev server with watch mode -- `{{runScriptCommand packageManager "build"}}` - {{#if (eq packageManager "deno")}}type-check the app with Deno{{else}}{{#if (eq packageManager "bun")}}type-check the app for Bun{{else}}compile the app into `dist/`{{/if}}{{/if}} -- `{{runScriptCommand packageManager "start"}}` - {{#if (eq packageManager "deno")}}run the server directly from `src/main.ts` with Deno{{else}}{{#if (eq packageManager "bun")}}run the server directly from `src/main.ts` with Bun{{else}}run the compiled server from `dist/main.js`{{/if}}{{/if}} -{{#if compute}} -- `{{runScriptCommand packageManager "compute:deploy"}}` - redeploy to Prisma Compute with environment variables from `.env` -{{/if}} - -## Prisma - -1. Make sure dependencies are installed. -2. Generate Prisma Client: - -`{{runScriptCommand packageManager "db:generate"}}` - -3. Run your first migration: - -`{{runScriptCommand packageManager "db:migrate"}}` - -4. Seed the database: - -`{{runScriptCommand packageManager "db:seed"}}` - -5. Use the shared Prisma setup from `src/lib/prisma.ts` and inject `PrismaService` from `src/prisma.service.ts` inside Nest providers. - -Generated Prisma files are written to `src/generated/prisma`. -{{#if (eq schemaPreset "basic")}} - -The template includes a basic `User` model, a sample `GET /users` endpoint, and seed data in `prisma/seed.ts`. -{{/if}} -{{#if compute}} - -## Prisma Compute - -This project includes a Prisma Compute deploy script. Deploys load environment variables from `.env`; if setup created a Prisma Postgres database, its `DATABASE_URL` is already written there. - -After local changes, run `{{runScriptCommand packageManager "compute:deploy"}}` to redeploy. -{{/if}} diff --git a/templates/create/nest/deno.json.hbs b/templates/create/nest/deno.json.hbs deleted file mode 100644 index 360f2ea..0000000 --- a/templates/create/nest/deno.json.hbs +++ /dev/null @@ -1,5 +0,0 @@ -{{#if (eq packageManager "deno")}} -{ - "nodeModulesDir": "auto" -} -{{/if}} diff --git a/templates/create/nest/package.json.hbs b/templates/create/nest/package.json.hbs index 9bd7d7a..21388c4 100644 --- a/templates/create/nest/package.json.hbs +++ b/templates/create/nest/package.json.hbs @@ -7,18 +7,18 @@ "type": "module", "scripts": { "dev": "{{runtimeScript packageManager "dev" "src/main.ts" "dist/main.js"}}", - "build": "{{runtimeScript packageManager "build" "src/main.ts" "dist/main.js" emit=true}}", - "start": "{{runtimeScript packageManager "start" "src/main.ts" "dist/main.js"}}" + "build": "esbuild src/main.ts --bundle --platform=node --format=esm --outfile=dist/server.mjs --banner:js=\"import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);\" --external:'@nestjs/websockets/*' --external:@nestjs/microservices --external:'@nestjs/microservices/*' --external:@nestjs/platform-socket.io --external:class-transformer --external:class-validator", + "start": "node dist/server.mjs" }, "dependencies": { - "@nestjs/common": "^11.1.27", - "@nestjs/core": "^11.1.27", - "@nestjs/platform-express": "^11.1.27", + "@nestjs/common": "^11.1.17", + "@nestjs/core": "^11.1.17", + "@nestjs/platform-express": "^11.1.17", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.2" }, "devDependencies": { - "@types/node": "^26.0.0", - "typescript": "^6.0.3" + "@types/node": "^25.5.0", + "typescript": "^5.9.3" } } diff --git a/templates/create/nest/prisma.compute.ts.hbs b/templates/create/nest/prisma.compute.ts.hbs deleted file mode 100644 index 6f7bb0a..0000000 --- a/templates/create/nest/prisma.compute.ts.hbs +++ /dev/null @@ -1,10 +0,0 @@ -import { defineComputeConfig } from "@prisma/compute-sdk/config"; - -export default defineComputeConfig({ - app: { - name: "{{projectName}}", - framework: "nestjs", - httpPort: 3000, - env: ".env", - }, -}); diff --git a/templates/create/nest/prisma.config.ts.hbs b/templates/create/nest/prisma.config.ts.hbs deleted file mode 100644 index a33e79e..0000000 --- a/templates/create/nest/prisma.config.ts.hbs +++ /dev/null @@ -1,15 +0,0 @@ -{{#if (requiresPrismaConfigDotenvImport this.packageManager)}} -import "dotenv/config"; -{{/if}} -import { defineConfig, env } from "prisma/config"; - -export default defineConfig({ - schema: "prisma/schema.prisma", - migrations: { - path: "prisma/migrations", - seed: "{{seedCommand this.packageManager}}", - }, - datasource: { - url: env("DATABASE_URL"), - }, -}); diff --git a/templates/create/nest/prisma/schema.prisma.hbs b/templates/create/nest/prisma/schema.prisma.hbs deleted file mode 100644 index 2c3e85e..0000000 --- a/templates/create/nest/prisma/schema.prisma.hbs +++ /dev/null @@ -1,25 +0,0 @@ -generator client { - provider = "prisma-client" - output = "../src/generated/prisma" -{{#if (eq packageManager "deno")}} - runtime = "deno" -{{else}} -{{#if (eq packageManager "bun")}} - runtime = "bun" -{{/if}} -{{/if}} -} - -datasource db { - provider = "{{provider}}" -} -{{#if (eq schemaPreset "basic")}} - -model User { - id String @id @default(cuid()) - email String @unique - name String? - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt -} -{{/if}} diff --git a/templates/create/nest/prisma/seed.ts.hbs b/templates/create/nest/prisma/seed.ts.hbs deleted file mode 100644 index f9aa65f..0000000 --- a/templates/create/nest/prisma/seed.ts.hbs +++ /dev/null @@ -1,40 +0,0 @@ -import { createPrismaClient } from "../src/lib/prisma{{#if (eq packageManager "deno")}}.ts{{/if}}"; - -const prisma = createPrismaClient(); - -async function main() { -{{#if (eq schemaPreset "basic")}} - const users = await Promise.all([ - prisma.user.upsert({ - where: { email: "alice@prisma.io" }, - update: { name: "Alice" }, - create: { - email: "alice@prisma.io", - name: "Alice", - }, - }), - prisma.user.upsert({ - where: { email: "bob@prisma.io" }, - update: { name: "Bob" }, - create: { - email: "bob@prisma.io", - name: "Bob", - }, - }), - ]); - - console.log(`Seeded ${users.length} users.`); -{{else}} - console.log("No seed data defined for the empty schema preset."); -{{/if}} -} - -main() - .then(async () => { - await prisma.$disconnect(); - }) - .catch(async (error) => { - console.error(error); - await prisma.$disconnect(); - process.exit(1); - }); diff --git a/templates/create/nest/src/app.module.ts.hbs b/templates/create/nest/src/app.module.ts.hbs index d9346bd..67d6a94 100644 --- a/templates/create/nest/src/app.module.ts.hbs +++ b/templates/create/nest/src/app.module.ts.hbs @@ -1,20 +1,19 @@ import { Module } from "@nestjs/common"; -import { AppController } from "./app.controller{{#if (eq packageManager "deno")}}.ts{{/if}}"; -import { PrismaService } from "./prisma.service{{#if (eq packageManager "deno")}}.ts{{/if}}"; -{{#if (eq schemaPreset "basic")}} -import { UsersController } from "./users.controller{{#if (eq packageManager "deno")}}.ts{{/if}}"; -import { UsersService } from "./users.service{{#if (eq packageManager "deno")}}.ts{{/if}}"; -{{/if}} +import { AppController } from "./app.controller"; +import { PrismaService } from "./prisma.service"; + +import { UsersController } from "./users.controller"; +import { UsersService } from "./users.service"; @Module({ imports: [], controllers: [ - AppController{{#if (eq schemaPreset "basic")}}, - UsersController{{/if}} + AppController, + UsersController ], providers: [ - PrismaService{{#if (eq schemaPreset "basic")}}, - UsersService{{/if}} + PrismaService, + UsersService ], }) export class AppModule {} diff --git a/templates/create/nest/src/lib/prisma.ts.hbs b/templates/create/nest/src/lib/prisma.ts.hbs deleted file mode 100644 index 1711554..0000000 --- a/templates/create/nest/src/lib/prisma.ts.hbs +++ /dev/null @@ -1,58 +0,0 @@ -{{#if (requiresDotenvConfigImport packageManager)}} -import "dotenv/config"; -{{/if}} - -import { PrismaClient } from "../generated/prisma/client{{#if (eq packageManager "deno")}}.ts{{/if}}"; -{{#if (eq provider "postgresql")}} -import { PrismaPg } from "@prisma/adapter-pg"; -{{/if}} -{{#if (eq provider "cockroachdb")}} -import { PrismaPg } from "@prisma/adapter-pg"; -{{/if}} -{{#if (eq provider "mysql")}} -import { PrismaMariaDb } from "@prisma/adapter-mariadb"; -{{/if}} -{{#if (eq provider "sqlite")}} -import { {{sqliteAdapterClass packageManager}} } from "{{sqliteAdapterPackage packageManager}}"; -{{/if}} -{{#if (eq provider "sqlserver")}} -import { PrismaMssql } from "@prisma/adapter-mssql"; -{{/if}} - -const rawDatabaseUrl = process.env.DATABASE_URL; -{{#if (eq provider "sqlite")}} -const databaseUrl = (rawDatabaseUrl ?? "").trim() || "file:./dev.db"; -{{else}} -const databaseUrl = (rawDatabaseUrl ?? "").trim(); -if (!databaseUrl) { - throw new Error("DATABASE_URL is required"); -} -{{/if}} - -{{#if (eq provider "postgresql")}} -const adapter = new PrismaPg({ - connectionString: databaseUrl, -}); -{{/if}} -{{#if (eq provider "cockroachdb")}} -const adapter = new PrismaPg({ - connectionString: databaseUrl, -}); -{{/if}} -{{#if (eq provider "mysql")}} -const adapter = new PrismaMariaDb(databaseUrl); -{{/if}} -{{#if (eq provider "sqlite")}} -const adapter = new {{sqliteAdapterClass packageManager}}({ - url: databaseUrl, -}); -{{/if}} -{{#if (eq provider "sqlserver")}} -const adapter = new PrismaMssql(databaseUrl); -{{/if}} - -export const prismaClientOptions = { adapter }; - -export function createPrismaClient() { - return new PrismaClient(prismaClientOptions); -} diff --git a/templates/create/nest/src/main.ts.hbs b/templates/create/nest/src/main.ts.hbs index f3906b9..9ffc8f2 100644 --- a/templates/create/nest/src/main.ts.hbs +++ b/templates/create/nest/src/main.ts.hbs @@ -1,27 +1,20 @@ import "reflect-metadata"; -{{#if (requiresDotenvConfigImport packageManager)}} -import "dotenv/config"; -{{/if}} import { NestFactory } from "@nestjs/core"; -import { AppModule } from "./app.module{{#if (eq packageManager "deno")}}.ts{{/if}}"; +import { AppModule } from "./app.module"; async function bootstrap() { const app = await NestFactory.create(AppModule); - const rawPort = ({{#if (eq packageManager "deno")}}Deno.env.get("PORT"){{else}}process.env.PORT{{/if}} ?? "").trim(); + const rawPort = (process.env.PORT ?? "").trim(); const parsedPort = rawPort.length > 0 ? Number(rawPort) : Number.NaN; const port = Number.isFinite(parsedPort) && parsedPort >= 0 && parsedPort <= 65535 ? parsedPort : 3000; - await app.listen(port, "0.0.0.0"); + await app.listen(port); console.log(`Server running at http://localhost:${port}`); } bootstrap().catch((error) => { console.error("Failed to start server", error); - {{#if (eq packageManager "deno")}} - Deno.exit(1); - {{else}} process.exit(1); - {{/if}} }); diff --git a/templates/create/nest/src/prisma.service.ts.hbs b/templates/create/nest/src/prisma.service.ts.hbs index 2f54ea5..f605465 100644 --- a/templates/create/nest/src/prisma.service.ts.hbs +++ b/templates/create/nest/src/prisma.service.ts.hbs @@ -1,10 +1,11 @@ import { Injectable } from "@nestjs/common"; -import { PrismaClient } from "./generated/prisma/client{{#if (eq packageManager "deno")}}.ts{{/if}}"; -import { prismaClientOptions } from "./lib/prisma{{#if (eq packageManager "deno")}}.ts{{/if}}"; +import { db, listUsers, type StarterUser } from "./prisma/users"; @Injectable() -export class PrismaService extends PrismaClient { - constructor() { - super(prismaClientOptions); +export class PrismaService { + readonly db = db; + + listUsers(limit = 10): Promise { + return listUsers(limit); } } diff --git a/templates/create/nest/src/users.controller.ts.hbs b/templates/create/nest/src/users.controller.ts.hbs index 7d21cd1..f799b28 100644 --- a/templates/create/nest/src/users.controller.ts.hbs +++ b/templates/create/nest/src/users.controller.ts.hbs @@ -1,15 +1,13 @@ -{{#if (eq schemaPreset "basic")}} -import { Controller, Get } from "@nestjs/common"; +import { Controller, Get, Inject } from "@nestjs/common"; -import { UsersService } from "./users.service{{#if (eq packageManager "deno")}}.ts{{/if}}"; +import { UsersService } from "./users.service"; @Controller("users") export class UsersController { - constructor(private readonly usersService: UsersService) {} + constructor(@Inject(UsersService) private readonly usersService: UsersService) {} @Get() findAll() { return this.usersService.findAll(); } } -{{/if}} diff --git a/templates/create/nest/src/users.service.ts.hbs b/templates/create/nest/src/users.service.ts.hbs index eec309b..60c873d 100644 --- a/templates/create/nest/src/users.service.ts.hbs +++ b/templates/create/nest/src/users.service.ts.hbs @@ -1,19 +1,12 @@ -{{#if (eq schemaPreset "basic")}} -import { Injectable } from "@nestjs/common"; +import { Inject, Injectable } from "@nestjs/common"; -import { PrismaService } from "./prisma.service{{#if (eq packageManager "deno")}}.ts{{/if}}"; +import { PrismaService } from "./prisma.service"; @Injectable() export class UsersService { - constructor(private readonly prisma: PrismaService) {} + constructor(@Inject(PrismaService) private readonly prisma: PrismaService) {} async findAll() { - return this.prisma.user.findMany({ - take: 10, - orderBy: { - createdAt: "desc", - }, - }); + return this.prisma.listUsers(10); } } -{{/if}} diff --git a/templates/create/nest/tsconfig.json b/templates/create/nest/tsconfig.json index d6db30a..3fa1273 100644 --- a/templates/create/nest/tsconfig.json +++ b/templates/create/nest/tsconfig.json @@ -3,16 +3,16 @@ "target": "ES2022", "module": "ESNext", "moduleResolution": "Bundler", + "resolveJsonModule": true, "verbatimModuleSyntax": true, "strict": true, "esModuleInterop": true, "skipLibCheck": true, - "types": ["node"], "forceConsistentCasingInFileNames": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, - "rootDir": "src", - "outDir": "dist" + "outDir": "dist", + "types": ["node"] }, "include": ["src/**/*.ts"] } diff --git a/templates/create/next/README.md.hbs b/templates/create/next/README.md.hbs deleted file mode 100644 index a087b73..0000000 --- a/templates/create/next/README.md.hbs +++ /dev/null @@ -1,42 +0,0 @@ -# {{projectName}} - -Generated by `create-prisma` with the Next.js template. - -## Scripts - -- `{{runScriptCommand packageManager "dev"}}` - start local dev server -- `{{runScriptCommand packageManager "build"}}` - production build -- `{{runScriptCommand packageManager "start"}}` - run production server -{{#if compute}} -- `{{runScriptCommand packageManager "compute:deploy"}}` - redeploy to Prisma Compute with environment variables from `.env` -{{/if}} - -## Prisma - -Prisma setup is scaffolded automatically in: - -- `prisma/schema.prisma` -- `prisma/seed.ts` -- `src/lib/prisma.ts` -- `prisma.config.ts` -- `prisma.compute.ts` -- `src/generated/prisma` - -Database helper scripts are added to `package.json`: - -- `db:generate` -- `db:push` -- `db:migrate` -- `db:seed` -{{#if (eq schemaPreset "basic")}} - -The starter page in `src/app/page.tsx` reads from a basic `User` model so you can verify queries quickly, and `prisma/seed.ts` inserts starter users. -{{/if}} -{{#if compute}} - -## Prisma Compute - -This project includes a Prisma Compute deploy script and deploy defaults in `prisma.compute.ts`. Deploys load environment variables from `.env`; if setup created a Prisma Postgres database, its `DATABASE_URL` is already written there. - -After local changes, run `{{runScriptCommand packageManager "compute:deploy"}}` to redeploy. -{{/if}} diff --git a/templates/create/next/deno.json.hbs b/templates/create/next/deno.json.hbs deleted file mode 100644 index 0420072..0000000 --- a/templates/create/next/deno.json.hbs +++ /dev/null @@ -1,12 +0,0 @@ -{{#if (eq packageManager "deno")}} -{ - "nodeModulesDir": "auto", - "unstable": [ - "bare-node-builtins", - "detect-cjs", - "node-globals", - "unsafe-proto", - "sloppy-imports" - ] -} -{{/if}} diff --git a/templates/create/next/eslint.config.mjs b/templates/create/next/eslint.config.mjs index c03c2a9..d838aa6 100644 --- a/templates/create/next/eslint.config.mjs +++ b/templates/create/next/eslint.config.mjs @@ -5,7 +5,14 @@ import nextTs from "eslint-config-next/typescript"; const eslintConfig = defineConfig([ ...nextVitals, ...nextTs, - globalIgnores([".next/**", "out/**", "build/**", "next-env.d.ts"]), + globalIgnores([ + ".next/**", + "out/**", + "build/**", + "migrations/**", + "src/prisma/**/*.d.ts", + "next-env.d.ts", + ]), ]); export default eslintConfig; diff --git a/templates/create/next/next.config.ts.hbs b/templates/create/next/next.config.ts similarity index 100% rename from templates/create/next/next.config.ts.hbs rename to templates/create/next/next.config.ts diff --git a/templates/create/next/package.json.hbs b/templates/create/next/package.json.hbs index af77275..2a5336e 100644 --- a/templates/create/next/package.json.hbs +++ b/templates/create/next/package.json.hbs @@ -13,17 +13,17 @@ "lint": "eslint" }, "dependencies": { - "next": "16.2.9", - "react": "19.2.7", - "react-dom": "19.2.7" + "next": "16.1.6", + "react": "19.2.3", + "react-dom": "19.2.3" }, "devDependencies": { - "@types/node": "^26.0.0", - "@types/react": "^19.2.17", - "@types/react-dom": "^19.2.3", - "eslint": "^10.5.0", - "eslint-config-next": "16.2.9", - "tsx": "^4.22.4", - "typescript": "^6.0.3" + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "eslint": "^9", + "eslint-config-next": "16.1.6", + "tsx": "^4.7.1", + "typescript": "^5.9.3" } } diff --git a/templates/create/next/prisma.compute.ts.hbs b/templates/create/next/prisma.compute.ts.hbs deleted file mode 100644 index 10c7b39..0000000 --- a/templates/create/next/prisma.compute.ts.hbs +++ /dev/null @@ -1,9 +0,0 @@ -import { defineComputeConfig } from "@prisma/compute-sdk/config"; - -export default defineComputeConfig({ - app: { - name: "{{projectName}}", - framework: "nextjs", - env: ".env", - }, -}); diff --git a/templates/create/next/prisma.config.ts.hbs b/templates/create/next/prisma.config.ts.hbs deleted file mode 100644 index a33e79e..0000000 --- a/templates/create/next/prisma.config.ts.hbs +++ /dev/null @@ -1,15 +0,0 @@ -{{#if (requiresPrismaConfigDotenvImport this.packageManager)}} -import "dotenv/config"; -{{/if}} -import { defineConfig, env } from "prisma/config"; - -export default defineConfig({ - schema: "prisma/schema.prisma", - migrations: { - path: "prisma/migrations", - seed: "{{seedCommand this.packageManager}}", - }, - datasource: { - url: env("DATABASE_URL"), - }, -}); diff --git a/templates/create/next/prisma/schema.prisma.hbs b/templates/create/next/prisma/schema.prisma.hbs deleted file mode 100644 index cea58dd..0000000 --- a/templates/create/next/prisma/schema.prisma.hbs +++ /dev/null @@ -1,21 +0,0 @@ -generator client { - provider = "prisma-client" - output = "../src/generated/prisma" -{{#if (eq packageManager "deno")}} - runtime = "deno" -{{/if}} -} - -datasource db { - provider = "{{provider}}" -} -{{#if (eq schemaPreset "basic")}} - -model User { - id String @id @default(cuid()) - email String @unique - name String? - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt -} -{{/if}} diff --git a/templates/create/next/prisma/seed.ts.hbs b/templates/create/next/prisma/seed.ts.hbs deleted file mode 100644 index dc3d64c..0000000 --- a/templates/create/next/prisma/seed.ts.hbs +++ /dev/null @@ -1,38 +0,0 @@ -import prisma from "../src/lib/prisma{{#if (eq packageManager "deno")}}.ts{{/if}}"; - -async function main() { -{{#if (eq schemaPreset "basic")}} - const users = await Promise.all([ - prisma.user.upsert({ - where: { email: "alice@prisma.io" }, - update: { name: "Alice" }, - create: { - email: "alice@prisma.io", - name: "Alice", - }, - }), - prisma.user.upsert({ - where: { email: "bob@prisma.io" }, - update: { name: "Bob" }, - create: { - email: "bob@prisma.io", - name: "Bob", - }, - }), - ]); - - console.log(`Seeded ${users.length} users.`); -{{else}} - console.log("No seed data defined for the empty schema preset."); -{{/if}} -} - -main() - .then(async () => { - await prisma.$disconnect(); - }) - .catch(async (error) => { - console.error(error); - await prisma.$disconnect(); - process.exit(1); - }); diff --git a/templates/create/next/src/app/page.tsx.hbs b/templates/create/next/src/app/page.tsx.hbs index da84e40..1562e13 100644 --- a/templates/create/next/src/app/page.tsx.hbs +++ b/templates/create/next/src/app/page.tsx.hbs @@ -1,31 +1,23 @@ export const dynamic = "force-dynamic"; export default async function Home() { -{{#if (eq schemaPreset "basic")}} - const { prisma } = await import("../lib/prisma"); + + const { listUsers } = await import("../prisma/users"); const formatter = new Intl.DateTimeFormat("en", { dateStyle: "medium", timeStyle: "short", }); - const users = await prisma.user - .findMany({ - take: 10, - orderBy: { - createdAt: "desc", - }, - }) - .catch(() => undefined); -{{/if}} + const users = await listUsers(10).catch(() => undefined); return (
-

Next.js + Prisma 7

-{{#if (eq schemaPreset "basic")}} +

Next.js + Prisma 8

+

Users from your database, loaded on the server.

- This page reads from src/app/page.tsx using the Prisma instance in{" "} - src/lib/prisma.ts. + This page reads from src/app/page.tsx using the Prisma 8 helper in{" "} + src/prisma/users.ts.

@@ -37,63 +29,32 @@ export default async function Home() { {!users ? (

- Could not query users yet. Run db:migrate, then db:seed, + Could not query users yet. Run contract:emit and apply your schema, then refresh.

) : users.length === 0 ? ( -

No users yet. Run db:seed after your first migration.

+

No users found.

) : (
    {users.map((user) => (
  • {user.name ?? "Unnamed user"} -

    {user.email}

    +

    {user.username ? `@${user.username}` : user.email}

    - + {user.createdAt ? ( + + ) : ( + No timestamp + )}
  • ))}
)} -{{else}} -

Your Next.js app is ready.

-

- Edit prisma/schema.prisma, run db:migrate, then load your data - in server components with the Prisma instance in src/lib/prisma.ts. -

- -
-
-

What's included

- Starter kit -
- -
    -
  • -
    - Prisma client -

    Use the shared instance from src/lib/prisma.ts.

    -
    -
  • -
  • -
    - Seed script -

    Run db:seed after your first migration.

    -
    -
  • -
  • -
    - Generated client output -

    Prisma Client is generated into src/generated/prisma.

    -
    -
  • -
-
-{{/if}}
); } diff --git a/templates/create/next/src/lib/prisma.ts.hbs b/templates/create/next/src/lib/prisma.ts.hbs deleted file mode 100644 index 6193f37..0000000 --- a/templates/create/next/src/lib/prisma.ts.hbs +++ /dev/null @@ -1,56 +0,0 @@ -{{#if (requiresDotenvConfigImport packageManager)}} -import "dotenv/config"; -{{/if}} -import { PrismaClient } from "../generated/prisma/client{{#if (eq packageManager "deno")}}.ts{{/if}}"; -{{#if (eq provider "postgresql")}} -import { PrismaPg } from "@prisma/adapter-pg"; -{{/if}} -{{#if (eq provider "cockroachdb")}} -import { PrismaPg } from "@prisma/adapter-pg"; -{{/if}} -{{#if (eq provider "mysql")}} -import { PrismaMariaDb } from "@prisma/adapter-mariadb"; -{{/if}} -{{#if (eq provider "sqlite")}} -import { {{sqliteAdapterClass packageManager}} } from "{{sqliteAdapterPackage packageManager}}"; -{{/if}} -{{#if (eq provider "sqlserver")}} -import { PrismaMssql } from "@prisma/adapter-mssql"; -{{/if}} - -const rawDatabaseUrl = process.env.DATABASE_URL; -{{#if (eq provider "sqlite")}} -const databaseUrl = (rawDatabaseUrl ?? "").trim() || "file:./dev.db"; -{{else}} -const databaseUrl = (rawDatabaseUrl ?? "").trim(); -if (!databaseUrl) { - throw new Error("DATABASE_URL is required"); -} -{{/if}} - -{{#if (eq provider "postgresql")}} -const adapter = new PrismaPg({ - connectionString: databaseUrl, -}); -{{/if}} -{{#if (eq provider "cockroachdb")}} -const adapter = new PrismaPg({ - connectionString: databaseUrl, -}); -{{/if}} -{{#if (eq provider "mysql")}} -const adapter = new PrismaMariaDb(databaseUrl); -{{/if}} -{{#if (eq provider "sqlite")}} -const adapter = new {{sqliteAdapterClass packageManager}}({ - url: databaseUrl, -}); -{{/if}} -{{#if (eq provider "sqlserver")}} -const adapter = new PrismaMssql(databaseUrl); -{{/if}} - -const prisma = new PrismaClient({ adapter }); - -export { prisma }; -export default prisma; diff --git a/templates/create/next/tsconfig.json b/templates/create/next/tsconfig.json index 470837e..9cb38fb 100644 --- a/templates/create/next/tsconfig.json +++ b/templates/create/next/tsconfig.json @@ -14,6 +14,7 @@ "isolatedModules": true, "jsx": "react-jsx", "incremental": true, + "types": ["node"], "plugins": [ { "name": "next" diff --git a/templates/create/nuxt/README.md.hbs b/templates/create/nuxt/README.md.hbs deleted file mode 100644 index d991a73..0000000 --- a/templates/create/nuxt/README.md.hbs +++ /dev/null @@ -1,44 +0,0 @@ -# {{projectName}} - -Generated by `create-prisma` with the Nuxt template. - -## Scripts - -- `{{runScriptCommand packageManager "dev"}}` - start the Nuxt dev server -- `{{runScriptCommand packageManager "build"}}` - build for production -- `{{runScriptCommand packageManager "preview"}}` - preview the production build -- `{{runScriptCommand packageManager "typecheck"}}` - run Nuxt type checks -{{#if compute}} -- `{{runScriptCommand packageManager "compute:deploy"}}` - redeploy to Prisma Compute with environment variables from `.env` -{{/if}} - -## Prisma - -Prisma setup is scaffolded automatically in: - -- `prisma/schema.prisma` -- `prisma/seed.ts` -- `server/utils/prisma.ts` -- `server/api/users.get.ts` -- `prisma.config.ts` -- `prisma.compute.ts` -- `server/generated/prisma` - -Database helper scripts are added to `package.json`: - -- `db:generate` -- `db:push` -- `db:migrate` -- `db:seed` -{{#if (eq schemaPreset "basic")}} - -The starter page in `app/pages/index.vue` fetches seeded users from `server/api/users.get.ts`, and `prisma/seed.ts` inserts starter users. -{{/if}} -{{#if compute}} - -## Prisma Compute - -This project includes a Prisma Compute deploy script and deploy defaults in `prisma.compute.ts`. Deploys load environment variables from `.env`; if setup created a Prisma Postgres database, its `DATABASE_URL` is already written there. - -After local changes, run `{{runScriptCommand packageManager "compute:deploy"}}` to redeploy. -{{/if}} diff --git a/templates/create/nuxt/app/pages/index.vue.hbs b/templates/create/nuxt/app/pages/index.vue.hbs index 97ceb88..0d719a9 100644 --- a/templates/create/nuxt/app/pages/index.vue.hbs +++ b/templates/create/nuxt/app/pages/index.vue.hbs @@ -3,12 +3,12 @@ useHead({ title: "create-prisma + nuxt", }); -{{#if (eq schemaPreset "basic")}} type User = { id: string; email: string; + username: string | null; name: string | null; - createdAt: string; + createdAt: string | null; }; type UsersPayload = { @@ -26,18 +26,18 @@ const { data } = await useFetch("/api/users"); function formatCreatedAt(value: string): string { return formatter.format(new Date(value)); } -{{/if}} + @@ -165,6 +131,7 @@ h2 { .panel-header span, .empty, +.muted, time { color: #888; font-size: 0.8rem; diff --git a/templates/create/nuxt/deno.json.hbs b/templates/create/nuxt/deno.json.hbs deleted file mode 100644 index 360f2ea..0000000 --- a/templates/create/nuxt/deno.json.hbs +++ /dev/null @@ -1,5 +0,0 @@ -{{#if (eq packageManager "deno")}} -{ - "nodeModulesDir": "auto" -} -{{/if}} diff --git a/templates/create/nuxt/package.json.hbs b/templates/create/nuxt/package.json.hbs index c8635e2..4935fda 100644 --- a/templates/create/nuxt/package.json.hbs +++ b/templates/create/nuxt/package.json.hbs @@ -15,14 +15,15 @@ "typecheck": "nuxt typecheck" }, "dependencies": { - "nuxt": "^4.4.8", - "vue": "^3.5.38", - "vue-router": "^5.1.0" + "nuxt": "^4.3.1", + "vue": "^3.5.29", + "vue-router": "^4.6.4" }, "devDependencies": { - "@types/node": "^26.0.0", - "tsx": "^4.22.4", - "typescript": "^6.0.3", - "vue-tsc": "^3.3.5" + "@types/node": "^24.3.0", + "tsx": "^4.7.1", + "typescript": "^5.9.3", + "vite": "^8.1.2", + "vue-tsc": "^3.3.9" } } diff --git a/templates/create/nuxt/prisma.compute.ts.hbs b/templates/create/nuxt/prisma.compute.ts.hbs deleted file mode 100644 index ab0cc71..0000000 --- a/templates/create/nuxt/prisma.compute.ts.hbs +++ /dev/null @@ -1,9 +0,0 @@ -import { defineComputeConfig } from "@prisma/compute-sdk/config"; - -export default defineComputeConfig({ - app: { - name: "{{projectName}}", - framework: "nuxt", - env: ".env", - }, -}); diff --git a/templates/create/nuxt/prisma.config.ts.hbs b/templates/create/nuxt/prisma.config.ts.hbs deleted file mode 100644 index a33e79e..0000000 --- a/templates/create/nuxt/prisma.config.ts.hbs +++ /dev/null @@ -1,15 +0,0 @@ -{{#if (requiresPrismaConfigDotenvImport this.packageManager)}} -import "dotenv/config"; -{{/if}} -import { defineConfig, env } from "prisma/config"; - -export default defineConfig({ - schema: "prisma/schema.prisma", - migrations: { - path: "prisma/migrations", - seed: "{{seedCommand this.packageManager}}", - }, - datasource: { - url: env("DATABASE_URL"), - }, -}); diff --git a/templates/create/nuxt/prisma/schema.prisma.hbs b/templates/create/nuxt/prisma/schema.prisma.hbs deleted file mode 100644 index 2e912cd..0000000 --- a/templates/create/nuxt/prisma/schema.prisma.hbs +++ /dev/null @@ -1,21 +0,0 @@ -generator client { - provider = "prisma-client" - output = "../server/generated/prisma" -{{#if (eq packageManager "deno")}} - runtime = "deno" -{{/if}} -} - -datasource db { - provider = "{{provider}}" -} -{{#if (eq schemaPreset "basic")}} - -model User { - id String @id @default(cuid()) - email String @unique - name String? - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt -} -{{/if}} diff --git a/templates/create/nuxt/prisma/seed.ts.hbs b/templates/create/nuxt/prisma/seed.ts.hbs deleted file mode 100644 index 28577e1..0000000 --- a/templates/create/nuxt/prisma/seed.ts.hbs +++ /dev/null @@ -1,38 +0,0 @@ -import prisma from "../server/utils/prisma{{#if (eq packageManager "deno")}}.ts{{/if}}"; - -async function main() { -{{#if (eq schemaPreset "basic")}} - const users = await Promise.all([ - prisma.user.upsert({ - where: { email: "alice@prisma.io" }, - update: { name: "Alice" }, - create: { - email: "alice@prisma.io", - name: "Alice", - }, - }), - prisma.user.upsert({ - where: { email: "bob@prisma.io" }, - update: { name: "Bob" }, - create: { - email: "bob@prisma.io", - name: "Bob", - }, - }), - ]); - - console.log(`Seeded ${users.length} users.`); -{{else}} - console.log("No seed data defined for the empty schema preset."); -{{/if}} -} - -main() - .then(async () => { - await prisma.$disconnect(); - }) - .catch(async (error) => { - console.error(error); - await prisma.$disconnect(); - process.exit(1); - }); diff --git a/templates/create/nuxt/server/api/users.get.ts.hbs b/templates/create/nuxt/server/api/users.get.ts.hbs index 4a3ff2d..4f39d15 100644 --- a/templates/create/nuxt/server/api/users.get.ts.hbs +++ b/templates/create/nuxt/server/api/users.get.ts.hbs @@ -1,18 +1,11 @@ -{{#if (eq schemaPreset "basic")}} -import prisma from "../utils/prisma"; +import { listUsers } from "../../src/prisma/users"; export default defineEventHandler(async () => { - const users = await prisma.user - .findMany({ - take: 10, - orderBy: { - createdAt: "desc", - }, - }) + const users = await listUsers(10) .then((rows) => rows.map((user) => ({ ...user, - createdAt: user.createdAt.toISOString(), + createdAt: user.createdAt?.toISOString() ?? null, })) ) .catch((error) => { @@ -29,8 +22,3 @@ export default defineEventHandler(async () => { return { users }; }); -{{else}} -export default defineEventHandler(async () => { - return { users: [] }; -}); -{{/if}} diff --git a/templates/create/nuxt/server/utils/prisma.ts.hbs b/templates/create/nuxt/server/utils/prisma.ts.hbs deleted file mode 100644 index 6193f37..0000000 --- a/templates/create/nuxt/server/utils/prisma.ts.hbs +++ /dev/null @@ -1,56 +0,0 @@ -{{#if (requiresDotenvConfigImport packageManager)}} -import "dotenv/config"; -{{/if}} -import { PrismaClient } from "../generated/prisma/client{{#if (eq packageManager "deno")}}.ts{{/if}}"; -{{#if (eq provider "postgresql")}} -import { PrismaPg } from "@prisma/adapter-pg"; -{{/if}} -{{#if (eq provider "cockroachdb")}} -import { PrismaPg } from "@prisma/adapter-pg"; -{{/if}} -{{#if (eq provider "mysql")}} -import { PrismaMariaDb } from "@prisma/adapter-mariadb"; -{{/if}} -{{#if (eq provider "sqlite")}} -import { {{sqliteAdapterClass packageManager}} } from "{{sqliteAdapterPackage packageManager}}"; -{{/if}} -{{#if (eq provider "sqlserver")}} -import { PrismaMssql } from "@prisma/adapter-mssql"; -{{/if}} - -const rawDatabaseUrl = process.env.DATABASE_URL; -{{#if (eq provider "sqlite")}} -const databaseUrl = (rawDatabaseUrl ?? "").trim() || "file:./dev.db"; -{{else}} -const databaseUrl = (rawDatabaseUrl ?? "").trim(); -if (!databaseUrl) { - throw new Error("DATABASE_URL is required"); -} -{{/if}} - -{{#if (eq provider "postgresql")}} -const adapter = new PrismaPg({ - connectionString: databaseUrl, -}); -{{/if}} -{{#if (eq provider "cockroachdb")}} -const adapter = new PrismaPg({ - connectionString: databaseUrl, -}); -{{/if}} -{{#if (eq provider "mysql")}} -const adapter = new PrismaMariaDb(databaseUrl); -{{/if}} -{{#if (eq provider "sqlite")}} -const adapter = new {{sqliteAdapterClass packageManager}}({ - url: databaseUrl, -}); -{{/if}} -{{#if (eq provider "sqlserver")}} -const adapter = new PrismaMssql(databaseUrl); -{{/if}} - -const prisma = new PrismaClient({ adapter }); - -export { prisma }; -export default prisma; diff --git a/templates/create/nuxt/tsconfig.json b/templates/create/nuxt/tsconfig.json index 6ae5970..2c89a86 100644 --- a/templates/create/nuxt/tsconfig.json +++ b/templates/create/nuxt/tsconfig.json @@ -1,4 +1,7 @@ { + "compilerOptions": { + "types": ["node"] + }, "files": [], "references": [ { diff --git a/templates/create/svelte/.npmrc b/templates/create/svelte/.npmrc deleted file mode 100644 index b6f27f1..0000000 --- a/templates/create/svelte/.npmrc +++ /dev/null @@ -1 +0,0 @@ -engine-strict=true diff --git a/templates/create/svelte/README.md.hbs b/templates/create/svelte/README.md.hbs deleted file mode 100644 index 3513d27..0000000 --- a/templates/create/svelte/README.md.hbs +++ /dev/null @@ -1,45 +0,0 @@ -# {{projectName}} - -Generated by `create-prisma` with the SvelteKit template. - -## Scripts - -- `{{runScriptCommand packageManager "dev"}}` - start the SvelteKit dev server -- `{{runScriptCommand packageManager "build"}}` - build for production -- `{{runScriptCommand packageManager "preview"}}` - preview the production build -- `{{runScriptCommand packageManager "check"}}` - run SvelteKit sync and type checks -{{#if compute}} -- `{{runScriptCommand packageManager "compute:deploy"}}` - redeploy to Prisma Compute with environment variables from `.env` -{{/if}} - -## Prisma - -Prisma setup is scaffolded automatically in: - -- `prisma/schema.prisma` -- `prisma/seed.ts` -- `src/lib/server/prisma.ts` -- `prisma.config.ts` -- `src/generated/prisma` - -Database helper scripts are added to `package.json`: - -- `db:generate` -- `db:push` -- `db:migrate` -- `db:seed` -{{#if (eq schemaPreset "basic")}} - -The starter page loads users in `+page.server.ts`, renders them in `+page.svelte`, and `prisma/seed.ts` inserts starter users. -{{else}} - -The starter page keeps the official SvelteKit minimal structure and points you to `prisma/schema.prisma` for your first model. -{{/if}} -{{#if compute}} - -## Prisma Compute - -This project includes a Prisma Compute deploy script. Deploys load environment variables from `.env`; if setup created a Prisma Postgres database, its `DATABASE_URL` is already written there. - -After local changes, run `{{runScriptCommand packageManager "compute:deploy"}}` to redeploy. -{{/if}} diff --git a/templates/create/svelte/deno.json.hbs b/templates/create/svelte/deno.json.hbs deleted file mode 100644 index 360f2ea..0000000 --- a/templates/create/svelte/deno.json.hbs +++ /dev/null @@ -1,5 +0,0 @@ -{{#if (eq packageManager "deno")}} -{ - "nodeModulesDir": "auto" -} -{{/if}} diff --git a/templates/create/svelte/package.json.hbs b/templates/create/svelte/package.json.hbs index 42a2e65..a153eb2 100644 --- a/templates/create/svelte/package.json.hbs +++ b/templates/create/svelte/package.json.hbs @@ -12,18 +12,16 @@ "preview": "vite preview", "prepare": "svelte-kit sync || echo ''", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", - "db:generate": "svelte-kit sync && {{prismaCommand packageManager "generate"}}" + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch" }, "devDependencies": { - "@sveltejs/adapter-auto": "^7.0.1", - "@sveltejs/kit": "^2.67.0", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@types/node": "^26.0.0", - "svelte": "^5.56.3", - "svelte-check": "^4.6.0", - "tsx": "^4.22.4", - "typescript": "^6.0.3", - "vite": "^8.0.16" + "@sveltejs/kit": "^2.50.2", + "@sveltejs/vite-plugin-svelte": "^7.3.0", + "@types/node": "^24.3.0", + "svelte": "^5.51.0", + "svelte-check": "^4.4.2", + "tsx": "^4.7.1", + "typescript": "^5.9.3", + "vite": "^8.1.2" } } diff --git a/templates/create/svelte/prisma.config.ts.hbs b/templates/create/svelte/prisma.config.ts.hbs deleted file mode 100644 index a33e79e..0000000 --- a/templates/create/svelte/prisma.config.ts.hbs +++ /dev/null @@ -1,15 +0,0 @@ -{{#if (requiresPrismaConfigDotenvImport this.packageManager)}} -import "dotenv/config"; -{{/if}} -import { defineConfig, env } from "prisma/config"; - -export default defineConfig({ - schema: "prisma/schema.prisma", - migrations: { - path: "prisma/migrations", - seed: "{{seedCommand this.packageManager}}", - }, - datasource: { - url: env("DATABASE_URL"), - }, -}); diff --git a/templates/create/svelte/prisma/schema.prisma.hbs b/templates/create/svelte/prisma/schema.prisma.hbs deleted file mode 100644 index cea58dd..0000000 --- a/templates/create/svelte/prisma/schema.prisma.hbs +++ /dev/null @@ -1,21 +0,0 @@ -generator client { - provider = "prisma-client" - output = "../src/generated/prisma" -{{#if (eq packageManager "deno")}} - runtime = "deno" -{{/if}} -} - -datasource db { - provider = "{{provider}}" -} -{{#if (eq schemaPreset "basic")}} - -model User { - id String @id @default(cuid()) - email String @unique - name String? - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt -} -{{/if}} diff --git a/templates/create/svelte/prisma/seed.ts.hbs b/templates/create/svelte/prisma/seed.ts.hbs deleted file mode 100644 index b8708b2..0000000 --- a/templates/create/svelte/prisma/seed.ts.hbs +++ /dev/null @@ -1,38 +0,0 @@ -import prisma from "../src/lib/server/prisma{{#if (eq packageManager "deno")}}.ts{{/if}}"; - -async function main() { -{{#if (eq schemaPreset "basic")}} - const users = await Promise.all([ - prisma.user.upsert({ - where: { email: "alice@prisma.io" }, - update: { name: "Alice" }, - create: { - email: "alice@prisma.io", - name: "Alice", - }, - }), - prisma.user.upsert({ - where: { email: "bob@prisma.io" }, - update: { name: "Bob" }, - create: { - email: "bob@prisma.io", - name: "Bob", - }, - }), - ]); - - console.log(`Seeded ${users.length} users.`); -{{else}} - console.log("No seed data defined for the empty schema preset."); -{{/if}} -} - -main() - .then(async () => { - await prisma.$disconnect(); - }) - .catch(async (error) => { - console.error(error); - await prisma.$disconnect(); - process.exit(1); - }); diff --git a/templates/create/svelte/src/lib/server/prisma.ts.hbs b/templates/create/svelte/src/lib/server/prisma.ts.hbs deleted file mode 100644 index 1dd6467..0000000 --- a/templates/create/svelte/src/lib/server/prisma.ts.hbs +++ /dev/null @@ -1,53 +0,0 @@ -import { PrismaClient } from "../../generated/prisma/client{{#if (eq packageManager "deno")}}.ts{{/if}}"; -{{#if (eq provider "postgresql")}} -import { PrismaPg } from "@prisma/adapter-pg"; -{{/if}} -{{#if (eq provider "cockroachdb")}} -import { PrismaPg } from "@prisma/adapter-pg"; -{{/if}} -{{#if (eq provider "mysql")}} -import { PrismaMariaDb } from "@prisma/adapter-mariadb"; -{{/if}} -{{#if (eq provider "sqlite")}} -import { {{sqliteAdapterClass packageManager}} } from "{{sqliteAdapterPackage packageManager}}"; -{{/if}} -{{#if (eq provider "sqlserver")}} -import { PrismaMssql } from "@prisma/adapter-mssql"; -{{/if}} - -const rawDatabaseUrl = process.env.DATABASE_URL; -{{#if (eq provider "sqlite")}} -const databaseUrl = (rawDatabaseUrl ?? "").trim() || "file:./dev.db"; -{{else}} -const databaseUrl = (rawDatabaseUrl ?? "").trim(); -if (!databaseUrl) { - throw new Error("DATABASE_URL is required"); -} -{{/if}} - -{{#if (eq provider "postgresql")}} -const adapter = new PrismaPg({ - connectionString: databaseUrl, -}); -{{/if}} -{{#if (eq provider "cockroachdb")}} -const adapter = new PrismaPg({ - connectionString: databaseUrl, -}); -{{/if}} -{{#if (eq provider "mysql")}} -const adapter = new PrismaMariaDb(databaseUrl); -{{/if}} -{{#if (eq provider "sqlite")}} -const adapter = new {{sqliteAdapterClass packageManager}}({ - url: databaseUrl, -}); -{{/if}} -{{#if (eq provider "sqlserver")}} -const adapter = new PrismaMssql(databaseUrl); -{{/if}} - -const prisma = new PrismaClient({ adapter }); - -export { prisma }; -export default prisma; diff --git a/templates/create/svelte/src/routes/+page.server.ts.hbs b/templates/create/svelte/src/routes/+page.server.ts.hbs index aec06cd..aba4c74 100644 --- a/templates/create/svelte/src/routes/+page.server.ts.hbs +++ b/templates/create/svelte/src/routes/+page.server.ts.hbs @@ -1,28 +1,16 @@ import type { PageServerLoad } from "./$types"; -{{#if (eq schemaPreset "basic")}} -import prisma from "$lib/server/prisma"; + +import { listUsers } from "../prisma/users"; export const load: PageServerLoad = async () => { - const users = await prisma.user - .findMany({ - take: 10, - orderBy: { - createdAt: "desc", - }, - }) + const users = await listUsers(10) .then((rows) => rows.map((user) => ({ ...user, - createdAt: user.createdAt.toISOString(), + createdAt: user.createdAt?.toISOString() ?? null, })) ) .catch(() => undefined); return { users }; }; -{{else}} - -export const load: PageServerLoad = async () => { - return {}; -}; -{{/if}} diff --git a/templates/create/svelte/src/routes/+page.svelte.hbs b/templates/create/svelte/src/routes/+page.svelte.hbs index b5a9f26..4406dbb 100644 --- a/templates/create/svelte/src/routes/+page.svelte.hbs +++ b/templates/create/svelte/src/routes/+page.svelte.hbs @@ -1,4 +1,3 @@ -{{#if (eq schemaPreset "basic")}}