feat: implement robust database seeding strategy

This commit is contained in:
Matti Nannt
2025-12-22 12:46:09 +01:00
parent 5cc2a61089
commit 9dd604524f
5 changed files with 555 additions and 134 deletions

View File

@@ -82,6 +82,12 @@ Run these commands from the root directory of the Formbricks monorepo:
- Generates new `migration.sql` in the custom directory
- Copies migration to Prisma's internal directory
- Applies all pending migrations to the database
- **`pnpm db:seed`**: Seed the database with sample data
- Upserts base infrastructure (Organization, Project, Environments)
- Creates multi-role users (Admin, Manager)
- Generates complex surveys and sample responses
- **`pnpm db:seed:clear`**: Clear all seeded data and re-seed
- **WARNING**: This will delete existing data in the database.
### Package Level Commands
@@ -92,6 +98,8 @@ Run these commands from the `packages/database` directory:
- Creates new subdirectory with appropriate timestamp
- Generates `migration.ts` file with pre-configured ID and name
- **Note**: Only use Prisma raw queries in data migrations for better performance and to avoid type errors
- **`pnpm db:seed`**: Run the seeding script
- **`pnpm db:seed:clear`**: Clear data and run the seeding script
### Available Scripts
@@ -102,13 +110,41 @@ Run these commands from the `packages/database` directory:
"db:migrate:deploy": "Apply migrations in production",
"db:migrate:dev": "Apply migrations in development",
"db:push": "prisma db push --accept-data-loss",
"db:setup": "pnpm db:migrate:dev && pnpm db:create-saml-database:dev",
"db:seed": "Seed the database with sample data",
"db:seed:clear": "Clear all data and re-seed",
"db:setup": "pnpm db:migrate:dev && pnpm db:create-saml-database:dev && pnpm db:seed",
"dev": "vite build --watch",
"generate": "prisma generate",
"generate-data-migration": "Create new data migration"
}
```
## Database Seeding
The seeding system provides a quick way to set up a functional environment for development, QA, and testing.
### Safety Guard
To prevent accidental data loss in production, seeding is blocked if `NODE_ENV=production`. If you explicitly need to seed a production-like environment (e.g., staging), you must set:
```bash
ALLOW_SEED=true
```
### Seeding Logic
The `pnpm db:seed` script:
1. **Infrastructure**: Upserts a default organization, project, and environments.
2. **Users**: Creates default users with the following credentials (passwords are hashed):
- **Admin**: `admin@formbricks.com` / `password123`
- **Manager**: `manager@formbricks.com` / `password123`
3. **Surveys**: Creates complex sample surveys (Kitchen Sink, CSAT, Draft, etc.) in the **Production** environment.
4. **Responses**: Generates ~50 realistic responses and displays for each survey.
### Idempotency
By default, the seed script uses `upsert` to ensure it can be run multiple times without creating duplicate infrastructure. To perform a clean reset, use `pnpm db:seed:clear`.
## Migration Workflow
### Adding a Schema Migration

View File

@@ -50,17 +50,20 @@
"@formbricks/logger": "workspace:*",
"@paralleldrive/cuid2": "2.2.2",
"@prisma/client": "6.14.0",
"bcryptjs": "2.4.3",
"zod": "3.24.4",
"zod-openapi": "4.2.4"
},
"devDependencies": {
"@formbricks/config-typescript": "workspace:*",
"@formbricks/eslint-config": "workspace:*",
"@types/bcryptjs": "2.4.6",
"dotenv-cli": "8.0.0",
"glob": "11.1.0",
"prisma": "6.14.0",
"prisma-json-types-generator": "3.5.4",
"ts-node": "10.9.2",
"tsx": "4.19.2",
"vite": "6.4.1",
"vite-plugin-dts": "4.5.3"
}

View File

@@ -1,5 +1,5 @@
import { PrismaClient } from "@prisma/client";
import bcrypt from "bcryptjs";
import { type Prisma, PrismaClient } from "@prisma/client";
import * as bcrypt from "bcryptjs";
import { SEED_CREDENTIALS, SEED_IDS } from "./seed/constants";
const prisma = new PrismaClient();
@@ -14,9 +14,61 @@ if (isProduction && !allowSeed) {
const clearData = process.argv.includes("--clear");
async function deleteData() {
// Define local types to avoid resolution issues in seed script
type SurveyElementType =
| "openText"
| "multipleChoiceSingle"
| "multipleChoiceMulti"
| "nps"
| "cta"
| "rating"
| "consent"
| "date"
| "matrix"
| "address"
| "ranking"
| "contactInfo";
interface SurveyQuestion {
id: string;
type: SurveyElementType;
headline: { default: string; [key: string]: string };
subheader?: { default: string; [key: string]: string };
required?: boolean;
placeholder?: { default: string; [key: string]: string };
longAnswer?: boolean;
choices?: { id: string; label: { default: string }; imageUrl?: string }[];
lowerLabel?: { default: string };
upperLabel?: { default: string };
buttonLabel?: { default: string };
buttonUrl?: string;
buttonExternal?: boolean;
dismissButtonLabel?: { default: string };
scale?: string;
range?: number;
label?: { default: string };
allowMulti?: boolean;
format?: string;
rows?: { id: string; label: { default: string } }[];
columns?: { id: string; label: { default: string } }[];
addressLine1?: { show: boolean; required: boolean; placeholder: { default: string } };
addressLine2?: { show: boolean; required: boolean; placeholder: { default: string } };
city?: { show: boolean; required: boolean; placeholder: { default: string } };
state?: { show: boolean; required: boolean; placeholder: { default: string } };
zip?: { show: boolean; required: boolean; placeholder: { default: string } };
country?: { show: boolean; required: boolean; placeholder: { default: string } };
firstName?: { show: boolean; required: boolean; placeholder: { default: string } };
lastName?: { show: boolean; required: boolean; placeholder: { default: string } };
email?: { show: boolean; required: boolean; placeholder: { default: string } };
phone?: { show: boolean; required: boolean; placeholder: { default: string } };
company?: { show: boolean; required: boolean; placeholder: { default: string } };
allowMultipleFiles?: boolean;
maxSizeInMB?: number;
}
async function deleteData(): Promise<void> {
console.log("Clearing existing data...");
const deleteOrder = [
const deleteOrder: Prisma.ModelName[] = [
"ResponseQuotaLink",
"SurveyQuota",
"TagsOnResponses",
@@ -50,16 +102,20 @@ async function deleteData() {
for (const model of deleteOrder) {
try {
// @ts-ignore
await prisma[model.charAt(0).toLowerCase() + model.slice(1)].deleteMany();
} catch (e) {
console.warn(`Could not delete data from ${model}: ${e.message}`);
// @ts-expect-error - dynamic model access
const modelClient = prisma[model.charAt(0).toLowerCase() + model.slice(1)] as {
deleteMany: () => Promise<unknown>;
};
await modelClient.deleteMany();
} catch (e: unknown) {
const errorMessage = e instanceof Error ? e.message : String(e);
console.warn(`Could not delete data from ${String(model)}: ${errorMessage}`);
}
}
console.log("Data cleared.");
}
const KITCHEN_SINK_QUESTIONS = [
const KITCHEN_SINK_QUESTIONS: SurveyQuestion[] = [
{
id: "q_open_text",
type: "openText",
@@ -128,17 +184,6 @@ const KITCHEN_SINK_QUESTIONS = [
required: true,
label: { default: "I agree to the terms and conditions" },
},
{
id: "q_picture_selection",
type: "pictureSelection",
headline: { default: "Which logo do you prefer?" },
required: true,
allowMulti: false,
choices: [
{ id: "pic_1", imageUrl: "https://formbricks.com/logo-dark.png" },
{ id: "pic_2", imageUrl: "https://formbricks.com/logo-light.png" },
],
},
{
id: "q_date",
type: "date",
@@ -196,44 +241,42 @@ const KITCHEN_SINK_QUESTIONS = [
phone: { show: true, required: false, placeholder: { default: "Phone" } },
company: { show: true, required: false, placeholder: { default: "Company" } },
},
{
id: "q_file_upload",
type: "fileUpload",
headline: { default: "Upload your logo" },
required: false,
allowMultipleFiles: true,
maxSizeInMB: 5,
},
];
async function generateResponses(surveyId: string, count: number) {
console.log(`Generating ${count} responses for survey ${surveyId}...`);
async function generateResponses(surveyId: string, count: number): Promise<void> {
console.log(`Generating ${String(count)} responses for survey ${surveyId}...`);
const survey = await prisma.survey.findUnique({
where: { id: surveyId },
});
if (!survey) return;
const questions = survey.questions as any[];
const questions = survey.questions as unknown as SurveyQuestion[];
for (let i = 0; i < count; i++) {
const data: Record<string, any> = {};
questions.forEach((q) => {
const data: Record<string, string | number | string[] | Record<string, string>> = {};
for (const q of questions) {
switch (q.type) {
case "openText":
data[q.id] = `Sample response ${i}`;
data[q.id] = `Sample response ${String(i)}`;
break;
case "multipleChoiceSingle":
data[q.id] = q.choices[Math.floor(Math.random() * q.choices.length)].label.default;
if (q.choices) {
data[q.id] = q.choices[Math.floor(Math.random() * q.choices.length)].label.default;
}
break;
case "multipleChoiceMulti":
data[q.id] = [q.choices[0].label.default, q.choices[1].label.default];
if (q.choices) {
data[q.id] = [q.choices[0].label.default, q.choices[1].label.default];
}
break;
case "nps":
data[q.id] = Math.floor(Math.random() * 11);
break;
case "rating":
data[q.id] = Math.floor(Math.random() * q.range) + 1;
if (q.range) {
data[q.id] = Math.floor(Math.random() * q.range) + 1;
}
break;
case "cta":
data[q.id] = "clicked";
@@ -244,16 +287,23 @@ async function generateResponses(surveyId: string, count: number) {
case "date":
data[q.id] = new Date().toISOString().split("T")[0];
break;
case "matrix":
case "matrix": {
const matrixData: Record<string, string> = {};
q.rows.forEach((row: any) => {
matrixData[row.label.default] =
q.columns[Math.floor(Math.random() * q.columns.length)].label.default;
});
if (q.rows) {
for (const row of q.rows) {
if (q.columns) {
matrixData[row.label.default] =
q.columns[Math.floor(Math.random() * q.columns.length)].label.default;
}
}
}
data[q.id] = matrixData;
break;
}
case "ranking":
data[q.id] = q.choices.map((c: any) => c.label.default).sort(() => Math.random() - 0.5);
if (q.choices) {
data[q.id] = q.choices.map((c) => c.label.default).sort(() => Math.random() - 0.5);
}
break;
case "address":
data[q.id] = {
@@ -268,25 +318,45 @@ async function generateResponses(surveyId: string, count: number) {
data[q.id] = {
firstName: "John",
lastName: "Doe",
email: `john.doe.${i}@example.com`,
email: `john.doe.${String(i)}@example.com`,
};
break;
default:
data[q.id] = "Sample data";
}
});
}
await prisma.response.create({
await prisma.$transaction(async (tx) => {
const display = await tx.display.create({
data: {
surveyId,
},
});
await tx.response.create({
data: {
surveyId,
finished: true,
data: data as unknown as Prisma.InputJsonValue,
displayId: display.id,
},
});
});
}
// Generate some displays without responses (e.g., 30% more)
const extraDisplays = Math.floor(count * 0.3);
console.log(`Generating ${String(extraDisplays)} extra displays for survey ${surveyId}...`);
for (let i = 0; i < extraDisplays; i++) {
await prisma.display.create({
data: {
surveyId,
finished: true,
data,
},
});
}
}
async function main() {
async function main(): Promise<void> {
if (clearData) {
await deleteData();
}
@@ -313,7 +383,7 @@ async function main() {
// Users
const passwordHash = await bcrypt.hash(SEED_CREDENTIALS.ADMIN.password, 10);
const admin = await prisma.user.upsert({
await prisma.user.upsert({
where: { id: SEED_IDS.USER_ADMIN },
update: {},
create: {
@@ -332,7 +402,7 @@ async function main() {
},
});
const manager = await prisma.user.upsert({
await prisma.user.upsert({
where: { id: SEED_IDS.USER_MANAGER },
update: {},
create: {
@@ -363,13 +433,14 @@ async function main() {
});
// Environments
const devEnv = await prisma.environment.upsert({
await prisma.environment.upsert({
where: { id: SEED_IDS.ENV_DEV },
update: {},
update: { appSetupCompleted: false },
create: {
id: SEED_IDS.ENV_DEV,
type: "development",
projectId: project.id,
appSetupCompleted: false,
attributeKeys: {
create: [
{ name: "Email", key: "email", isUnique: true, type: "default" },
@@ -383,11 +454,12 @@ async function main() {
const prodEnv = await prisma.environment.upsert({
where: { id: SEED_IDS.ENV_PROD },
update: {},
update: { appSetupCompleted: false },
create: {
id: SEED_IDS.ENV_PROD,
type: "production",
projectId: project.id,
appSetupCompleted: false,
attributeKeys: {
create: [
{ name: "Email", key: "email", isUnique: true, type: "default" },
@@ -401,96 +473,93 @@ async function main() {
console.log("Seeding surveys...");
const createSurveyWithBlocks = async (
id: string,
name: string,
environmentId: string,
status: "inProgress" | "draft" | "completed",
questions: SurveyQuestion[]
): Promise<void> => {
const blocks = [
{
id: `block_${id}`,
name: "Main Block",
elements: questions,
},
];
await prisma.survey.upsert({
where: { id },
update: {
environmentId,
type: "link",
questions: questions as unknown as Prisma.InputJsonValue,
blocks: blocks as unknown as Prisma.InputJsonValue[],
},
create: {
id,
name,
environmentId,
status,
type: "link",
questions: questions as unknown as Prisma.InputJsonValue,
blocks: blocks as unknown as Prisma.InputJsonValue[],
},
});
};
// Kitchen Sink Survey
await prisma.survey.upsert({
where: { id: SEED_IDS.SURVEY_KITCHEN_SINK },
update: {},
create: {
id: SEED_IDS.SURVEY_KITCHEN_SINK,
name: "Kitchen Sink Survey",
environmentId: devEnv.id,
status: "inProgress",
type: "app",
questions: KITCHEN_SINK_QUESTIONS,
},
});
await createSurveyWithBlocks(
SEED_IDS.SURVEY_KITCHEN_SINK,
"Kitchen Sink Survey",
prodEnv.id,
"inProgress",
KITCHEN_SINK_QUESTIONS
);
// CSAT Survey
await prisma.survey.upsert({
where: { id: SEED_IDS.SURVEY_CSAT },
update: {},
create: {
id: SEED_IDS.SURVEY_CSAT,
name: "CSAT Survey",
environmentId: devEnv.id,
status: "inProgress",
type: "app",
questions: [
{
id: "csat_rating",
type: "rating",
headline: { default: "How satisfied are you with our product?" },
required: true,
scale: "smiley",
range: 5,
},
],
await createSurveyWithBlocks(SEED_IDS.SURVEY_CSAT, "CSAT Survey", prodEnv.id, "inProgress", [
{
id: "csat_rating",
type: "rating",
headline: { default: "How satisfied are you with our product?" },
required: true,
scale: "smiley",
range: 5,
},
});
]);
// Draft Survey
await prisma.survey.upsert({
where: { id: SEED_IDS.SURVEY_DRAFT },
update: {},
create: {
id: SEED_IDS.SURVEY_DRAFT,
name: "Draft Survey",
environmentId: devEnv.id,
status: "draft",
type: "app",
questions: [
{
id: "draft_q1",
type: "openText",
headline: { default: "Coming soon..." },
required: false,
},
],
await createSurveyWithBlocks(SEED_IDS.SURVEY_DRAFT, "Draft Survey", prodEnv.id, "draft", [
{
id: "draft_q1",
type: "openText",
headline: { default: "Coming soon..." },
required: false,
},
});
]);
// Completed Survey
await prisma.survey.upsert({
where: { id: SEED_IDS.SURVEY_COMPLETED },
update: {},
create: {
id: SEED_IDS.SURVEY_COMPLETED,
name: "Exit Survey",
environmentId: devEnv.id,
status: "completed",
type: "app",
questions: [
{
id: "exit_q1",
type: "multipleChoiceSingle",
headline: { default: "Why are you leaving?" },
required: true,
choices: [
{ id: "c1", label: { default: "Too expensive" } },
{ id: "c2", label: { default: "Found a better alternative" } },
{ id: "c3", label: { default: "Missing features" } },
],
},
await createSurveyWithBlocks(SEED_IDS.SURVEY_COMPLETED, "Exit Survey", prodEnv.id, "completed", [
{
id: "exit_q1",
type: "multipleChoiceSingle",
headline: { default: "Why are you leaving?" },
required: true,
choices: [
{ id: "c1", label: { default: "Too expensive" } },
{ id: "c2", label: { default: "Found a better alternative" } },
{ id: "c3", label: { default: "Missing features" } },
],
},
});
]);
console.log("Generating responses...");
await generateResponses(SEED_IDS.SURVEY_KITCHEN_SINK, 50);
await generateResponses(SEED_IDS.SURVEY_CSAT, 50);
await generateResponses(SEED_IDS.SURVEY_COMPLETED, 50);
console.log("\n" + "=".repeat(50));
console.log(`\n${"=".repeat(50)}`);
console.log("🚀 SEEDING COMPLETED SUCCESSFULLY");
console.log("=".repeat(50));
console.log("\nLog in with the following credentials:");
@@ -503,14 +572,16 @@ async function main() {
console.log(`\n Member:`);
console.log(` Email: ${SEED_CREDENTIALS.MEMBER.email}`);
console.log(` Password: ${SEED_CREDENTIALS.MEMBER.password}`);
console.log("\n" + "=".repeat(50) + "\n");
console.log(`\n${"=".repeat(50)}\n`);
}
main()
.catch((e) => {
.catch((e: unknown) => {
console.error(e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
.finally(() => {
prisma.$disconnect().catch((e: unknown) => {
console.error("Error disconnecting prisma:", e);
});
});

314
pnpm-lock.yaml generated
View File

@@ -656,6 +656,9 @@ importers:
'@prisma/client':
specifier: 6.14.0
version: 6.14.0(prisma@6.14.0(magicast@0.3.5)(typescript@5.8.3))(typescript@5.8.3)
bcryptjs:
specifier: 2.4.3
version: 2.4.3
zod:
specifier: 3.24.4
version: 3.24.4
@@ -669,6 +672,9 @@ importers:
'@formbricks/eslint-config':
specifier: workspace:*
version: link:../config-eslint
'@types/bcryptjs':
specifier: 2.4.6
version: 2.4.6
dotenv-cli:
specifier: 8.0.0
version: 8.0.0
@@ -684,12 +690,15 @@ importers:
ts-node:
specifier: 10.9.2
version: 10.9.2(@types/node@22.15.18)(typescript@5.8.3)
tsx:
specifier: 4.19.2
version: 4.19.2
vite:
specifier: 6.4.1
version: 6.4.1(@types/node@22.15.18)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.19.4)(yaml@2.8.1)
version: 6.4.1(@types/node@22.15.18)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.19.2)(yaml@2.8.1)
vite-plugin-dts:
specifier: 4.5.3
version: 4.5.3(@types/node@22.15.18)(rollup@4.52.5)(typescript@5.8.3)(vite@6.4.1(@types/node@22.15.18)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.19.4)(yaml@2.8.1))
version: 4.5.3(@types/node@22.15.18)(rollup@4.52.5)(typescript@5.8.3)(vite@6.4.1(@types/node@22.15.18)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.19.2)(yaml@2.8.1))
packages/i18n-utils:
dependencies:
@@ -1726,6 +1735,12 @@ packages:
'@epic-web/invariant@1.0.0':
resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==}
'@esbuild/aix-ppc64@0.23.1':
resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [aix]
'@esbuild/aix-ppc64@0.25.10':
resolution: {integrity: sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==}
engines: {node: '>=18'}
@@ -1738,6 +1753,12 @@ packages:
cpu: [ppc64]
os: [aix]
'@esbuild/android-arm64@0.23.1':
resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [android]
'@esbuild/android-arm64@0.25.10':
resolution: {integrity: sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==}
engines: {node: '>=18'}
@@ -1750,6 +1771,12 @@ packages:
cpu: [arm64]
os: [android]
'@esbuild/android-arm@0.23.1':
resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==}
engines: {node: '>=18'}
cpu: [arm]
os: [android]
'@esbuild/android-arm@0.25.10':
resolution: {integrity: sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==}
engines: {node: '>=18'}
@@ -1762,6 +1789,12 @@ packages:
cpu: [arm]
os: [android]
'@esbuild/android-x64@0.23.1':
resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==}
engines: {node: '>=18'}
cpu: [x64]
os: [android]
'@esbuild/android-x64@0.25.10':
resolution: {integrity: sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==}
engines: {node: '>=18'}
@@ -1774,6 +1807,12 @@ packages:
cpu: [x64]
os: [android]
'@esbuild/darwin-arm64@0.23.1':
resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==}
engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
'@esbuild/darwin-arm64@0.25.10':
resolution: {integrity: sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==}
engines: {node: '>=18'}
@@ -1786,6 +1825,12 @@ packages:
cpu: [arm64]
os: [darwin]
'@esbuild/darwin-x64@0.23.1':
resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==}
engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
'@esbuild/darwin-x64@0.25.10':
resolution: {integrity: sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==}
engines: {node: '>=18'}
@@ -1798,6 +1843,12 @@ packages:
cpu: [x64]
os: [darwin]
'@esbuild/freebsd-arm64@0.23.1':
resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==}
engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
'@esbuild/freebsd-arm64@0.25.10':
resolution: {integrity: sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==}
engines: {node: '>=18'}
@@ -1810,6 +1861,12 @@ packages:
cpu: [arm64]
os: [freebsd]
'@esbuild/freebsd-x64@0.23.1':
resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==}
engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
'@esbuild/freebsd-x64@0.25.10':
resolution: {integrity: sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==}
engines: {node: '>=18'}
@@ -1822,6 +1879,12 @@ packages:
cpu: [x64]
os: [freebsd]
'@esbuild/linux-arm64@0.23.1':
resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==}
engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
'@esbuild/linux-arm64@0.25.10':
resolution: {integrity: sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==}
engines: {node: '>=18'}
@@ -1834,6 +1897,12 @@ packages:
cpu: [arm64]
os: [linux]
'@esbuild/linux-arm@0.23.1':
resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==}
engines: {node: '>=18'}
cpu: [arm]
os: [linux]
'@esbuild/linux-arm@0.25.10':
resolution: {integrity: sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==}
engines: {node: '>=18'}
@@ -1846,6 +1915,12 @@ packages:
cpu: [arm]
os: [linux]
'@esbuild/linux-ia32@0.23.1':
resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==}
engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
'@esbuild/linux-ia32@0.25.10':
resolution: {integrity: sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==}
engines: {node: '>=18'}
@@ -1858,6 +1933,12 @@ packages:
cpu: [ia32]
os: [linux]
'@esbuild/linux-loong64@0.23.1':
resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==}
engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
'@esbuild/linux-loong64@0.25.10':
resolution: {integrity: sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==}
engines: {node: '>=18'}
@@ -1870,6 +1951,12 @@ packages:
cpu: [loong64]
os: [linux]
'@esbuild/linux-mips64el@0.23.1':
resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==}
engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
'@esbuild/linux-mips64el@0.25.10':
resolution: {integrity: sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==}
engines: {node: '>=18'}
@@ -1882,6 +1969,12 @@ packages:
cpu: [mips64el]
os: [linux]
'@esbuild/linux-ppc64@0.23.1':
resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
'@esbuild/linux-ppc64@0.25.10':
resolution: {integrity: sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==}
engines: {node: '>=18'}
@@ -1894,6 +1987,12 @@ packages:
cpu: [ppc64]
os: [linux]
'@esbuild/linux-riscv64@0.23.1':
resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==}
engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
'@esbuild/linux-riscv64@0.25.10':
resolution: {integrity: sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==}
engines: {node: '>=18'}
@@ -1906,6 +2005,12 @@ packages:
cpu: [riscv64]
os: [linux]
'@esbuild/linux-s390x@0.23.1':
resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==}
engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
'@esbuild/linux-s390x@0.25.10':
resolution: {integrity: sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==}
engines: {node: '>=18'}
@@ -1918,6 +2023,12 @@ packages:
cpu: [s390x]
os: [linux]
'@esbuild/linux-x64@0.23.1':
resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
'@esbuild/linux-x64@0.25.10':
resolution: {integrity: sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==}
engines: {node: '>=18'}
@@ -1942,6 +2053,12 @@ packages:
cpu: [arm64]
os: [netbsd]
'@esbuild/netbsd-x64@0.23.1':
resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
'@esbuild/netbsd-x64@0.25.10':
resolution: {integrity: sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==}
engines: {node: '>=18'}
@@ -1954,6 +2071,12 @@ packages:
cpu: [x64]
os: [netbsd]
'@esbuild/openbsd-arm64@0.23.1':
resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openbsd]
'@esbuild/openbsd-arm64@0.25.10':
resolution: {integrity: sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==}
engines: {node: '>=18'}
@@ -1966,6 +2089,12 @@ packages:
cpu: [arm64]
os: [openbsd]
'@esbuild/openbsd-x64@0.23.1':
resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==}
engines: {node: '>=18'}
cpu: [x64]
os: [openbsd]
'@esbuild/openbsd-x64@0.25.10':
resolution: {integrity: sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==}
engines: {node: '>=18'}
@@ -1990,6 +2119,12 @@ packages:
cpu: [arm64]
os: [openharmony]
'@esbuild/sunos-x64@0.23.1':
resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==}
engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
'@esbuild/sunos-x64@0.25.10':
resolution: {integrity: sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==}
engines: {node: '>=18'}
@@ -2002,6 +2137,12 @@ packages:
cpu: [x64]
os: [sunos]
'@esbuild/win32-arm64@0.23.1':
resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==}
engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
'@esbuild/win32-arm64@0.25.10':
resolution: {integrity: sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==}
engines: {node: '>=18'}
@@ -2014,6 +2155,12 @@ packages:
cpu: [arm64]
os: [win32]
'@esbuild/win32-ia32@0.23.1':
resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==}
engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
'@esbuild/win32-ia32@0.25.10':
resolution: {integrity: sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==}
engines: {node: '>=18'}
@@ -2026,6 +2173,12 @@ packages:
cpu: [ia32]
os: [win32]
'@esbuild/win32-x64@0.23.1':
resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==}
engines: {node: '>=18'}
cpu: [x64]
os: [win32]
'@esbuild/win32-x64@0.25.10':
resolution: {integrity: sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==}
engines: {node: '>=18'}
@@ -5744,6 +5897,9 @@ packages:
resolution: {integrity: sha512-JU0h5APyQNsHOlAM7HnQnPToSDQoEBZqzu/YBlqDnEeymPnZDREeXJA3KBMQee+dKteAxZ2AtvQEvVYdZf241Q==}
hasBin: true
bcryptjs@2.4.3:
resolution: {integrity: sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==}
bcryptjs@3.0.2:
resolution: {integrity: sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog==}
hasBin: true
@@ -6472,6 +6628,11 @@ packages:
resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}
engines: {node: '>= 0.4'}
esbuild@0.23.1:
resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==}
engines: {node: '>=18'}
hasBin: true
esbuild@0.25.10:
resolution: {integrity: sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==}
engines: {node: '>=18'}
@@ -9880,6 +10041,11 @@ packages:
peerDependencies:
typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
tsx@4.19.2:
resolution: {integrity: sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==}
engines: {node: '>=18.0.0'}
hasBin: true
tsx@4.19.4:
resolution: {integrity: sha512-gK5GVzDkJK1SI1zwHf32Mqxf2tSJkNx+eYcNly5+nHvWqXUJYUkWBQtKauoESz3ymezAI++ZwT855x5p5eop+Q==}
engines: {node: '>=18.0.0'}
@@ -12288,102 +12454,153 @@ snapshots:
'@epic-web/invariant@1.0.0': {}
'@esbuild/aix-ppc64@0.23.1':
optional: true
'@esbuild/aix-ppc64@0.25.10':
optional: true
'@esbuild/aix-ppc64@0.27.0':
optional: true
'@esbuild/android-arm64@0.23.1':
optional: true
'@esbuild/android-arm64@0.25.10':
optional: true
'@esbuild/android-arm64@0.27.0':
optional: true
'@esbuild/android-arm@0.23.1':
optional: true
'@esbuild/android-arm@0.25.10':
optional: true
'@esbuild/android-arm@0.27.0':
optional: true
'@esbuild/android-x64@0.23.1':
optional: true
'@esbuild/android-x64@0.25.10':
optional: true
'@esbuild/android-x64@0.27.0':
optional: true
'@esbuild/darwin-arm64@0.23.1':
optional: true
'@esbuild/darwin-arm64@0.25.10':
optional: true
'@esbuild/darwin-arm64@0.27.0':
optional: true
'@esbuild/darwin-x64@0.23.1':
optional: true
'@esbuild/darwin-x64@0.25.10':
optional: true
'@esbuild/darwin-x64@0.27.0':
optional: true
'@esbuild/freebsd-arm64@0.23.1':
optional: true
'@esbuild/freebsd-arm64@0.25.10':
optional: true
'@esbuild/freebsd-arm64@0.27.0':
optional: true
'@esbuild/freebsd-x64@0.23.1':
optional: true
'@esbuild/freebsd-x64@0.25.10':
optional: true
'@esbuild/freebsd-x64@0.27.0':
optional: true
'@esbuild/linux-arm64@0.23.1':
optional: true
'@esbuild/linux-arm64@0.25.10':
optional: true
'@esbuild/linux-arm64@0.27.0':
optional: true
'@esbuild/linux-arm@0.23.1':
optional: true
'@esbuild/linux-arm@0.25.10':
optional: true
'@esbuild/linux-arm@0.27.0':
optional: true
'@esbuild/linux-ia32@0.23.1':
optional: true
'@esbuild/linux-ia32@0.25.10':
optional: true
'@esbuild/linux-ia32@0.27.0':
optional: true
'@esbuild/linux-loong64@0.23.1':
optional: true
'@esbuild/linux-loong64@0.25.10':
optional: true
'@esbuild/linux-loong64@0.27.0':
optional: true
'@esbuild/linux-mips64el@0.23.1':
optional: true
'@esbuild/linux-mips64el@0.25.10':
optional: true
'@esbuild/linux-mips64el@0.27.0':
optional: true
'@esbuild/linux-ppc64@0.23.1':
optional: true
'@esbuild/linux-ppc64@0.25.10':
optional: true
'@esbuild/linux-ppc64@0.27.0':
optional: true
'@esbuild/linux-riscv64@0.23.1':
optional: true
'@esbuild/linux-riscv64@0.25.10':
optional: true
'@esbuild/linux-riscv64@0.27.0':
optional: true
'@esbuild/linux-s390x@0.23.1':
optional: true
'@esbuild/linux-s390x@0.25.10':
optional: true
'@esbuild/linux-s390x@0.27.0':
optional: true
'@esbuild/linux-x64@0.23.1':
optional: true
'@esbuild/linux-x64@0.25.10':
optional: true
@@ -12396,18 +12613,27 @@ snapshots:
'@esbuild/netbsd-arm64@0.27.0':
optional: true
'@esbuild/netbsd-x64@0.23.1':
optional: true
'@esbuild/netbsd-x64@0.25.10':
optional: true
'@esbuild/netbsd-x64@0.27.0':
optional: true
'@esbuild/openbsd-arm64@0.23.1':
optional: true
'@esbuild/openbsd-arm64@0.25.10':
optional: true
'@esbuild/openbsd-arm64@0.27.0':
optional: true
'@esbuild/openbsd-x64@0.23.1':
optional: true
'@esbuild/openbsd-x64@0.25.10':
optional: true
@@ -12420,24 +12646,36 @@ snapshots:
'@esbuild/openharmony-arm64@0.27.0':
optional: true
'@esbuild/sunos-x64@0.23.1':
optional: true
'@esbuild/sunos-x64@0.25.10':
optional: true
'@esbuild/sunos-x64@0.27.0':
optional: true
'@esbuild/win32-arm64@0.23.1':
optional: true
'@esbuild/win32-arm64@0.25.10':
optional: true
'@esbuild/win32-arm64@0.27.0':
optional: true
'@esbuild/win32-ia32@0.23.1':
optional: true
'@esbuild/win32-ia32@0.25.10':
optional: true
'@esbuild/win32-ia32@0.27.0':
optional: true
'@esbuild/win32-x64@0.23.1':
optional: true
'@esbuild/win32-x64@0.25.10':
optional: true
@@ -17007,6 +17245,8 @@ snapshots:
baseline-browser-mapping@2.8.21: {}
bcryptjs@2.4.3: {}
bcryptjs@3.0.2: {}
bidi-js@1.0.3:
@@ -17789,6 +18029,33 @@ snapshots:
is-date-object: 1.1.0
is-symbol: 1.1.1
esbuild@0.23.1:
optionalDependencies:
'@esbuild/aix-ppc64': 0.23.1
'@esbuild/android-arm': 0.23.1
'@esbuild/android-arm64': 0.23.1
'@esbuild/android-x64': 0.23.1
'@esbuild/darwin-arm64': 0.23.1
'@esbuild/darwin-x64': 0.23.1
'@esbuild/freebsd-arm64': 0.23.1
'@esbuild/freebsd-x64': 0.23.1
'@esbuild/linux-arm': 0.23.1
'@esbuild/linux-arm64': 0.23.1
'@esbuild/linux-ia32': 0.23.1
'@esbuild/linux-loong64': 0.23.1
'@esbuild/linux-mips64el': 0.23.1
'@esbuild/linux-ppc64': 0.23.1
'@esbuild/linux-riscv64': 0.23.1
'@esbuild/linux-s390x': 0.23.1
'@esbuild/linux-x64': 0.23.1
'@esbuild/netbsd-x64': 0.23.1
'@esbuild/openbsd-arm64': 0.23.1
'@esbuild/openbsd-x64': 0.23.1
'@esbuild/sunos-x64': 0.23.1
'@esbuild/win32-arm64': 0.23.1
'@esbuild/win32-ia32': 0.23.1
'@esbuild/win32-x64': 0.23.1
esbuild@0.25.10:
optionalDependencies:
'@esbuild/aix-ppc64': 0.25.10
@@ -21640,6 +21907,13 @@ snapshots:
tslib: 1.14.1
typescript: 5.8.3
tsx@4.19.2:
dependencies:
esbuild: 0.23.1
get-tsconfig: 4.13.0
optionalDependencies:
fsevents: 2.3.3
tsx@4.19.4:
dependencies:
esbuild: 0.25.10
@@ -21982,6 +22256,25 @@ snapshots:
- rollup
- supports-color
vite-plugin-dts@4.5.3(@types/node@22.15.18)(rollup@4.52.5)(typescript@5.8.3)(vite@6.4.1(@types/node@22.15.18)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.19.2)(yaml@2.8.1)):
dependencies:
'@microsoft/api-extractor': 7.53.3(@types/node@22.15.18)
'@rollup/pluginutils': 5.3.0(rollup@4.52.5)
'@volar/typescript': 2.4.23
'@vue/language-core': 2.2.0(typescript@5.8.3)
compare-versions: 6.1.1
debug: 4.4.3
kolorist: 1.8.0
local-pkg: 1.1.2
magic-string: 0.30.21
typescript: 5.8.3
optionalDependencies:
vite: 6.4.1(@types/node@22.15.18)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.19.2)(yaml@2.8.1)
transitivePeerDependencies:
- '@types/node'
- rollup
- supports-color
vite-plugin-dts@4.5.3(@types/node@22.15.18)(rollup@4.52.5)(typescript@5.8.3)(vite@6.4.1(@types/node@22.15.18)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.19.4)(yaml@2.8.1)):
dependencies:
'@microsoft/api-extractor': 7.53.3(@types/node@22.15.18)
@@ -22078,6 +22371,23 @@ snapshots:
tsx: 4.19.4
yaml: 2.8.1
vite@6.4.1(@types/node@22.15.18)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.19.2)(yaml@2.8.1):
dependencies:
esbuild: 0.25.10
fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3
postcss: 8.5.3
rollup: 4.52.5
tinyglobby: 0.2.15
optionalDependencies:
'@types/node': 22.15.18
fsevents: 2.3.3
jiti: 2.6.1
lightningcss: 1.30.2
terser: 5.44.1
tsx: 4.19.2
yaml: 2.8.1
vite@6.4.1(@types/node@22.15.18)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.19.4)(yaml@2.8.1):
dependencies:
esbuild: 0.25.10

View File

@@ -274,6 +274,7 @@
"outputs": []
},
"db:seed": {
"env": ["ALLOW_SEED"],
"outputs": []
},
"db:setup": {