startx 1.1.0 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -20,20 +20,21 @@
20
20
  "author": "",
21
21
  "license": "ISC",
22
22
  "devDependencies": {
23
- "cross-env": "^10.1.0",
23
+ "cross-env": "catalog:",
24
24
  "eslint-config": "workspace:*",
25
25
  "tsdown-config": "workspace:*",
26
26
  "typescript-config": "workspace:*",
27
27
  "vitest-config": "workspace:*"
28
28
  },
29
29
  "dependencies": {
30
- "@inquirer/prompts": "^8.3.0",
30
+ "@inquirer/prompts": "catalog:",
31
31
  "@repo/lib": "workspace:*",
32
32
  "@repo/logger": "workspace:*",
33
33
  "@repo/env": "workspace:*",
34
- "chokidar": "^4.0.3",
35
- "commander": "^14.0.0",
36
- "type-fest": "^5.4.4"
34
+ "chokidar": "catalog:",
35
+ "commander": "catalog:",
36
+ "type-fest": "catalog:",
37
+ "yaml": "catalog:"
37
38
  },
38
39
  "startx": {
39
40
  "mode": "silent",
@@ -4,8 +4,10 @@ import { spawn } from "child_process";
4
4
  import { Command } from "commander";
5
5
  import fs from "fs/promises";
6
6
  import path from "path";
7
+ import YAML from "yaml";
7
8
  import z from "zod";
8
9
 
10
+ import { DepCheck } from "../configs/deps";
9
11
  import { FileCheck } from "../configs/files";
10
12
  import type { StartXPackageJson, TAGS } from "../types";
11
13
  import { CliUtils, type PackageItem } from "../utils/cli-utils";
@@ -15,6 +17,7 @@ import { CommonInquirer } from "../utils/inquirer";
15
17
  type PackageOptions = {
16
18
  eslint?: boolean;
17
19
  install?: boolean;
20
+ name?: string;
18
21
  };
19
22
 
20
23
  type NewPackageOptions = PackageOptions & {
@@ -39,11 +42,12 @@ export class PackageCommand {
39
42
  )
40
43
  .addCommand(
41
44
  new Command("add")
42
- .description("Add an existing StartX package by name.")
45
+ .description("Add an existing StartX app or package, optionally with a new name.")
43
46
  .argument("[packageName]")
47
+ .option("-n, --name <name>", "override the name for the added package")
44
48
  .option("--eslint", "enable ESLint support for the added package")
45
49
  .option("--no-eslint", "skip ESLint support for the added package")
46
- .option("--no-install", "do not run the package manager after updating ESLint")
50
+ .option("--no-install", "do not run the package manager after updating dependencies")
47
51
  .action(PackageCommand.add.bind(PackageCommand))
48
52
  )
49
53
  .addCommand(
@@ -85,7 +89,7 @@ export class PackageCommand {
85
89
  const selectedName =
86
90
  packageName ??
87
91
  (await CommonInquirer.choose({
88
- message: "Select package to add",
92
+ message: "Select app or package to add",
89
93
  options: availablePackages.map(pkg => pkg.name),
90
94
  mode: "single",
91
95
  required: true,
@@ -96,6 +100,16 @@ export class PackageCommand {
96
100
  throw new Error(`Package "${selectedName}" was not found in the StartX template.`);
97
101
  }
98
102
 
103
+ const templateName = selectedPackage.packageJson?.name ?? selectedPackage.name;
104
+ const overrideName =
105
+ options.name ??
106
+ (await CommonInquirer.getText({
107
+ message: "Name for the new package (leave unchanged to keep the original)",
108
+ name: "overrideName",
109
+ default: templateName,
110
+ schema: packageNameSchema,
111
+ }));
112
+
99
113
  const directory = CliUtils.getDirectory();
100
114
  const eslintEnabled = await this.resolveEslintPreference(options);
101
115
  const packagesToInstall = this.resolvePackageClosure({
@@ -109,15 +123,24 @@ export class PackageCommand {
109
123
  eslintEnabled,
110
124
  });
111
125
 
126
+ await this.checkAndInstallMissingDeps({
127
+ workspace: directory.workspace,
128
+ tags,
129
+ install: options.install,
130
+ });
131
+
112
132
  for (const pkg of packagesToInstall) {
133
+ const isMain = pkg.name === selectedPackage.name;
113
134
  await this.installTemplatePackage({
114
135
  pkg,
115
136
  directory,
116
137
  tags,
138
+ overrideName: isMain ? overrideName : undefined,
139
+ overrideRelativePath: isMain ? this.getDestinationPath(pkg.relativePath, overrideName) : undefined,
117
140
  });
118
141
  }
119
142
 
120
- logger.info(`Package add complete: ${selectedPackage.name}`);
143
+ logger.info(`Done! Run \`pnpm install\` to link the new package.`);
121
144
  }
122
145
 
123
146
  private static async create(packageName: string | undefined, options: NewPackageOptions) {
@@ -136,8 +159,11 @@ export class PackageCommand {
136
159
  throw new Error(`Package directory already exists: ${packageDir}`);
137
160
  }
138
161
 
162
+ const rootPackage = await this.readRootPackage(directory.workspace);
139
163
  const eslintEnabled = await this.resolveEslintPreference(options);
164
+ const vitestEnabled = this.hasDependency(rootPackage, "vitest");
140
165
  const packages = await CliUtils.getPackageList();
166
+
141
167
  await this.ensureTemplatePackage({
142
168
  packages,
143
169
  name: "typescript-config",
@@ -154,8 +180,20 @@ export class PackageCommand {
154
180
  });
155
181
  }
156
182
 
183
+ if (vitestEnabled) {
184
+ await this.ensureTemplatePackage({
185
+ packages,
186
+ name: "vitest-config",
187
+ directory,
188
+ tags: ["common", "node", "vitest"],
189
+ });
190
+ }
191
+
157
192
  await fs.mkdir(path.join(packageDir, "src"), { recursive: true });
158
- await this.writeJson(path.join(packageDir, "package.json"), this.createPackageJson({ name, eslintEnabled }));
193
+ await this.writeJson(
194
+ path.join(packageDir, "package.json"),
195
+ this.createPackageJson({ name, eslintEnabled, vitestEnabled })
196
+ );
159
197
  await fs.writeFile(
160
198
  path.join(packageDir, "tsconfig.json"),
161
199
  `${JSON.stringify(
@@ -181,7 +219,15 @@ export class PackageCommand {
181
219
  );
182
220
  }
183
221
 
222
+ if (vitestEnabled) {
223
+ await fs.writeFile(
224
+ path.join(packageDir, "vitest.config.ts"),
225
+ `import vitestConfig from "vitest-config/node";\n\nexport default vitestConfig;\n`
226
+ );
227
+ }
228
+
184
229
  logger.info(`Created package ${name} at ${path.relative(directory.workspace, packageDir)}`);
230
+ logger.info(`Run \`pnpm install\` to link the new package.`);
185
231
  }
186
232
 
187
233
  private static async resolveEslintPreference(options: PackageOptions) {
@@ -216,11 +262,7 @@ export class PackageCommand {
216
262
  return true;
217
263
  }
218
264
 
219
- private static async getInstallTags(props: {
220
- workspace: string;
221
- packages: PackageItem[];
222
- eslintEnabled: boolean;
223
- }) {
265
+ private static async getInstallTags(props: { workspace: string; packages: PackageItem[]; eslintEnabled: boolean }) {
224
266
  const tags = new Set<TAGS>(["common", "node"]);
225
267
  const rootPackage = await this.readRootPackage(props.workspace);
226
268
 
@@ -228,6 +270,7 @@ export class PackageCommand {
228
270
  if (this.hasDependency(rootPackage, "@biomejs/biome")) tags.add("biome");
229
271
  if (this.hasDependency(rootPackage, "prettier")) tags.add("prettier");
230
272
  if (this.hasDependency(rootPackage, "vitest")) tags.add("vitest");
273
+ if (this.hasDependency(rootPackage, "tsdown")) tags.add("tsdown");
231
274
 
232
275
  for (const pkg of props.packages) {
233
276
  pkg.packageJson?.startx?.tags?.forEach(tag => tags.add(tag));
@@ -295,15 +338,25 @@ export class PackageCommand {
295
338
  pkg: PackageItem;
296
339
  directory: ReturnType<typeof CliUtils.getDirectory>;
297
340
  tags: TAGS[];
341
+ overrideName?: string;
342
+ overrideRelativePath?: string;
298
343
  }) {
299
344
  if (!props.pkg.packageJson) {
300
345
  throw new Error(`Missing package.json for ${props.pkg.name}`);
301
346
  }
302
347
 
303
- const destination = path.join(props.directory.workspace, props.pkg.relativePath);
348
+ const relativePath = props.overrideRelativePath ?? props.pkg.relativePath;
349
+ const destination = path.join(props.directory.workspace, relativePath);
350
+
304
351
  if (await this.pathExists(path.join(destination, "package.json"))) {
305
- logger.info(`Skipping ${props.pkg.name}; it already exists.`);
306
- return;
352
+ const overwrite = await CommonInquirer.confirm({
353
+ message: `"${relativePath}" already exists. Overwrite?`,
354
+ default: false,
355
+ });
356
+ if (!overwrite) {
357
+ logger.info(`Skipping ${props.pkg.name}.`);
358
+ return;
359
+ }
307
360
  }
308
361
 
309
362
  const tags = new Set<TAGS>([...props.tags, ...(props.pkg.packageJson.startx?.tags ?? [])]);
@@ -314,13 +367,18 @@ export class PackageCommand {
314
367
  const { packageJson, isWorkspace } = FileHandler.handlePackageJson({
315
368
  app: props.pkg.packageJson,
316
369
  tags: Array.from(tags),
317
- name: props.pkg.packageJson.name || props.pkg.name,
370
+ name: props.overrideName ?? props.pkg.packageJson.name ?? props.pkg.name,
318
371
  });
319
372
 
320
373
  if (isWorkspace) {
321
374
  throw new Error(`Cannot install workspace as a package: ${props.pkg.name}`);
322
375
  }
323
376
 
377
+ await this.syncDepsWithCatalog({
378
+ workspace: props.directory.workspace,
379
+ packageJson: packageJson as Record<string, unknown>,
380
+ });
381
+
324
382
  await fsTool.writeJSONFile({ dir: destination, file: "package", content: packageJson });
325
383
  await this.copyValidatedFilesFromFolder(props.pkg.path, destination, tags);
326
384
  await fsTool.copyDirectory({
@@ -329,7 +387,7 @@ export class PackageCommand {
329
387
  exclude: !tags.has("vitest") ? /\.test\.tsx?$/ : undefined,
330
388
  });
331
389
 
332
- logger.info(`Installed ${props.pkg.name}`);
390
+ logger.info(`Installed ${props.overrideName ?? props.pkg.name} at ${relativePath}`);
333
391
  }
334
392
 
335
393
  private static async copyValidatedFilesFromFolder(source: string, destination: string, tags: Set<TAGS>) {
@@ -346,7 +404,7 @@ export class PackageCommand {
346
404
  }
347
405
  }
348
406
 
349
- private static createPackageJson(props: { name: string; eslintEnabled: boolean }) {
407
+ private static createPackageJson(props: { name: string; eslintEnabled: boolean; vitestEnabled: boolean }) {
350
408
  const scripts: Record<string, string> = {
351
409
  typecheck: "tsc --noEmit",
352
410
  clean: "rimraf dist .turbo",
@@ -354,11 +412,21 @@ export class PackageCommand {
354
412
  const devDependencies: Record<string, string> = {
355
413
  "typescript-config": "workspace:*",
356
414
  };
415
+ const ignore: string[] = [];
357
416
 
358
417
  if (props.eslintEnabled) {
359
418
  scripts.lint = "eslint .";
360
419
  scripts["lint:fix"] = "eslint . --fix";
361
420
  devDependencies["eslint-config"] = "workspace:*";
421
+ } else {
422
+ ignore.push("eslint-config");
423
+ }
424
+
425
+ if (props.vitestEnabled) {
426
+ scripts.test = "vitest run";
427
+ devDependencies["vitest-config"] = "workspace:*";
428
+ } else {
429
+ ignore.push("vitest-config");
362
430
  }
363
431
 
364
432
  return {
@@ -371,11 +439,62 @@ export class PackageCommand {
371
439
  startx: {
372
440
  iTags: ["node"],
373
441
  requiredDevDeps: ["typescript-config"],
374
- ...(props.eslintEnabled ? {} : { ignore: ["eslint-config"] }),
442
+ ...(ignore.length > 0 ? { ignore } : {}),
375
443
  },
376
444
  };
377
445
  }
378
446
 
447
+ private static async checkAndInstallMissingDeps(props: { workspace: string; tags: TAGS[]; install?: boolean }) {
448
+ const rootPackage = await this.readRootPackage(props.workspace);
449
+ const pnpmWorkspace = await CliUtils.parsePnpmWorkspace({ dir: props.workspace });
450
+
451
+ const missing: Array<{ name: string; version: string; isDev: boolean }> = [];
452
+ for (const [dep, config] of Object.entries(DepCheck)) {
453
+ if (!config.tags.every(tag => props.tags.includes(tag))) continue;
454
+ if (config.tags.includes("root")) continue;
455
+ if (this.hasDependency(rootPackage, dep)) continue;
456
+ const version = pnpmWorkspace?.catalog?.[dep] ? "catalog:" : config.version;
457
+ missing.push({ name: dep, version, isDev: config.isDevDependency ?? true });
458
+ }
459
+
460
+ if (missing.length === 0) return;
461
+
462
+ logger.warn(`The following workspace dependencies are required but not installed:`);
463
+ for (const dep of missing) {
464
+ logger.warn(` - ${dep.name}`);
465
+ }
466
+
467
+ const shouldAdd = await CommonInquirer.confirm({
468
+ message: "Add them to the workspace root package.json?",
469
+ default: true,
470
+ });
471
+ if (!shouldAdd) {
472
+ logger.warn("Skipping. Some features may not work correctly without these dependencies.");
473
+ return;
474
+ }
475
+
476
+ for (const dep of missing) {
477
+ if (dep.isDev) {
478
+ (rootPackage.devDependencies as Record<string, string>)[dep.name] = dep.version;
479
+ } else {
480
+ (rootPackage.dependencies as Record<string, string>)[dep.name] = dep.version;
481
+ }
482
+ }
483
+
484
+ await this.writeJson(path.join(props.workspace, "package.json"), rootPackage);
485
+ logger.info("Added missing dependencies to root package.json.");
486
+
487
+ if (props.install !== false) {
488
+ await this.installRootDependencies(props.workspace);
489
+ }
490
+ }
491
+
492
+ private static getDestinationPath(templateRelativePath: string, newName: string): string {
493
+ const parentDir = path.dirname(templateRelativePath);
494
+ const leafName = newName.includes("/") ? newName.split("/").pop()! : newName;
495
+ return path.join(parentDir, leafName);
496
+ }
497
+
379
498
  private static getDefaultPackagePath(name: string) {
380
499
  if (name.startsWith("@")) {
381
500
  const [scope, packageName] = name.split("/");
@@ -438,6 +557,55 @@ export class PackageCommand {
438
557
  });
439
558
  }
440
559
 
560
+ private static async syncDepsWithCatalog(props: {
561
+ workspace: string;
562
+ packageJson: Record<string, unknown>;
563
+ }): Promise<void> {
564
+ const workspacePath = path.join(props.workspace, "pnpm-workspace.yaml");
565
+ let content: string;
566
+ try {
567
+ content = await fs.readFile(workspacePath, "utf-8");
568
+ } catch {
569
+ throw new Error(`Could not find workspace file at ${workspacePath}.`);
570
+ }
571
+
572
+ const doc = YAML.parseDocument(content);
573
+ const catalog = doc.getIn(["catalog"]) as Record<string, string> | undefined;
574
+ if (!catalog) return;
575
+
576
+ const deps = props.packageJson.dependencies as Record<string, string> | undefined;
577
+ const devDeps = props.packageJson.devDependencies as Record<string, string> | undefined;
578
+ const newEntries: Record<string, string> = {};
579
+
580
+ const processMap = (depMap: Record<string, string> | undefined) => {
581
+ if (!depMap) return;
582
+ for (const [name, version] of Object.entries(depMap)) {
583
+ if (version === "catalog:" || version.startsWith("workspace:")) continue;
584
+ if (catalog[name]) {
585
+ depMap[name] = "catalog:";
586
+ } else {
587
+ newEntries[name] = version;
588
+ depMap[name] = "catalog:";
589
+ }
590
+ }
591
+ };
592
+
593
+ processMap(deps);
594
+ processMap(devDeps);
595
+
596
+ if (Object.keys(newEntries).length === 0) return;
597
+
598
+ for (const [name, version] of Object.entries(newEntries)) {
599
+ doc.setIn(["catalog", name], version);
600
+ }
601
+
602
+ await fs.writeFile(workspacePath, doc.toString());
603
+ logger.info("Added to pnpm-workspace.yaml catalog:");
604
+ for (const [name, version] of Object.entries(newEntries)) {
605
+ logger.info(` + ${name}: ${version}`);
606
+ }
607
+ }
608
+
441
609
  private static async writeJson(file: string, content: object) {
442
610
  await fs.writeFile(file, `${JSON.stringify(content, null, 2)}\n`);
443
611
  }
@@ -16,6 +16,9 @@ export const FileCheck: WHITELIST_FILES = {
16
16
  ".prettierignore": {
17
17
  tags: ["biome"],
18
18
  },
19
+ "README.md": {
20
+ tags: ["never"],
21
+ },
19
22
  "biome.json": {
20
23
  tags: ["biome"],
21
24
  },
@@ -3,6 +3,7 @@ import { logger } from "@repo/logger";
3
3
  import { Command } from "commander";
4
4
 
5
5
  import { InitCommand } from "./commands/init";
6
+ import { PackageCommand } from "./commands/package";
6
7
  import { version } from "../../../package.json";
7
8
 
8
9
  const program = new Command();
@@ -14,6 +15,6 @@ program.command("ping").action(() => {
14
15
  });
15
16
 
16
17
  program.addCommand(InitCommand.command);
17
- // program.addCommand(PackageCommand.command);
18
+ program.addCommand(PackageCommand.command);
18
19
 
19
20
  program.parse(process.argv);
@@ -23,7 +23,7 @@
23
23
  "react": "catalog:",
24
24
  "react-dom": "catalog:",
25
25
  "react-router": "catalog:",
26
- "zustand": "^5.0.13",
26
+ "zustand": "catalog:",
27
27
  "@repo/common": "workspace:*"
28
28
  },
29
29
  "devDependencies": {
@@ -20,29 +20,29 @@
20
20
  "test": "vitest run"
21
21
  },
22
22
  "dependencies": {
23
- "@eslint/compat": "^2.0.2",
24
- "@eslint/js": "^9.0.0",
25
- "@stylistic/eslint-plugin": "^2.0.0",
26
- "eslint-config-prettier": "^9.1.0",
27
- "eslint-import-resolver-typescript": "^3.6.1",
28
- "eslint-plugin-import-x": "^4.0.0",
29
- "eslint-plugin-jsx-a11y": "^6.9.0",
30
- "eslint-plugin-lodash": "^8.0.0",
31
- "eslint-plugin-react": "^7.35.0",
32
- "eslint-plugin-react-hooks": "^5.0.0",
33
- "eslint-plugin-unicorn": "^55.0.0",
34
- "eslint-plugin-unused-imports": "^4.0.0",
35
- "globals": "^15.9.0"
23
+ "@eslint/compat": "catalog:",
24
+ "@eslint/js": "catalog:",
25
+ "@stylistic/eslint-plugin": "catalog:",
26
+ "eslint-config-prettier": "catalog:",
27
+ "eslint-import-resolver-typescript": "catalog:",
28
+ "eslint-plugin-import-x": "catalog:",
29
+ "eslint-plugin-jsx-a11y": "catalog:",
30
+ "eslint-plugin-lodash": "catalog:",
31
+ "eslint-plugin-react": "catalog:",
32
+ "eslint-plugin-react-hooks": "catalog:",
33
+ "eslint-plugin-unicorn": "catalog:",
34
+ "eslint-plugin-unused-imports": "catalog:",
35
+ "globals": "catalog:"
36
36
  },
37
37
  "devDependencies": {
38
- "typescript-eslint": "^8.54.0",
39
- "@types/eslint-config-prettier": "^6.11.3",
40
- "@types/eslint-plugin-jsx-a11y": "^6.10.1",
41
- "@typescript-eslint/eslint-plugin": "^8.0.0",
42
- "@typescript-eslint/rule-tester": "^8.54.0",
43
- "@typescript-eslint/utils": "^8.0.0",
38
+ "@types/eslint-config-prettier": "catalog:",
39
+ "@types/eslint-plugin-jsx-a11y": "catalog:",
40
+ "@typescript-eslint/eslint-plugin": "catalog:",
41
+ "@typescript-eslint/rule-tester": "catalog:",
42
+ "@typescript-eslint/utils": "catalog:",
44
43
  "eslint": "catalog:",
45
44
  "typescript-config": "workspace:*",
45
+ "typescript-eslint": "catalog:",
46
46
  "vitest-config": "workspace:*"
47
47
  },
48
48
  "startx": {
@@ -3,7 +3,7 @@
3
3
  "version": "1.5.0",
4
4
  "type": "module",
5
5
  "devDependencies": {
6
- "jsdom": "^29.0.1",
6
+ "jsdom": "catalog:",
7
7
  "typescript-config": "workspace:*",
8
8
  "vite": "catalog:",
9
9
  "vitest": "catalog:"
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "startx",
3
3
  "description": "",
4
- "version": "1.1.0",
4
+ "version": "1.1.2",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/avinashid/startx.git"
@@ -18,8 +18,8 @@
18
18
  "./*": "./src/*/index.ts"
19
19
  },
20
20
  "devDependencies": {
21
- "@types/jsonwebtoken": "^9.0.7",
22
- "@types/nodemailer": "^6.4.16",
21
+ "@types/jsonwebtoken": "catalog:",
22
+ "@types/nodemailer": "catalog:",
23
23
  "eslint-config": "workspace:*",
24
24
  "typescript-config": "workspace:*",
25
25
  "vine": "link:@types/vinejs/vine",
@@ -38,7 +38,7 @@
38
38
  "firebase-admin": "catalog:",
39
39
  "jsonwebtoken": "catalog:",
40
40
  "nodemailer": "catalog:",
41
- "yaml": "^2.8.2"
41
+ "yaml": "catalog:"
42
42
  },
43
43
  "startx": {
44
44
  "iTags": [
@@ -21,14 +21,14 @@
21
21
  "vitest-config": "workspace:*"
22
22
  },
23
23
  "dependencies": {
24
- "@aws-sdk/client-bedrock": "^3.1047.0",
25
- "@aws-sdk/client-bedrock-runtime": "^3.1047.0",
24
+ "@aws-sdk/client-bedrock": "catalog:",
25
+ "@aws-sdk/client-bedrock-runtime": "catalog:",
26
26
  "@repo/env": "workspace:*",
27
27
  "@repo/lib": "workspace:*",
28
28
  "@repo/logger": "workspace:*",
29
- "@toon-format/toon": "^2.1.0",
29
+ "@toon-format/toon": "catalog:",
30
30
  "js-tiktoken": "catalog:",
31
- "jsonrepair": "^3.14.0",
31
+ "jsonrepair": "catalog:",
32
32
  "openai": "catalog:",
33
33
  "pg": "catalog:",
34
34
  "quickjs-emscripten": "catalog:",
@@ -19,34 +19,34 @@
19
19
  "@tailwindcss/vite": "catalog:",
20
20
  "@types/react": "catalog:",
21
21
  "@types/react-dom": "catalog:",
22
- "autoprefixer": "^10",
22
+ "autoprefixer": "catalog:",
23
23
  "eslint-config": "workspace:*",
24
24
  "tailwindcss": "catalog:",
25
25
  "typescript-config": "workspace:*",
26
26
  "vitest-config": "workspace:*"
27
27
  },
28
28
  "dependencies": {
29
- "@fontsource-variable/eb-garamond": "^5.2.7",
30
- "@fontsource-variable/inter": "^5.2.8",
31
- "@hookform/resolvers": "^3.9.1",
32
- "@phosphor-icons/react": "^2.1.10",
33
- "@tailwindcss/postcss": "^4",
34
- "@tailwindcss/typography": "^0.5.19",
29
+ "@fontsource-variable/eb-garamond": "catalog:",
30
+ "@fontsource-variable/inter": "catalog:",
31
+ "@hookform/resolvers": "catalog:",
32
+ "@phosphor-icons/react": "catalog:",
33
+ "@tailwindcss/postcss": "catalog:",
34
+ "@tailwindcss/typography": "catalog:",
35
35
  "@tanstack/react-query": "catalog:",
36
36
  "@tanstack/react-query-devtools": "catalog:",
37
- "class-variance-authority": "^0.7.1",
38
- "clsx": "^2.1.1",
39
- "cmdk": "^1.1.1",
40
- "embla-carousel-react": "^8.6.0",
41
- "input-otp": "^1.4.2",
37
+ "class-variance-authority": "catalog:",
38
+ "clsx": "catalog:",
39
+ "cmdk": "catalog:",
40
+ "embla-carousel-react": "catalog:",
41
+ "input-otp": "catalog:",
42
42
  "lucide-react": "catalog:",
43
- "next-themes": "^0.4.6",
44
- "radix-ui": "^1.4.3",
45
- "react-hook-form": "^7.75.0",
46
- "react-icons": "^5.5.0",
47
- "sonner": "^2.0.7",
48
- "tailwind-merge": "^2.3.0",
49
- "tw-animate-css": "^1.4.0"
43
+ "next-themes": "catalog:",
44
+ "radix-ui": "catalog:",
45
+ "react-hook-form": "catalog:",
46
+ "react-icons": "catalog:",
47
+ "sonner": "catalog:",
48
+ "tailwind-merge": "catalog:",
49
+ "tw-animate-css": "catalog:"
50
50
  },
51
51
  "exports": {
52
52
  "./globals.css": "./src/styles/globals.css",