@puzzle-ui/create 0.4.0 → 0.5.0

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.
package/README.md CHANGED
@@ -1,40 +1,210 @@
1
1
  # @puzzle-ui/create
2
2
 
3
- Create React applications with Puzzle UI.
3
+ Create a new React application with Puzzle UI installed and configured.
4
+
5
+ The CLI scaffolds a React application, configures the Puzzle theme, optionally configures Tailwind CSS, and can add the Puzzle authentication client and framework integration.
4
6
 
5
7
  ## Requirements
6
8
 
7
- - Node.js >= 20.19
8
- - npm or Bun
9
+ - Node.js 20.19 or later.
10
+ - npm, Bun, pnpm, or Yarn.
11
+ - An internet connection to download framework templates and dependencies.
9
12
 
10
- ## Usage
13
+ ## Quick start
11
14
 
12
- With npm:
15
+ ### npm
13
16
 
14
17
  ```bash
15
18
  npx @puzzle-ui/create
16
19
  ```
17
20
 
18
- With Bun:
21
+ ### Bun
19
22
 
20
23
  ```bash
21
24
  bunx @puzzle-ui/create
22
25
  ```
23
26
 
27
+ ### pnpm
28
+
29
+ ```bash
30
+ pnpm dlx @puzzle-ui/create
31
+ ```
32
+
33
+ ### Yarn
34
+
35
+ ```bash
36
+ yarn dlx @puzzle-ui/create
37
+ ```
38
+
39
+ Yarn's <code>dlx</code> command requires Yarn 2 or later. With Yarn Classic, use <code>npx @puzzle-ui/create</code> instead.
40
+
41
+ The CLI detects the package manager from the execution environment and uses it for framework generation and dependency installation.
42
+
24
43
  ## Supported frameworks
25
44
 
26
- - Next.js
27
- - TanStack Start
28
- - Basic React (Vite + TypeScript)
45
+ | Framework | Description |
46
+ | -------------- | ---------------------------------- |
47
+ | Next.js | Next.js App Router with TypeScript |
48
+ | TanStack Start | Full-stack React application |
49
+ | Basic React | React, Vite, and TypeScript |
50
+
51
+ ## Setup options
52
+
53
+ The interactive setup asks for:
54
+
55
+ 1. **Project name** — converted to kebab-case and used as the project directory and package name.
56
+ 2. **Framework** — Next.js, TanStack Start, or Basic React.
57
+ 3. **Tailwind CSS** — optionally configures Tailwind CSS v4.
58
+ 4. **Puzzle Auth** — optionally installs and configures the Puzzle authentication client and framework integration.
59
+
60
+ The CLI then:
61
+
62
+ 1. Checks that the target directory does not already exist.
63
+ 2. Generates the selected framework.
64
+ 3. Configures framework package transpilation where required.
65
+ 4. Configures the Puzzle theme provider.
66
+ 5. Updates the generated package name.
67
+ 6. Optionally configures and installs Tailwind CSS.
68
+ 7. Optionally configures Puzzle Auth.
69
+ 8. Installs the selected Puzzle packages.
70
+
71
+ The CLI does not overwrite an existing directory.
72
+
73
+ ## Puzzle UI and Theme
74
+
75
+ The generated application includes:
76
+
77
+ - React 19 and TypeScript.
78
+ - A configured Puzzle <code>Theme</code> provider.
79
+ - A starter page using the Puzzle <code>Button</code> component.
80
+ - A framework-specific entry point and development configuration.
81
+ - Optional Tailwind CSS v4 integration.
82
+
83
+ ## Puzzle Auth
84
+
85
+ When enabled, the generator installs:
86
+
87
+ - <code>@puzzle-ui/auth</code>
88
+ - <code>@puzzle-ui/fullstack</code>
89
+ - <code>@puzzle-ui/session</code>
90
+
91
+ The generated client integration includes:
92
+
93
+ - An <code>AuthProvider</code> configured with <code>/api/auth</code>.
94
+ - A sign-in page using <code>AuthExperience</code>.
95
+ - A sign-up page using <code>AuthExperience</code>.
96
+ - A framework-specific authentication API route for Next.js or TanStack Start.
97
+ - A server-only AuthServer registration boundary.
98
+ - A bootstrap function for application-specific server configuration.
99
+
100
+ ### Important server setup
101
+
102
+ Puzzle Auth intentionally does not ship an insecure default password hasher, storage adapter, or production rate limiter.
103
+
104
+ You must configure the following application dependencies:
105
+
106
+ - A storage adapter with the atomicity and uniqueness capabilities required by Puzzle Auth.
107
+ - A secure password hashing provider.
108
+ - A shared, atomic rate limiter.
109
+ - A session manager.
110
+ - An MFA manager and secret protector.
111
+ - A step-up manager.
112
+ - Secure cookie and CSRF configuration.
113
+ - Trusted client IP resolution.
114
+
115
+ The generated API route returns HTTP 503 until the application registers an actual <code>AuthServer</code>.
116
+
117
+ This is intentional. The generator must never silently create an authentication endpoint that appears functional while using unsafe or incomplete security providers.
118
+
119
+ See the [Authentication setup guide](/docs/developer/authentication) for the required configuration.
120
+
121
+ ### Basic React limitation
122
+
123
+ A Basic React project is a browser application. The generator adds the Auth provider and authentication screens, but does not create a server runtime or API route.
124
+
125
+ Host the authentication API in a separate server application and configure the Auth client's base path accordingly.
126
+
127
+ ## Run your application
128
+
129
+ After creation, move into the generated project and start its development server.
130
+
131
+ ```bash
132
+ cd my-awesome-app
133
+ npm run dev
134
+ ```
135
+
136
+ Use the package manager selected during setup. For example, with Bun:
137
+
138
+ ```bash
139
+ cd my-awesome-app
140
+ bun run dev
141
+ ```
142
+
143
+ ## Manual installation
144
+
145
+ Install the UI and theme packages:
146
+
147
+ ```bash
148
+ npm install @puzzle-ui/ui @puzzle-ui/theme
149
+ ```
150
+
151
+ Wrap your application in the theme provider:
152
+
153
+ ```tsx
154
+ import { Theme } from "@puzzle-ui/theme";
155
+ import { Button } from "@puzzle-ui/ui";
156
+
157
+ const App = () => (
158
+ <Theme theme="system">
159
+ <main>
160
+ <h1>Welcome to Puzzle</h1>
161
+ <Button>Get started</Button>
162
+ </main>
163
+ </Theme>
164
+ );
165
+
166
+ export default App;
167
+ ```
168
+
169
+ To add the authentication client and framework integrations:
170
+
171
+ ```bash
172
+ npm install @puzzle-ui/auth @puzzle-ui/fullstack @puzzle-ui/session
173
+ ```
174
+
175
+ See the [Authentication setup guide](/docs/developer/authentication) before exposing authentication routes.
176
+
177
+ ## Compatibility
178
+
179
+ The generated templates target React 19.
180
+
181
+ Framework templates are generated using their official CLI tools. Their generated configuration can change as those tools evolve.
182
+
183
+ Puzzle is under active development and is not ready for production use. Review and test the generated application before using it in a real project.
184
+
185
+ ## Troubleshooting
186
+
187
+ ### The target directory already exists
188
+
189
+ Choose another project name or remove the existing directory yourself before running the CLI again. The CLI intentionally does not overwrite existing projects.
190
+
191
+ ### A framework generator fails
192
+
193
+ The CLI invokes the official framework generator through your selected package manager. Check that the package manager is installed and that your environment can access the package registry.
194
+
195
+ ### Dependency installation fails
196
+
197
+ Run the failed installation command manually from the generated project directory. Check the package manager output for registry, network, or version errors.
198
+
199
+ ### Tailwind CSS is not configured
200
+
201
+ Tailwind is optional. If you skipped it, the generated application still works with Puzzle's own theme and component styling.
202
+
203
+ ### Authentication returns HTTP 503
29
204
 
30
- ## Features
205
+ The generated server bootstrap is intentionally incomplete. Configure your storage adapter, password hasher, rate limiter, session manager, MFA manager, step-up manager, cookies, CSRF policy, and trusted client IP resolver.
31
206
 
32
- - Interactive project setup
33
- - Automatic kebab-case project names
34
- - Framework scaffolding using official CLI tools
35
- - Automatic Puzzle UI installation
36
- - Automatic Puzzle Theme configuration
37
- - React 19 compatibility
207
+ Register the resulting <code>AuthServer</code> with <code>configureAuthServer</code> from the generated server-only module.
38
208
 
39
209
  ## License
40
210
 
package/dist/index.js CHANGED
@@ -5,6 +5,11 @@ import path from "node:path";
5
5
  import { spawn } from "node:child_process";
6
6
  // src/constants.ts
7
7
  const PUZZLE_PACKAGES = ["@puzzle-ui/ui@latest", "@puzzle-ui/theme@latest"];
8
+ const PUZZLE_AUTH_PACKAGES = [
9
+ "@puzzle-ui/auth@latest",
10
+ "@puzzle-ui/fullstack@latest",
11
+ "@puzzle-ui/session@latest"
12
+ ];
8
13
  const FRAMEWORKS = [
9
14
  {
10
15
  value: "react",
@@ -26,8 +31,7 @@ const FRAMEWORKS = [
26
31
  const toKebabCase = (value) => value.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/([A-Z])([A-Z][a-z])/g, "$1-$2").replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase();
27
32
  // src/utils/detect-package-manager.ts
28
33
  const detectPackageManager = (userAgent = process.env.npm_config_user_agent ?? "") => {
29
- if (userAgent.startsWith("bun/")) return "bun";
30
- return "npm";
34
+ return userAgent.match(/(?:^|\s)(bun|pnpm|yarn|npm)\/[^\s]+/)?.[1] ?? "npm";
31
35
  };
32
36
  // src/prompts.ts
33
37
  const getProjectOptions = async () => {
@@ -59,12 +63,21 @@ const getProjectOptions = async () => {
59
63
  p.cancel("Project creation cancelled.");
60
64
  return null;
61
65
  }
66
+ const auth = await p.confirm({
67
+ message: "Would you like to add Puzzle Auth?",
68
+ initialValue: false
69
+ });
70
+ if (p.isCancel(auth)) {
71
+ p.cancel("Project creation cancelled.");
72
+ return null;
73
+ }
62
74
  return {
63
75
  name: directory,
64
76
  directory,
65
77
  framework,
66
78
  packageManager: detectPackageManager(),
67
- tailwind
79
+ tailwind,
80
+ auth
68
81
  };
69
82
  };
70
83
  // src/utils/execute.ts
@@ -85,6 +98,20 @@ const runCommand = (command, args, options = {}) => new Promise((resolve, reject
85
98
  });
86
99
  });
87
100
  // src/frameworks/next.ts
101
+ const getExecutor$1 = (packageManager) => {
102
+ if (packageManager === "bun") return {
103
+ command: "bunx",
104
+ prefix: []
105
+ };
106
+ if (packageManager === "pnpm" || packageManager === "yarn") return {
107
+ command: packageManager,
108
+ prefix: ["dlx"]
109
+ };
110
+ return {
111
+ command: "npx",
112
+ prefix: ["--yes"]
113
+ };
114
+ };
88
115
  const createNextProject = async (directory, packageManager, runner = runCommand, cwd) => {
89
116
  const args = [
90
117
  "create-next-app@latest",
@@ -96,17 +123,26 @@ const createNextProject = async (directory, packageManager, runner = runCommand,
96
123
  "--disable-git",
97
124
  "--no-tailwind",
98
125
  "--yes",
99
- packageManager === "bun" ? "--use-bun" : "--use-npm"
126
+ `--use-${packageManager}`
100
127
  ];
101
- const command = packageManager === "bun" ? "bunx" : "npx";
102
- const commandArgs = packageManager === "bun" ? args : ["--yes", ...args];
103
- if (cwd) {
104
- await runner(command, commandArgs, { cwd });
105
- return;
106
- }
107
- await runner(command, commandArgs);
128
+ const executor = getExecutor$1(packageManager);
129
+ await runner(executor.command, [...executor.prefix, ...args], cwd ? { cwd } : void 0);
108
130
  };
109
131
  // src/frameworks/tanstack.ts
132
+ const getExecutor = (packageManager) => {
133
+ if (packageManager === "bun") return {
134
+ command: "bunx",
135
+ prefix: []
136
+ };
137
+ if (packageManager === "pnpm" || packageManager === "yarn") return {
138
+ command: packageManager,
139
+ prefix: ["dlx"]
140
+ };
141
+ return {
142
+ command: "npx",
143
+ prefix: ["--yes"]
144
+ };
145
+ };
110
146
  const createTanStackProject = async (directory, packageManager, runner = runCommand, cwd) => {
111
147
  const args = [
112
148
  "@tanstack/cli@latest",
@@ -121,13 +157,8 @@ const createTanStackProject = async (directory, packageManager, runner = runComm
121
157
  "--no-git",
122
158
  "--yes"
123
159
  ];
124
- const command = packageManager === "bun" ? "bunx" : "npx";
125
- const commandArgs = packageManager === "bun" ? args : ["--yes", ...args];
126
- if (cwd) {
127
- await runner(command, commandArgs, { cwd });
128
- return;
129
- }
130
- await runner(command, commandArgs);
160
+ const executor = getExecutor(packageManager);
161
+ await runner(executor.command, [...executor.prefix, ...args], cwd ? { cwd } : void 0);
131
162
  };
132
163
  // src/frameworks/react.ts
133
164
  const createReactProject = async (directory, _packageManager, _runner) => {
@@ -246,6 +277,43 @@ const frameworkGenerators = {
246
277
  tanstack: createTanStackProject,
247
278
  react: createReactProject
248
279
  };
280
+ // src/frameworks/configure-framework.ts
281
+ const getTranspiledPackages = (auth) => [
282
+ "@puzzle-ui/ui",
283
+ "@puzzle-ui/theme",
284
+ ...auth ? ["@puzzle-ui/fullstack"] : []
285
+ ];
286
+ const configureNext = async (directory, auth) => {
287
+ const configPath = path.join(directory, "next.config.ts");
288
+ const packages = getTranspiledPackages(auth);
289
+ const config = `import type { NextConfig } from "next";
290
+
291
+ const nextConfig: NextConfig = {
292
+ transpilePackages: ${JSON.stringify(packages, null, 4)},
293
+ };
294
+
295
+ export default nextConfig;
296
+ `;
297
+ await writeFile(configPath, config, "utf8");
298
+ };
299
+ const configureTanStack = async (directory, auth) => {
300
+ const configPath = path.join(directory, "vite.config.ts");
301
+ let config = await readFile(configPath, "utf8");
302
+ const packages = getTranspiledPackages(auth);
303
+ if (!config.includes("noExternal")) config = config.replace(/defineConfig\(\s*\{/, `defineConfig({
304
+ ssr: {
305
+ noExternal: ${JSON.stringify(packages)},
306
+ },`);
307
+ else if (auth && !config.includes("\"@puzzle-ui/fullstack\"")) config = config.replace(/noExternal:\s*\[([^\]]*)\]/, `noExternal: [$1, "@puzzle-ui/fullstack"]`);
308
+ await writeFile(configPath, config, "utf8");
309
+ };
310
+ const configureFramework = async (directory, framework, auth = false) => {
311
+ if (framework === "next") {
312
+ await configureNext(directory, auth);
313
+ return;
314
+ }
315
+ if (framework === "tanstack") await configureTanStack(directory, auth);
316
+ };
249
317
  const themeTemplates = {
250
318
  next: {
251
319
  "src/app/providers.tsx": `"use client";
@@ -399,6 +467,283 @@ const configureTheme = async (directory, framework) => {
399
467
  await writeFile(filePath, content, "utf8");
400
468
  }));
401
469
  };
470
+ // src/auth/templates.ts
471
+ const authServer = `import type { AuthServer } from "@puzzle-ui/fullstack/auth/server";
472
+
473
+ let authServer: AuthServer | null = null;
474
+
475
+ /**
476
+ * Register the server configured by your application.
477
+ *
478
+ * Create the AuthServer with your own storage adapter, password hasher,
479
+ * rate limiter, session manager, MFA manager and CSRF configuration.
480
+ *
481
+ * Never import this module from browser-facing code.
482
+ */
483
+ export const configureAuthServer = (server: AuthServer): void => {
484
+ if (authServer && authServer !== server) {
485
+ throw new Error("Puzzle Auth has already been configured.");
486
+ }
487
+
488
+ authServer = server;
489
+ };
490
+
491
+ /**
492
+ * Returns null until the application has registered its AuthServer.
493
+ */
494
+ export const getAuthServer = (): AuthServer | null => authServer;
495
+ `;
496
+ const authBootstrap = `/**
497
+ * Initialize Puzzle Auth once for this server runtime.
498
+ *
499
+ * Configure your storage adapter and security providers here.
500
+ *
501
+ * Example:
502
+ *
503
+ * configureAuthServer(
504
+ * createAuthServer({
505
+ * auth,
506
+ * mfa,
507
+ * stepUp,
508
+ * sessions,
509
+ * cookie,
510
+ * csrf,
511
+ * resolveClientIp,
512
+ * }),
513
+ * );
514
+ *
515
+ * Do not use development-only or in-memory providers in production.
516
+ */
517
+ const configure = async (): Promise<void> => {
518
+ // TODO: initialize your application-specific AuthServer.
519
+ };
520
+
521
+ let initialization: Promise<void> | null = null;
522
+
523
+ export const initializePuzzleAuth = (): Promise<void> => {
524
+ if (!initialization) {
525
+ initialization = configure().catch((error: unknown) => {
526
+ initialization = null;
527
+ throw error;
528
+ });
529
+ }
530
+
531
+ return initialization;
532
+ };
533
+ `;
534
+ const authUnavailableResponse = `const createAuthUnavailableResponse = (): Response =>
535
+ new Response(
536
+ JSON.stringify({
537
+ error: {
538
+ code: "AUTH_NOT_CONFIGURED",
539
+ message: "Puzzle Auth has not been configured by the application.",
540
+ },
541
+ }),
542
+ {
543
+ status: 503,
544
+ headers: {
545
+ "Content-Type": "application/json; charset=utf-8",
546
+ "Cache-Control": "no-store",
547
+ Pragma: "no-cache",
548
+ },
549
+ },
550
+ );
551
+
552
+ export { createAuthUnavailableResponse };
553
+ `;
554
+ const authTemplates = {
555
+ next: {
556
+ "src/app/providers.tsx": `"use client";
557
+
558
+ import type { ReactNode } from "react";
559
+
560
+ import { Theme } from "@puzzle-ui/theme";
561
+ import { AuthProvider } from "@puzzle-ui/fullstack/auth/client";
562
+
563
+ type ProvidersProps = {
564
+ children: ReactNode;
565
+ };
566
+
567
+ const Providers = ({ children }: ProvidersProps) => (
568
+ <Theme theme="system">
569
+ <AuthProvider options={{ basePath: "/api/auth" }}>
570
+ {children}
571
+ </AuthProvider>
572
+ </Theme>
573
+ );
574
+
575
+ export { Providers };
576
+ `,
577
+ "src/app/sign-in/page.tsx": `"use client";
578
+
579
+ import { AuthExperience } from "@puzzle-ui/fullstack/auth/client";
580
+
581
+ const SignInPage = () => <AuthExperience mode="sign-in" />;
582
+
583
+ export default SignInPage;
584
+ `,
585
+ "src/app/sign-up/page.tsx": `"use client";
586
+
587
+ import { AuthExperience } from "@puzzle-ui/fullstack/auth/client";
588
+
589
+ const SignUpPage = () => <AuthExperience mode="sign-up" />;
590
+
591
+ export default SignUpPage;
592
+ `,
593
+ "src/app/api/auth/[...auth]/route.ts": `import { createNextAuthHandler } from "@puzzle-ui/fullstack/auth/next";
594
+
595
+ import { getAuthServer } from "../../../../lib/auth/server";
596
+ import { initializePuzzleAuth } from "../../../../lib/auth/bootstrap";
597
+ import { createAuthUnavailableResponse } from "../../../../lib/auth/unavailable";
598
+
599
+ const handle = async (request: Request): Promise<Response> => {
600
+ await initializePuzzleAuth();
601
+
602
+ const auth = getAuthServer();
603
+
604
+ if (!auth) {
605
+ return createAuthUnavailableResponse();
606
+ }
607
+
608
+ const handlers = createNextAuthHandler({ auth });
609
+
610
+ return request.method.toUpperCase() === "GET"
611
+ ? handlers.GET(request)
612
+ : handlers.POST(request);
613
+ };
614
+
615
+ export { handle as GET, handle as POST };
616
+ `,
617
+ "src/lib/auth/server.ts": authServer,
618
+ "src/lib/auth/bootstrap.ts": authBootstrap,
619
+ "src/lib/auth/unavailable.ts": authUnavailableResponse
620
+ },
621
+ tanstack: {
622
+ "src/routes/__root.tsx": `import {
623
+ createRootRoute,
624
+ HeadContent,
625
+ Outlet,
626
+ Scripts,
627
+ } from "@tanstack/react-router";
628
+
629
+ import { Theme } from "@puzzle-ui/theme";
630
+ import { AuthProvider } from "@puzzle-ui/fullstack/auth/client";
631
+
632
+ const RootComponent = () => (
633
+ <html lang="en">
634
+ <head>
635
+ <HeadContent />
636
+ </head>
637
+ <body>
638
+ <Theme theme="system">
639
+ <AuthProvider options={{ basePath: "/api/auth" }}>
640
+ <Outlet />
641
+ </AuthProvider>
642
+ </Theme>
643
+ <Scripts />
644
+ </body>
645
+ </html>
646
+ );
647
+
648
+ export const Route = createRootRoute({
649
+ component: RootComponent,
650
+ });
651
+ `,
652
+ "src/routes/sign-in.tsx": `import { createFileRoute } from "@tanstack/react-router";
653
+
654
+ import { AuthExperience } from "@puzzle-ui/fullstack/auth/client";
655
+
656
+ const SignInPage = () => <AuthExperience mode="sign-in" />;
657
+
658
+ export const Route = createFileRoute("/sign-in")({
659
+ component: SignInPage,
660
+ });
661
+ `,
662
+ "src/routes/sign-up.tsx": `import { createFileRoute } from "@tanstack/react-router";
663
+
664
+ import { AuthExperience } from "@puzzle-ui/fullstack/auth/client";
665
+
666
+ const SignUpPage = () => <AuthExperience mode="sign-up" />;
667
+
668
+ export const Route = createFileRoute("/sign-up")({
669
+ component: SignUpPage,
670
+ });
671
+ `,
672
+ "src/routes/api/auth/$.ts": `import { createFileRoute } from "@tanstack/react-router";
673
+
674
+ import { createTanStackAuthHandler } from "@puzzle-ui/fullstack/auth/tanstack";
675
+
676
+ import { getAuthServer } from "../../../lib/auth/server";
677
+ import { initializePuzzleAuth } from "../../../lib/auth/bootstrap";
678
+ import { createAuthUnavailableResponse } from "../../../lib/auth/unavailable";
679
+
680
+ const handle = async (request: Request): Promise<Response> => {
681
+ await initializePuzzleAuth();
682
+
683
+ const auth = getAuthServer();
684
+
685
+ if (!auth) {
686
+ return createAuthUnavailableResponse();
687
+ }
688
+
689
+ return createTanStackAuthHandler({ auth })(request);
690
+ };
691
+
692
+ export const Route = createFileRoute("/api/auth/$")({
693
+ server: {
694
+ handlers: {
695
+ GET: ({ request }) => handle(request),
696
+ POST: ({ request }) => handle(request),
697
+ },
698
+ },
699
+ });
700
+ `,
701
+ "src/lib/auth/server.ts": authServer,
702
+ "src/lib/auth/bootstrap.ts": authBootstrap,
703
+ "src/lib/auth/unavailable.ts": authUnavailableResponse
704
+ },
705
+ react: {
706
+ "src/main.tsx": `import React from "react";
707
+ import ReactDOM from "react-dom/client";
708
+
709
+ import { Theme } from "@puzzle-ui/theme";
710
+ import { AuthProvider } from "@puzzle-ui/fullstack/auth/client";
711
+
712
+ import App from "./App";
713
+
714
+ import "./index.css";
715
+
716
+ ReactDOM.createRoot(
717
+ document.getElementById("root")!,
718
+ ).render(
719
+ <React.StrictMode>
720
+ <Theme theme="system">
721
+ <AuthProvider options={{ basePath: "/api/auth" }}>
722
+ <App />
723
+ </AuthProvider>
724
+ </Theme>
725
+ </React.StrictMode>,
726
+ );
727
+ `,
728
+ "src/auth/sign-in.tsx": `import { AuthExperience } from "@puzzle-ui/fullstack/auth/client";
729
+
730
+ export const SignInPage = () => <AuthExperience mode="sign-in" />;
731
+ `,
732
+ "src/auth/sign-up.tsx": `import { AuthExperience } from "@puzzle-ui/fullstack/auth/client";
733
+
734
+ export const SignUpPage = () => <AuthExperience mode="sign-up" />;
735
+ `
736
+ }
737
+ };
738
+ // src/auth/configure-auth.ts
739
+ const configureAuth = async (directory, framework) => {
740
+ const templates = authTemplates[framework];
741
+ await Promise.all(Object.entries(templates).map(async ([relativePath, content]) => {
742
+ const filePath = path.join(directory, relativePath);
743
+ await mkdir(path.dirname(filePath), { recursive: true });
744
+ await writeFile(filePath, content, "utf8");
745
+ }));
746
+ };
402
747
  // src/utils/validate-project.ts
403
748
  const validateProjectDirectory = async (directory, cwd = process.cwd()) => {
404
749
  const root = path.resolve(cwd);
@@ -501,30 +846,31 @@ const getTailwindPackages = (framework) => {
501
846
  ];
502
847
  return ["tailwindcss@latest", "@tailwindcss/vite@latest"];
503
848
  };
504
- const installTailwind = async ({ directory, framework, packageManager, runner }) => {
505
- const packages = getTailwindPackages(framework);
506
- if (packageManager === "bun") {
507
- await runner("bun", [
508
- "add",
509
- "-d",
510
- ...packages
511
- ], { cwd: directory });
512
- return;
513
- }
514
- await runner("npm", [
849
+ const getInstallArguments = (packageManager, packages) => {
850
+ if (packageManager === "npm") return [
515
851
  "install",
516
852
  "--save-dev",
517
853
  ...packages
518
- ], { cwd: directory });
854
+ ];
855
+ if (packageManager === "yarn") return [
856
+ "add",
857
+ "--dev",
858
+ ...packages
859
+ ];
860
+ return [
861
+ "add",
862
+ "-D",
863
+ ...packages
864
+ ];
865
+ };
866
+ const installTailwind = async ({ directory, framework, packageManager, runner }) => {
867
+ const packages = getTailwindPackages(framework);
868
+ await runner(packageManager, getInstallArguments(packageManager, packages), { cwd: directory });
519
869
  };
520
870
  // src/create-project.ts
521
- const installDependencies = async (directory, packageManager, runner) => {
522
- const packages = [...PUZZLE_PACKAGES];
523
- if (packageManager === "bun") {
524
- await runner("bun", ["add", ...packages], { cwd: directory });
525
- return;
526
- }
527
- await runner("npm", ["install", ...packages], { cwd: directory });
871
+ const installDependencies = async (directory, packageManager, auth, runner) => {
872
+ const packages = [...PUZZLE_PACKAGES, ...auth ? PUZZLE_AUTH_PACKAGES : []];
873
+ await runner(packageManager, packageManager === "npm" ? ["install", ...packages] : ["add", ...packages], { cwd: directory });
528
874
  };
529
875
  const configureProjectName = async (directory, projectName) => {
530
876
  const packageJsonPath = path.join(directory, "package.json");
@@ -551,10 +897,18 @@ const createProject = async (options, { cwd = process.cwd(), runner = runCommand
551
897
  if (options.framework === "react") await frameworkGenerators.react(targetDirectory, options.packageManager, runner);
552
898
  else await frameworkGenerators[options.framework](projectName, options.packageManager, runner, projectParent);
553
899
  finishStep("Framework generated");
900
+ startStep("Configuring framework");
901
+ await configureFramework(targetDirectory, options.framework, options.auth);
902
+ finishStep("Framework configured");
554
903
  startStep("Configuring Puzzle theme");
555
904
  await configureTheme(targetDirectory, options.framework);
556
905
  await configureProjectName(targetDirectory, projectName);
557
906
  finishStep("Puzzle theme configured");
907
+ if (options.auth) {
908
+ startStep("Configuring Puzzle Auth");
909
+ await configureAuth(targetDirectory, options.framework);
910
+ finishStep("Puzzle Auth configured");
911
+ }
558
912
  if (options.tailwind) {
559
913
  startStep("Configuring Tailwind CSS");
560
914
  await configureTailwind(targetDirectory, options.framework);
@@ -569,14 +923,14 @@ const createProject = async (options, { cwd = process.cwd(), runner = runCommand
569
923
  finishStep("Tailwind CSS installed");
570
924
  }
571
925
  startStep("Installing Puzzle");
572
- await installDependencies(targetDirectory, options.packageManager, runner);
573
- finishStep("Puzzle installed");
926
+ await installDependencies(targetDirectory, options.packageManager, options.auth, runner);
927
+ finishStep(options.auth ? "Puzzle and Auth installed" : "Puzzle installed");
574
928
  } catch (error) {
575
929
  if (spinnerActive) spinner.error("Project creation failed");
576
930
  throw error;
577
931
  }
578
932
  p.log.success(`Project "${projectName}" created successfully.`);
579
- p.outro(`Next steps:\n\n cd ${path.relative(process.cwd(), targetDirectory) || "."}\n ${options.packageManager} run dev`);
933
+ p.outro(`Next steps:\n\n cd ${path.relative(cwd, targetDirectory) || "."}\n ${options.packageManager} run dev`);
580
934
  };
581
935
  // src/index.ts
582
936
  const main = async () => {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/constants.ts","../src/utils/kebab-case.ts","../src/utils/detect-package-manager.ts","../src/prompts.ts","../src/utils/execute.ts","../src/frameworks/next.ts","../src/frameworks/tanstack.ts","../src/frameworks/react.ts","../src/frameworks/index.ts","../src/theme/templates.ts","../src/theme/configure-theme.ts","../src/utils/validate-project.ts","../src/tailwind/configure-tailwind.ts","../src/tailwind/install-tailwind.ts","../src/create-project.ts","../src/index.ts"],"sourcesContent":["import type { Framework } from \"./types\";\n\nexport const PACKAGE_NAME = \"@puzzle-ui/create\";\n\nexport const PUZZLE_PACKAGES = [\n \"@puzzle-ui/ui@latest\",\n \"@puzzle-ui/theme@latest\",\n] as const;\n\nexport const FRAMEWORKS: {\n value: Framework;\n label: string;\n hint: string;\n}[] = [\n {\n value: \"react\",\n label: \"Basic React Project\",\n hint: \"React + Vite + TypeScript\",\n },\n {\n value: \"tanstack\",\n label: \"TanStack Start\",\n hint: \"Full-stack React framework\",\n },\n {\n value: \"next\",\n label: \"Next.js\",\n hint: \"React framework with App Router\",\n },\n];\n","const toKebabCase = (value: string): string =>\n value\n .normalize(\"NFKD\")\n .replace(/[\\u0300-\\u036f]/g, \"\")\n .replace(/([a-z0-9])([A-Z])/g, \"$1-$2\")\n .replace(/([A-Z])([A-Z][a-z])/g, \"$1-$2\")\n .replace(/[^a-zA-Z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .toLowerCase();\n\nexport { toKebabCase };\n","import type { PackageManager } from \"../types\";\n\nconst detectPackageManager = (\n userAgent = process.env.npm_config_user_agent ?? \"\",\n): PackageManager => {\n if (userAgent.startsWith(\"bun/\")) {\n return \"bun\";\n }\n\n return \"npm\";\n};\n\nexport { detectPackageManager };\n","import * as p from \"@clack/prompts\";\n\nimport { FRAMEWORKS } from \"./constants\";\n\nimport type { Framework, ProjectOptions } from \"./types\";\n\nimport { toKebabCase } from \"./utils/kebab-case\";\n\nimport { detectPackageManager } from \"./utils/detect-package-manager\";\n\nconst getProjectOptions = async (): Promise<ProjectOptions | null> => {\n p.intro(\"Create a Puzzle application\");\n\n const name = await p.text({\n message: \"What is the name of your project?\",\n placeholder: \"my-awesome-app\",\n validate: (value) => {\n if (!value?.trim()) {\n return \"Project name is required.\";\n }\n\n if (!toKebabCase(value)) {\n return \"Please enter a valid project name.\";\n }\n },\n });\n\n if (p.isCancel(name)) {\n return null;\n }\n\n const directory = toKebabCase(name);\n\n const framework = await p.select({\n message: \"Which framework would you like to use?\",\n options: FRAMEWORKS.map((item) => ({\n value: item.value,\n label: item.label,\n hint: item.hint,\n })),\n });\n\n if (p.isCancel(framework)) {\n return null;\n }\n\n const tailwind = await p.confirm({\n message: \"Would you like to install Tailwind CSS?\",\n initialValue: true,\n });\n\n if (p.isCancel(tailwind)) {\n p.cancel(\"Project creation cancelled.\");\n return null;\n }\n\n return {\n name: directory,\n directory,\n framework: framework as Framework,\n packageManager: detectPackageManager(),\n tailwind,\n };\n};\n\nexport { getProjectOptions };\n","import { spawn } from \"node:child_process\";\n\nimport type { CommandRunner } from \"../types\";\n\nconst runCommand: CommandRunner = (command, args, options = {}) =>\n new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n cwd: options.cwd ?? process.cwd(),\n stdio: options.stdio ?? \"inherit\",\n shell: false,\n env: process.env,\n });\n\n child.once(\"error\", reject);\n\n child.once(\"close\", (code, signal) => {\n if (code === 0) {\n resolve();\n return;\n }\n\n reject(\n new Error(\n signal\n ? `${command} terminated with signal ${signal}`\n : `${command} exited with code ${code ?? \"unknown\"}`,\n ),\n );\n });\n });\n\nexport { runCommand };\n","import type { FrameworkGenerator } from \"../types\";\n\nimport { runCommand } from \"../utils/execute\";\n\nconst createNextProject: FrameworkGenerator = async (\n directory,\n packageManager,\n runner = runCommand,\n cwd,\n) => {\n const args = [\n \"create-next-app@latest\",\n directory,\n \"--ts\",\n \"--app\",\n \"--src-dir\",\n \"--skip-install\",\n \"--disable-git\",\n \"--no-tailwind\",\n \"--yes\",\n packageManager === \"bun\" ? \"--use-bun\" : \"--use-npm\",\n ];\n\n const command = packageManager === \"bun\" ? \"bunx\" : \"npx\";\n const commandArgs = packageManager === \"bun\" ? args : [\"--yes\", ...args];\n\n if (cwd) {\n await runner(command, commandArgs, { cwd });\n return;\n }\n\n await runner(command, commandArgs);\n};\n\nexport { createNextProject };\n","import type { FrameworkGenerator } from \"../types\";\n\nimport { runCommand } from \"../utils/execute\";\n\nconst createTanStackProject: FrameworkGenerator = async (\n directory,\n packageManager,\n runner = runCommand,\n cwd,\n) => {\n const args = [\n \"@tanstack/cli@latest\",\n \"create\",\n directory,\n \"--framework\",\n \"React\",\n \"--package-manager\",\n packageManager,\n \"--blank\",\n \"--no-install\",\n \"--no-git\",\n \"--yes\",\n ];\n\n const command = packageManager === \"bun\" ? \"bunx\" : \"npx\";\n const commandArgs = packageManager === \"bun\" ? args : [\"--yes\", ...args];\n\n if (cwd) {\n await runner(command, commandArgs, { cwd });\n return;\n }\n\n await runner(command, commandArgs);\n};\n\nexport { createTanStackProject };\n","import { mkdir, writeFile } from \"node:fs/promises\";\n\nimport path from \"node:path\";\n\nimport type { FrameworkGenerator } from \"../types\";\n\nconst createReactProject: FrameworkGenerator = async (\n directory,\n _packageManager,\n _runner,\n) => {\n await mkdir(path.join(directory, \"src\"), {\n recursive: true,\n });\n\n const packageJson = {\n name: path.basename(directory),\n private: true,\n version: \"0.0.0\",\n type: \"module\",\n scripts: {\n dev: \"vite\",\n build: \"tsc --noEmit -p tsconfig.app.json && vite build\",\n preview: \"vite preview\",\n },\n dependencies: {\n react: \"^19.0.0\",\n \"react-dom\": \"^19.0.0\",\n },\n devDependencies: {\n \"@types/node\": \"latest\",\n \"@types/react\": \"^19.0.0\",\n \"@types/react-dom\": \"^19.0.0\",\n \"@vitejs/plugin-react\": \"latest\",\n typescript: \"latest\",\n vite: \"latest\",\n },\n };\n\n const files: Record<string, string> = {\n \"package.json\": JSON.stringify(packageJson, null, 2),\n\n \"index.html\": `<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>Puzzle App</title>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\" src=\"/src/main.tsx\"></script>\n </body>\n</html>`,\n\n \"tsconfig.json\": JSON.stringify(\n {\n files: [],\n references: [\n { path: \"./tsconfig.app.json\" },\n { path: \"./tsconfig.node.json\" },\n ],\n },\n null,\n 2,\n ),\n\n \"tsconfig.app.json\": JSON.stringify(\n {\n compilerOptions: {\n tsBuildInfoFile: \"./node_modules/.tmp/tsconfig.app.tsbuildinfo\",\n target: \"ES2022\",\n useDefineForClassFields: true,\n lib: [\"ES2022\", \"DOM\", \"DOM.Iterable\"],\n module: \"ESNext\",\n skipLibCheck: true,\n moduleResolution: \"bundler\",\n allowImportingTsExtensions: true,\n verbatimModuleSyntax: true,\n moduleDetection: \"force\",\n noEmit: true,\n jsx: \"react-jsx\",\n strict: true,\n noUnusedLocals: true,\n noUnusedParameters: true,\n noFallthroughCasesInSwitch: true,\n types: [\"vite/client\"],\n },\n include: [\"src\"],\n },\n null,\n 2,\n ),\n\n \"tsconfig.node.json\": JSON.stringify(\n {\n compilerOptions: {\n tsBuildInfoFile: \"./node_modules/.tmp/tsconfig.node.tsbuildinfo\",\n target: \"ES2023\",\n lib: [\"ES2023\"],\n module: \"ESNext\",\n skipLibCheck: true,\n moduleResolution: \"bundler\",\n allowImportingTsExtensions: true,\n verbatimModuleSyntax: true,\n moduleDetection: \"force\",\n noEmit: true,\n strict: true,\n },\n include: [\"vite.config.ts\"],\n },\n null,\n 2,\n ),\n\n \"vite.config.ts\": `import { defineConfig } from \"vite\";\nimport react from \"@vitejs/plugin-react\";\n\nexport default defineConfig({\n plugins: [react()],\n});`,\n\n \"src/main.tsx\": \"\",\n \"src/App.tsx\": \"\",\n \"src/index.css\": `* {\n box-sizing: border-box;\n}\n\nhtml,\nbody,\n#root {\n min-height: 100%;\n}\n\nbody {\n margin: 0;\n font-family: var(--puzzle-font-family-body, sans-serif);\n}`,\n };\n\n await Promise.all(\n Object.entries(files).map(([file, content]) =>\n writeFile(path.join(directory, file), content, \"utf8\"),\n ),\n );\n};\n\nexport { createReactProject };\n","import { createNextProject } from \"./next\";\nimport { createTanStackProject } from \"./tanstack\";\nimport { createReactProject } from \"./react\";\n\nimport type { Framework, FrameworkGenerator } from \"../types\";\n\nconst frameworkGenerators: Record<Framework, FrameworkGenerator> = {\n next: createNextProject,\n tanstack: createTanStackProject,\n react: createReactProject,\n};\n\nexport {\n createNextProject,\n createTanStackProject,\n createReactProject,\n frameworkGenerators,\n};\n","const nextProviders = `\"use client\";\n\nimport type { ReactNode } from \"react\";\n\nimport { Theme } from \"@puzzle-ui/theme\";\n\ntype ProvidersProps = {\n children: ReactNode;\n};\n\nconst Providers = ({ children }: ProvidersProps) => (\n <Theme theme=\"system\">\n {children}\n </Theme>\n);\n\nexport { Providers };\n`;\n\nconst nextLayout = `import \"./globals.css\";\n\nimport type { ReactNode } from \"react\";\n\nimport { Providers } from \"./providers\";\n\ntype RootLayoutProps = {\n children: ReactNode;\n};\n\nconst RootLayout = ({ children }: RootLayoutProps) => (\n <html lang=\"en\">\n <body>\n <Providers>\n {children}\n </Providers>\n </body>\n </html>\n);\n\nexport default RootLayout;\n`;\n\nconst nextPage = `\"use client\";\nimport { Button } from \"@puzzle-ui/ui\";\n\nconst HomePage = () => (\n <main style={{ padding: \"2rem\" }}>\n <h1>Welcome to Puzzle</h1>\n <p>Your new Puzzle application is ready.</p>\n\n <Button onClick={() => console.log(\"Hello, Puzzle!\")}>\n Get started\n </Button>\n </main>\n);\n\nexport default HomePage;\n`;\n\nconst tanstackRootRoute = `import {\n createRootRoute,\n HeadContent,\n Outlet,\n Scripts,\n} from \"@tanstack/react-router\";\n\nimport { Theme } from \"@puzzle-ui/theme\";\n\nconst RootComponent = () => (\n <html lang=\"en\">\n <head>\n <HeadContent />\n </head>\n <body>\n <Theme theme=\"system\">\n <Outlet />\n </Theme>\n <Scripts />\n </body>\n </html>\n);\n\nexport const Route = createRootRoute({\n component: RootComponent,\n});\n`;\n\nconst tanstackIndexRoute = `import { createFileRoute } from \"@tanstack/react-router\";\n\nimport { Button } from \"@puzzle-ui/ui\";\n\nconst HomePage = () => (\n <main style={{ padding: \"2rem\" }}>\n <h1>Welcome to Puzzle</h1>\n <p>Your new Puzzle application is ready.</p>\n\n <Button onClick={() => console.log(\"Hello, Puzzle!\")}>\n Get started\n </Button>\n </main>\n);\n\nexport const Route = createFileRoute(\"/\")({\n component: HomePage,\n});\n`;\n\nconst reactMain = `import React from \"react\";\nimport ReactDOM from \"react-dom/client\";\n\nimport { Theme } from \"@puzzle-ui/theme\";\n\nimport App from \"./App\";\n\nimport \"./index.css\";\n\nReactDOM.createRoot(\n document.getElementById(\"root\")!,\n).render(\n <React.StrictMode>\n <Theme theme=\"system\">\n <App />\n </Theme>\n </React.StrictMode>,\n);\n`;\n\nconst reactApp = `import { Button } from \"@puzzle-ui/ui\";\n\nconst App = () => (\n <main style={{ padding: \"2rem\" }}>\n <h1>Welcome to Puzzle</h1>\n <p>Your new Puzzle application is ready.</p>\n\n <Button onClick={() => console.log(\"Hello, Puzzle!\")}>\n Get started\n </Button>\n </main>\n);\n\nexport default App;\n`;\n\nconst themeTemplates = {\n next: {\n \"src/app/providers.tsx\": nextProviders,\n \"src/app/layout.tsx\": nextLayout,\n \"src/app/page.tsx\": nextPage,\n },\n tanstack: {\n \"src/routes/__root.tsx\": tanstackRootRoute,\n \"src/routes/index.tsx\": tanstackIndexRoute,\n },\n react: {\n \"src/main.tsx\": reactMain,\n \"src/App.tsx\": reactApp,\n },\n} as const;\n\nexport {\n nextProviders,\n nextLayout,\n nextPage,\n tanstackRootRoute,\n tanstackIndexRoute,\n reactMain,\n reactApp,\n themeTemplates,\n};\n","import { mkdir, writeFile } from \"node:fs/promises\";\n\nimport path from \"node:path\";\n\nimport type { Framework } from \"../types\";\n\nimport { themeTemplates } from \"./templates\";\n\nconst configureTheme = async (\n directory: string,\n framework: Framework,\n): Promise<void> => {\n const templates = themeTemplates[framework];\n\n await Promise.all(\n Object.entries(templates).map(async ([relativePath, content]) => {\n const filePath = path.join(directory, relativePath);\n\n await mkdir(path.dirname(filePath), {\n recursive: true,\n });\n\n await writeFile(filePath, content, \"utf8\");\n }),\n );\n};\n\nexport { configureTheme };\n","import { access } from \"node:fs/promises\";\n\nimport path from \"node:path\";\n\nconst validateProjectDirectory = async (\n directory: string,\n cwd = process.cwd(),\n): Promise<string> => {\n const root = path.resolve(cwd);\n const target = path.resolve(root, directory);\n\n if (target === root || !target.startsWith(`${root}${path.sep}`)) {\n throw new Error(\"Invalid project directory.\");\n }\n\n try {\n await access(target);\n\n throw new Error(\n `The directory \"${directory}\" already exists. Choose another name.`,\n );\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"already exists\")) {\n throw error;\n }\n\n if (\n error &&\n typeof error === \"object\" &&\n \"code\" in error &&\n error.code === \"ENOENT\"\n ) {\n return target;\n }\n\n throw error;\n }\n};\n\nexport { validateProjectDirectory };\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\n\nimport path from \"node:path\";\n\nimport type { Framework } from \"../types\";\n\nconst readIfExists = async (filePath: string) => {\n try {\n return await readFile(filePath, \"utf8\");\n } catch {\n return null;\n }\n};\n\nconst writeIfMissingImport = async (\n filePath: string,\n importStatement: string,\n) => {\n const current = await readIfExists(filePath);\n\n if (current === null) {\n await mkdir(path.dirname(filePath), {\n recursive: true,\n });\n\n await writeFile(filePath, `${importStatement}\\n`, \"utf8\");\n\n return;\n }\n\n if (current.includes(importStatement)) {\n return;\n }\n\n await writeFile(filePath, `${importStatement}\\n\\n${current}`, \"utf8\");\n};\n\nconst prependCssImport = async (filePath: string) => {\n const importStatement = '@import \"tailwindcss\";';\n const current = await readIfExists(filePath);\n\n if (current === null) {\n await mkdir(path.dirname(filePath), {\n recursive: true,\n });\n\n await writeFile(filePath, `${importStatement}\\n`, \"utf8\");\n\n return;\n }\n\n if (current.includes(importStatement)) {\n return;\n }\n\n await writeFile(filePath, `${importStatement}\\n\\n${current}`, \"utf8\");\n};\n\nconst configureNextTailwind = async (directory: string) => {\n const cssPath = path.join(directory, \"src\", \"app\", \"globals.css\");\n\n await prependCssImport(cssPath);\n\n const postcssConfigPath = path.join(directory, \"postcss.config.mjs\");\n\n await writeFile(\n postcssConfigPath,\n `const config = {\n plugins: {\n \"@tailwindcss/postcss\": {},\n },\n};\n\nexport default config;\n`,\n \"utf8\",\n );\n};\n\nconst findTanStackCssPath = async (directory: string) => {\n const rootRoutePath = path.join(directory, \"src\", \"routes\", \"__root.tsx\");\n\n const rootRoute = await readFile(rootRoutePath, \"utf8\");\n\n const cssImportPattern =\n /import\\s+(?:[\\w{}\\s,*]+\\s+from\\s+)?[\"']([^\"']+\\.css(?:\\?url)?)[\"']/g;\n\n const matches = [...rootRoute.matchAll(cssImportPattern)];\n\n for (const match of matches) {\n const importedPath = match[1];\n\n if (!importedPath?.startsWith(\".\")) {\n continue;\n }\n\n const cleanPath = importedPath.replace(/\\?[^/]*$/, \"\");\n\n return path.resolve(path.dirname(rootRoutePath), cleanPath);\n }\n\n // Default stylesheet location used by TanStack Start templates.\n return path.join(directory, \"src\", \"styles.css\");\n};\n\nconst configureTanStackTailwind = async (directory: string) => {\n const cssPath = await findTanStackCssPath(directory);\n\n await prependCssImport(cssPath);\n\n const rootRoutePath = path.join(directory, \"src\", \"routes\", \"__root.tsx\");\n\n const rootRoute = await readFile(rootRoutePath, \"utf8\");\n\n if (!rootRoute.includes(\".css\")) {\n await writeFile(\n rootRoutePath,\n `import \"../styles.css\";\\n${rootRoute}`,\n \"utf8\",\n );\n }\n\n const viteConfigPath = path.join(directory, \"vite.config.ts\");\n\n let viteConfig = await readFile(viteConfigPath, \"utf8\");\n\n if (!viteConfig.includes(\"@tailwindcss/vite\")) {\n viteConfig = `import tailwindcss from \"@tailwindcss/vite\";\\n` + viteConfig;\n }\n\n if (!viteConfig.includes(\"tailwindcss()\")) {\n viteConfig = viteConfig.replace(\n /plugins:\\s*\\[/,\n \"plugins: [\\n tailwindcss(),\",\n );\n }\n\n if (!viteConfig.includes(\"noExternal\")) {\n viteConfig = viteConfig.replace(\n /defineConfig\\(\\s*\\{/,\n `defineConfig({\n ssr: {\n noExternal: [\"@puzzle-ui/ui\", \"@puzzle-ui/theme\"],\n },`,\n );\n }\n\n await writeFile(viteConfigPath, viteConfig, \"utf8\");\n};\n\nconst configureReactTailwind = async (directory: string) => {\n const cssPath = path.join(directory, \"src\", \"index.css\");\n\n await prependCssImport(cssPath);\n\n const viteConfigPath = path.join(directory, \"vite.config.ts\");\n\n let viteConfig = await readFile(viteConfigPath, \"utf8\");\n\n if (!viteConfig.includes(\"@tailwindcss/vite\")) {\n viteConfig = `import tailwindcss from \"@tailwindcss/vite\";\\n` + viteConfig;\n }\n\n if (!viteConfig.includes(\"tailwindcss()\")) {\n viteConfig = viteConfig.replace(\n /plugins:\\s*\\[/,\n \"plugins: [\\n tailwindcss(),\",\n );\n }\n\n await writeFile(viteConfigPath, viteConfig, \"utf8\");\n};\n\nconst configureTailwind = async (directory: string, framework: Framework) => {\n if (framework === \"next\") {\n await configureNextTailwind(directory);\n return;\n }\n\n if (framework === \"tanstack\") {\n await configureTanStackTailwind(directory);\n return;\n }\n\n await configureReactTailwind(directory);\n};\n\nexport { configureTailwind };\n","import type { CommandRunner, Framework, PackageManager } from \"../types\";\n\nconst getTailwindPackages = (framework: Framework) => {\n if (framework === \"next\") {\n return [\n \"tailwindcss@latest\",\n \"@tailwindcss/postcss@latest\",\n \"postcss@latest\",\n ];\n }\n\n return [\"tailwindcss@latest\", \"@tailwindcss/vite@latest\"];\n};\n\nconst installTailwind = async ({\n directory,\n framework,\n packageManager,\n runner,\n}: {\n directory: string;\n framework: Framework;\n packageManager: PackageManager;\n runner: CommandRunner;\n}) => {\n const packages = getTailwindPackages(framework);\n\n if (packageManager === \"bun\") {\n await runner(\"bun\", [\"add\", \"-d\", ...packages], { cwd: directory });\n\n return;\n }\n\n await runner(\"npm\", [\"install\", \"--save-dev\", ...packages], {\n cwd: directory,\n });\n};\n\nexport { installTailwind };\n","import { readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport * as p from \"@clack/prompts\";\n\nimport type { CommandRunner, ProjectOptions } from \"./types\";\nimport { frameworkGenerators } from \"./frameworks\";\nimport { configureTheme } from \"./theme/configure-theme\";\nimport { runCommand } from \"./utils/execute\";\nimport { validateProjectDirectory } from \"./utils/validate-project\";\nimport { PUZZLE_PACKAGES } from \"./constants\";\nimport { configureTailwind } from \"./tailwind/configure-tailwind\";\nimport { installTailwind } from \"./tailwind/install-tailwind\";\n\ntype CreateProjectContext = {\n /** Directory the project directory is resolved from. Defaults to `process.cwd()`. */\n cwd?: string;\n /** Runs external commands. Defaults to spawning a child process. */\n runner?: CommandRunner;\n};\n\nconst installDependencies = async (\n directory: string,\n packageManager: ProjectOptions[\"packageManager\"],\n runner: CommandRunner,\n) => {\n const packages = [...PUZZLE_PACKAGES];\n\n if (packageManager === \"bun\") {\n await runner(\"bun\", [\"add\", ...packages], { cwd: directory });\n return;\n }\n\n await runner(\"npm\", [\"install\", ...packages], { cwd: directory });\n};\n\nconst configureProjectName = async (directory: string, projectName: string) => {\n const packageJsonPath = path.join(directory, \"package.json\");\n\n const packageJson = JSON.parse(await readFile(packageJsonPath, \"utf8\")) as {\n name?: string;\n [key: string]: unknown;\n };\n\n packageJson.name = projectName;\n\n await writeFile(\n packageJsonPath,\n `${JSON.stringify(packageJson, null, 2)}\\n`,\n \"utf8\",\n );\n};\n\nconst createProject = async (\n options: ProjectOptions,\n { cwd = process.cwd(), runner = runCommand }: CreateProjectContext = {},\n) => {\n // Validate before starting the spinner, so nothing is generated or reported\n // as a failed step when the target directory cannot be used.\n const targetDirectory = await validateProjectDirectory(\n options.directory,\n cwd,\n );\n\n const projectName = path.basename(targetDirectory);\n const projectParent = path.dirname(targetDirectory);\n\n const spinner = p.spinner();\n let spinnerActive = false;\n\n const startStep = (message: string) => {\n spinner.start(message);\n spinnerActive = true;\n };\n\n const finishStep = (message: string) => {\n spinner.stop(message);\n spinnerActive = false;\n };\n\n try {\n startStep(\"Generating framework\");\n\n if (options.framework === \"react\") {\n // The Basic React generator writes directly into its target directory.\n await frameworkGenerators.react(\n targetDirectory,\n options.packageManager,\n runner,\n );\n } else {\n // Next.js and TanStack CLI create their own project directory.\n await frameworkGenerators[options.framework](\n projectName,\n options.packageManager,\n runner,\n projectParent,\n );\n }\n\n finishStep(\"Framework generated\");\n\n startStep(\"Configuring Puzzle theme\");\n await configureTheme(targetDirectory, options.framework);\n await configureProjectName(targetDirectory, projectName);\n finishStep(\"Puzzle theme configured\");\n\n if (options.tailwind) {\n startStep(\"Configuring Tailwind CSS\");\n await configureTailwind(targetDirectory, options.framework);\n finishStep(\"Tailwind CSS configured\");\n\n startStep(\"Installing Tailwind CSS\");\n await installTailwind({\n directory: targetDirectory,\n framework: options.framework,\n packageManager: options.packageManager,\n runner,\n });\n finishStep(\"Tailwind CSS installed\");\n }\n\n startStep(\"Installing Puzzle\");\n await installDependencies(targetDirectory, options.packageManager, runner);\n finishStep(\"Puzzle installed\");\n } catch (error) {\n if (spinnerActive) {\n spinner.error(\"Project creation failed\");\n }\n\n throw error;\n }\n\n p.log.success(`Project \"${projectName}\" created successfully.`);\n\n p.outro(\n `Next steps:\\n\\n cd ${path.relative(process.cwd(), targetDirectory) || \".\"}\\n ${options.packageManager} run dev`,\n );\n};\n\nexport { createProject, type CreateProjectContext };\n","#!/usr/bin/env node\n\nimport * as p from \"@clack/prompts\";\n\nimport { getProjectOptions } from \"./prompts\";\n\nimport { createProject } from \"./create-project\";\n\nconst main = async (): Promise<void> => {\n const options = await getProjectOptions();\n\n if (!options) {\n p.cancel(\"Project creation cancelled.\");\n return;\n }\n\n await createProject(options);\n};\n\nmain().catch((error: unknown) => {\n p.log.error(error instanceof Error ? error.message : String(error));\n\n process.exitCode = 1;\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["getExecutor"],"sources":["../src/constants.ts","../src/utils/kebab-case.ts","../src/utils/detect-package-manager.ts","../src/prompts.ts","../src/utils/execute.ts","../src/frameworks/next.ts","../src/frameworks/tanstack.ts","../src/frameworks/react.ts","../src/frameworks/index.ts","../src/frameworks/configure-framework.ts","../src/theme/templates.ts","../src/theme/configure-theme.ts","../src/auth/templates.ts","../src/auth/configure-auth.ts","../src/utils/validate-project.ts","../src/tailwind/configure-tailwind.ts","../src/tailwind/install-tailwind.ts","../src/create-project.ts","../src/index.ts"],"sourcesContent":["import type { Framework } from \"./types\";\n\nexport const PACKAGE_NAME = \"@puzzle-ui/create\";\n\nexport const PUZZLE_PACKAGES = [\n \"@puzzle-ui/ui@latest\",\n \"@puzzle-ui/theme@latest\",\n] as const;\n\nexport const PUZZLE_AUTH_PACKAGES = [\n \"@puzzle-ui/auth@latest\",\n \"@puzzle-ui/fullstack@latest\",\n \"@puzzle-ui/session@latest\",\n] as const;\n\nexport const FRAMEWORKS: {\n value: Framework;\n label: string;\n hint: string;\n}[] = [\n {\n value: \"react\",\n label: \"Basic React Project\",\n hint: \"React + Vite + TypeScript\",\n },\n {\n value: \"tanstack\",\n label: \"TanStack Start\",\n hint: \"Full-stack React framework\",\n },\n {\n value: \"next\",\n label: \"Next.js\",\n hint: \"React framework with App Router\",\n },\n];\n","const toKebabCase = (value: string): string =>\n value\n .normalize(\"NFKD\")\n .replace(/[\\u0300-\\u036f]/g, \"\")\n .replace(/([a-z0-9])([A-Z])/g, \"$1-$2\")\n .replace(/([A-Z])([A-Z][a-z])/g, \"$1-$2\")\n .replace(/[^a-zA-Z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .toLowerCase();\n\nexport { toKebabCase };\n","import type { PackageManager } from \"../types\";\n\nconst detectPackageManager = (\n userAgent = process.env.npm_config_user_agent ?? \"\",\n): PackageManager => {\n const match = userAgent.match(/(?:^|\\s)(bun|pnpm|yarn|npm)\\/[^\\s]+/);\n\n return (match?.[1] as PackageManager | undefined) ?? \"npm\";\n};\n\nexport { detectPackageManager };\n","import * as p from \"@clack/prompts\";\n\nimport { FRAMEWORKS } from \"./constants\";\n\nimport type { Framework, ProjectOptions } from \"./types\";\n\nimport { toKebabCase } from \"./utils/kebab-case\";\n\nimport { detectPackageManager } from \"./utils/detect-package-manager\";\n\nconst getProjectOptions = async (): Promise<ProjectOptions | null> => {\n p.intro(\"Create a Puzzle application\");\n\n const name = await p.text({\n message: \"What is the name of your project?\",\n placeholder: \"my-awesome-app\",\n validate: (value) => {\n if (!value?.trim()) {\n return \"Project name is required.\";\n }\n\n if (!toKebabCase(value)) {\n return \"Please enter a valid project name.\";\n }\n },\n });\n\n if (p.isCancel(name)) {\n return null;\n }\n\n const directory = toKebabCase(name);\n\n const framework = await p.select({\n message: \"Which framework would you like to use?\",\n options: FRAMEWORKS.map((item) => ({\n value: item.value,\n label: item.label,\n hint: item.hint,\n })),\n });\n\n if (p.isCancel(framework)) {\n return null;\n }\n\n const tailwind = await p.confirm({\n message: \"Would you like to install Tailwind CSS?\",\n initialValue: true,\n });\n\n if (p.isCancel(tailwind)) {\n p.cancel(\"Project creation cancelled.\");\n return null;\n }\n\n const auth = await p.confirm({\n message: \"Would you like to add Puzzle Auth?\",\n initialValue: false,\n });\n\n if (p.isCancel(auth)) {\n p.cancel(\"Project creation cancelled.\");\n return null;\n }\n\n return {\n name: directory,\n directory,\n framework: framework as Framework,\n packageManager: detectPackageManager(),\n tailwind,\n auth,\n };\n};\n\nexport { getProjectOptions };\n","import { spawn } from \"node:child_process\";\n\nimport type { CommandRunner } from \"../types\";\n\nconst runCommand: CommandRunner = (command, args, options = {}) =>\n new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n cwd: options.cwd ?? process.cwd(),\n stdio: options.stdio ?? \"inherit\",\n shell: false,\n env: process.env,\n });\n\n child.once(\"error\", reject);\n\n child.once(\"close\", (code, signal) => {\n if (code === 0) {\n resolve();\n return;\n }\n\n reject(\n new Error(\n signal\n ? `${command} terminated with signal ${signal}`\n : `${command} exited with code ${code ?? \"unknown\"}`,\n ),\n );\n });\n });\n\nexport { runCommand };\n","import type { FrameworkGenerator, PackageManager } from \"../types\";\n\nimport { runCommand } from \"../utils/execute\";\n\nconst getExecutor = (packageManager: PackageManager) => {\n if (packageManager === \"bun\") {\n return {\n command: \"bunx\",\n prefix: [],\n };\n }\n\n if (packageManager === \"pnpm\" || packageManager === \"yarn\") {\n return {\n command: packageManager,\n prefix: [\"dlx\"],\n };\n }\n\n return {\n command: \"npx\",\n prefix: [\"--yes\"],\n };\n};\n\nconst createNextProject: FrameworkGenerator = async (\n directory,\n packageManager,\n runner = runCommand,\n cwd,\n) => {\n const args = [\n \"create-next-app@latest\",\n directory,\n \"--ts\",\n \"--app\",\n \"--src-dir\",\n \"--skip-install\",\n \"--disable-git\",\n \"--no-tailwind\",\n \"--yes\",\n `--use-${packageManager}`,\n ];\n\n const executor = getExecutor(packageManager);\n\n await runner(\n executor.command,\n [...executor.prefix, ...args],\n cwd ? { cwd } : undefined,\n );\n};\n\nexport { createNextProject };\n","import type { FrameworkGenerator, PackageManager } from \"../types\";\n\nimport { runCommand } from \"../utils/execute\";\n\nconst getExecutor = (packageManager: PackageManager) => {\n if (packageManager === \"bun\") {\n return {\n command: \"bunx\",\n prefix: [],\n };\n }\n\n if (packageManager === \"pnpm\" || packageManager === \"yarn\") {\n return {\n command: packageManager,\n prefix: [\"dlx\"],\n };\n }\n\n return {\n command: \"npx\",\n prefix: [\"--yes\"],\n };\n};\n\nconst createTanStackProject: FrameworkGenerator = async (\n directory,\n packageManager,\n runner = runCommand,\n cwd,\n) => {\n const args = [\n \"@tanstack/cli@latest\",\n \"create\",\n directory,\n \"--framework\",\n \"React\",\n \"--package-manager\",\n packageManager,\n \"--blank\",\n \"--no-install\",\n \"--no-git\",\n \"--yes\",\n ];\n\n const executor = getExecutor(packageManager);\n\n await runner(\n executor.command,\n [...executor.prefix, ...args],\n cwd ? { cwd } : undefined,\n );\n};\n\nexport { createTanStackProject };\n","import { mkdir, writeFile } from \"node:fs/promises\";\n\nimport path from \"node:path\";\n\nimport type { FrameworkGenerator } from \"../types\";\n\nconst createReactProject: FrameworkGenerator = async (\n directory,\n _packageManager,\n _runner,\n) => {\n await mkdir(path.join(directory, \"src\"), {\n recursive: true,\n });\n\n const packageJson = {\n name: path.basename(directory),\n private: true,\n version: \"0.0.0\",\n type: \"module\",\n scripts: {\n dev: \"vite\",\n build: \"tsc --noEmit -p tsconfig.app.json && vite build\",\n preview: \"vite preview\",\n },\n dependencies: {\n react: \"^19.0.0\",\n \"react-dom\": \"^19.0.0\",\n },\n devDependencies: {\n \"@types/node\": \"latest\",\n \"@types/react\": \"^19.0.0\",\n \"@types/react-dom\": \"^19.0.0\",\n \"@vitejs/plugin-react\": \"latest\",\n typescript: \"latest\",\n vite: \"latest\",\n },\n };\n\n const files: Record<string, string> = {\n \"package.json\": JSON.stringify(packageJson, null, 2),\n\n \"index.html\": `<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>Puzzle App</title>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\" src=\"/src/main.tsx\"></script>\n </body>\n</html>`,\n\n \"tsconfig.json\": JSON.stringify(\n {\n files: [],\n references: [\n { path: \"./tsconfig.app.json\" },\n { path: \"./tsconfig.node.json\" },\n ],\n },\n null,\n 2,\n ),\n\n \"tsconfig.app.json\": JSON.stringify(\n {\n compilerOptions: {\n tsBuildInfoFile: \"./node_modules/.tmp/tsconfig.app.tsbuildinfo\",\n target: \"ES2022\",\n useDefineForClassFields: true,\n lib: [\"ES2022\", \"DOM\", \"DOM.Iterable\"],\n module: \"ESNext\",\n skipLibCheck: true,\n moduleResolution: \"bundler\",\n allowImportingTsExtensions: true,\n verbatimModuleSyntax: true,\n moduleDetection: \"force\",\n noEmit: true,\n jsx: \"react-jsx\",\n strict: true,\n noUnusedLocals: true,\n noUnusedParameters: true,\n noFallthroughCasesInSwitch: true,\n types: [\"vite/client\"],\n },\n include: [\"src\"],\n },\n null,\n 2,\n ),\n\n \"tsconfig.node.json\": JSON.stringify(\n {\n compilerOptions: {\n tsBuildInfoFile: \"./node_modules/.tmp/tsconfig.node.tsbuildinfo\",\n target: \"ES2023\",\n lib: [\"ES2023\"],\n module: \"ESNext\",\n skipLibCheck: true,\n moduleResolution: \"bundler\",\n allowImportingTsExtensions: true,\n verbatimModuleSyntax: true,\n moduleDetection: \"force\",\n noEmit: true,\n strict: true,\n },\n include: [\"vite.config.ts\"],\n },\n null,\n 2,\n ),\n\n \"vite.config.ts\": `import { defineConfig } from \"vite\";\nimport react from \"@vitejs/plugin-react\";\n\nexport default defineConfig({\n plugins: [react()],\n});`,\n\n \"src/main.tsx\": \"\",\n \"src/App.tsx\": \"\",\n \"src/index.css\": `* {\n box-sizing: border-box;\n}\n\nhtml,\nbody,\n#root {\n min-height: 100%;\n}\n\nbody {\n margin: 0;\n font-family: var(--puzzle-font-family-body, sans-serif);\n}`,\n };\n\n await Promise.all(\n Object.entries(files).map(([file, content]) =>\n writeFile(path.join(directory, file), content, \"utf8\"),\n ),\n );\n};\n\nexport { createReactProject };\n","import { createNextProject } from \"./next\";\nimport { createTanStackProject } from \"./tanstack\";\nimport { createReactProject } from \"./react\";\n\nimport type { Framework, FrameworkGenerator } from \"../types\";\n\nconst frameworkGenerators: Record<Framework, FrameworkGenerator> = {\n next: createNextProject,\n tanstack: createTanStackProject,\n react: createReactProject,\n};\n\nexport {\n createNextProject,\n createTanStackProject,\n createReactProject,\n frameworkGenerators,\n};\n","import { readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport type { Framework } from \"../types\";\n\nconst getTranspiledPackages = (auth: boolean) => [\n \"@puzzle-ui/ui\",\n \"@puzzle-ui/theme\",\n ...(auth ? [\"@puzzle-ui/fullstack\"] : []),\n];\n\nconst configureNext = async (directory: string, auth: boolean) => {\n const configPath = path.join(directory, \"next.config.ts\");\n const packages = getTranspiledPackages(auth);\n\n const config = `import type { NextConfig } from \"next\";\n\nconst nextConfig: NextConfig = {\n transpilePackages: ${JSON.stringify(packages, null, 4)},\n};\n\nexport default nextConfig;\n`;\n\n await writeFile(configPath, config, \"utf8\");\n};\n\nconst configureTanStack = async (directory: string, auth: boolean) => {\n const configPath = path.join(directory, \"vite.config.ts\");\n\n let config = await readFile(configPath, \"utf8\");\n\n const packages = getTranspiledPackages(auth);\n\n if (!config.includes(\"noExternal\")) {\n config = config.replace(\n /defineConfig\\(\\s*\\{/,\n `defineConfig({\n ssr: {\n noExternal: ${JSON.stringify(packages)},\n },`,\n );\n } else if (auth && !config.includes('\"@puzzle-ui/fullstack\"')) {\n config = config.replace(\n /noExternal:\\s*\\[([^\\]]*)\\]/,\n `noExternal: [$1, \"@puzzle-ui/fullstack\"]`,\n );\n }\n\n await writeFile(configPath, config, \"utf8\");\n};\n\nconst configureFramework = async (\n directory: string,\n framework: Framework,\n auth = false,\n) => {\n if (framework === \"next\") {\n await configureNext(directory, auth);\n return;\n }\n\n if (framework === \"tanstack\") {\n await configureTanStack(directory, auth);\n }\n};\n\nexport { configureFramework };\n","const nextProviders = `\"use client\";\n\nimport type { ReactNode } from \"react\";\n\nimport { Theme } from \"@puzzle-ui/theme\";\n\ntype ProvidersProps = {\n children: ReactNode;\n};\n\nconst Providers = ({ children }: ProvidersProps) => (\n <Theme theme=\"system\">\n {children}\n </Theme>\n);\n\nexport { Providers };\n`;\n\nconst nextLayout = `import \"./globals.css\";\n\nimport type { ReactNode } from \"react\";\n\nimport { Providers } from \"./providers\";\n\ntype RootLayoutProps = {\n children: ReactNode;\n};\n\nconst RootLayout = ({ children }: RootLayoutProps) => (\n <html lang=\"en\">\n <body>\n <Providers>\n {children}\n </Providers>\n </body>\n </html>\n);\n\nexport default RootLayout;\n`;\n\nconst nextPage = `\"use client\";\nimport { Button } from \"@puzzle-ui/ui\";\n\nconst HomePage = () => (\n <main style={{ padding: \"2rem\" }}>\n <h1>Welcome to Puzzle</h1>\n <p>Your new Puzzle application is ready.</p>\n\n <Button onClick={() => console.log(\"Hello, Puzzle!\")}>\n Get started\n </Button>\n </main>\n);\n\nexport default HomePage;\n`;\n\nconst tanstackRootRoute = `import {\n createRootRoute,\n HeadContent,\n Outlet,\n Scripts,\n} from \"@tanstack/react-router\";\n\nimport { Theme } from \"@puzzle-ui/theme\";\n\nconst RootComponent = () => (\n <html lang=\"en\">\n <head>\n <HeadContent />\n </head>\n <body>\n <Theme theme=\"system\">\n <Outlet />\n </Theme>\n <Scripts />\n </body>\n </html>\n);\n\nexport const Route = createRootRoute({\n component: RootComponent,\n});\n`;\n\nconst tanstackIndexRoute = `import { createFileRoute } from \"@tanstack/react-router\";\n\nimport { Button } from \"@puzzle-ui/ui\";\n\nconst HomePage = () => (\n <main style={{ padding: \"2rem\" }}>\n <h1>Welcome to Puzzle</h1>\n <p>Your new Puzzle application is ready.</p>\n\n <Button onClick={() => console.log(\"Hello, Puzzle!\")}>\n Get started\n </Button>\n </main>\n);\n\nexport const Route = createFileRoute(\"/\")({\n component: HomePage,\n});\n`;\n\nconst reactMain = `import React from \"react\";\nimport ReactDOM from \"react-dom/client\";\n\nimport { Theme } from \"@puzzle-ui/theme\";\n\nimport App from \"./App\";\n\nimport \"./index.css\";\n\nReactDOM.createRoot(\n document.getElementById(\"root\")!,\n).render(\n <React.StrictMode>\n <Theme theme=\"system\">\n <App />\n </Theme>\n </React.StrictMode>,\n);\n`;\n\nconst reactApp = `import { Button } from \"@puzzle-ui/ui\";\n\nconst App = () => (\n <main style={{ padding: \"2rem\" }}>\n <h1>Welcome to Puzzle</h1>\n <p>Your new Puzzle application is ready.</p>\n\n <Button onClick={() => console.log(\"Hello, Puzzle!\")}>\n Get started\n </Button>\n </main>\n);\n\nexport default App;\n`;\n\nconst themeTemplates = {\n next: {\n \"src/app/providers.tsx\": nextProviders,\n \"src/app/layout.tsx\": nextLayout,\n \"src/app/page.tsx\": nextPage,\n },\n tanstack: {\n \"src/routes/__root.tsx\": tanstackRootRoute,\n \"src/routes/index.tsx\": tanstackIndexRoute,\n },\n react: {\n \"src/main.tsx\": reactMain,\n \"src/App.tsx\": reactApp,\n },\n} as const;\n\nexport {\n nextProviders,\n nextLayout,\n nextPage,\n tanstackRootRoute,\n tanstackIndexRoute,\n reactMain,\n reactApp,\n themeTemplates,\n};\n","import { mkdir, writeFile } from \"node:fs/promises\";\n\nimport path from \"node:path\";\n\nimport type { Framework } from \"../types\";\n\nimport { themeTemplates } from \"./templates\";\n\nconst configureTheme = async (\n directory: string,\n framework: Framework,\n): Promise<void> => {\n const templates = themeTemplates[framework];\n\n await Promise.all(\n Object.entries(templates).map(async ([relativePath, content]) => {\n const filePath = path.join(directory, relativePath);\n\n await mkdir(path.dirname(filePath), {\n recursive: true,\n });\n\n await writeFile(filePath, content, \"utf8\");\n }),\n );\n};\n\nexport { configureTheme };\n","import type { Framework } from \"../types\";\n\nconst authServer = `import type { AuthServer } from \"@puzzle-ui/fullstack/auth/server\";\n\nlet authServer: AuthServer | null = null;\n\n/**\n * Register the server configured by your application.\n *\n * Create the AuthServer with your own storage adapter, password hasher,\n * rate limiter, session manager, MFA manager and CSRF configuration.\n *\n * Never import this module from browser-facing code.\n */\nexport const configureAuthServer = (server: AuthServer): void => {\n if (authServer && authServer !== server) {\n throw new Error(\"Puzzle Auth has already been configured.\");\n }\n\n authServer = server;\n};\n\n/**\n * Returns null until the application has registered its AuthServer.\n */\nexport const getAuthServer = (): AuthServer | null => authServer;\n`;\n\nconst authBootstrap = `/**\n * Initialize Puzzle Auth once for this server runtime.\n *\n * Configure your storage adapter and security providers here.\n *\n * Example:\n *\n * configureAuthServer(\n * createAuthServer({\n * auth,\n * mfa,\n * stepUp,\n * sessions,\n * cookie,\n * csrf,\n * resolveClientIp,\n * }),\n * );\n *\n * Do not use development-only or in-memory providers in production.\n */\nconst configure = async (): Promise<void> => {\n // TODO: initialize your application-specific AuthServer.\n};\n\nlet initialization: Promise<void> | null = null;\n\nexport const initializePuzzleAuth = (): Promise<void> => {\n if (!initialization) {\n initialization = configure().catch((error: unknown) => {\n initialization = null;\n throw error;\n });\n }\n\n return initialization;\n};\n`;\n\nconst authUnavailableResponse = `const createAuthUnavailableResponse = (): Response =>\n new Response(\n JSON.stringify({\n error: {\n code: \"AUTH_NOT_CONFIGURED\",\n message: \"Puzzle Auth has not been configured by the application.\",\n },\n }),\n {\n status: 503,\n headers: {\n \"Content-Type\": \"application/json; charset=utf-8\",\n \"Cache-Control\": \"no-store\",\n Pragma: \"no-cache\",\n },\n },\n );\n\nexport { createAuthUnavailableResponse };\n`;\n\nconst nextProviders = `\"use client\";\n\nimport type { ReactNode } from \"react\";\n\nimport { Theme } from \"@puzzle-ui/theme\";\nimport { AuthProvider } from \"@puzzle-ui/fullstack/auth/client\";\n\ntype ProvidersProps = {\n children: ReactNode;\n};\n\nconst Providers = ({ children }: ProvidersProps) => (\n <Theme theme=\"system\">\n <AuthProvider options={{ basePath: \"/api/auth\" }}>\n {children}\n </AuthProvider>\n </Theme>\n);\n\nexport { Providers };\n`;\n\nconst nextSignIn = `\"use client\";\n\nimport { AuthExperience } from \"@puzzle-ui/fullstack/auth/client\";\n\nconst SignInPage = () => <AuthExperience mode=\"sign-in\" />;\n\nexport default SignInPage;\n`;\n\nconst nextSignUp = `\"use client\";\n\nimport { AuthExperience } from \"@puzzle-ui/fullstack/auth/client\";\n\nconst SignUpPage = () => <AuthExperience mode=\"sign-up\" />;\n\nexport default SignUpPage;\n`;\n\nconst nextAuthRoute = `import { createNextAuthHandler } from \"@puzzle-ui/fullstack/auth/next\";\n\nimport { getAuthServer } from \"../../../../lib/auth/server\";\nimport { initializePuzzleAuth } from \"../../../../lib/auth/bootstrap\";\nimport { createAuthUnavailableResponse } from \"../../../../lib/auth/unavailable\";\n\nconst handle = async (request: Request): Promise<Response> => {\n await initializePuzzleAuth();\n\n const auth = getAuthServer();\n\n if (!auth) {\n return createAuthUnavailableResponse();\n }\n\n const handlers = createNextAuthHandler({ auth });\n\n return request.method.toUpperCase() === \"GET\"\n ? handlers.GET(request)\n : handlers.POST(request);\n};\n\nexport { handle as GET, handle as POST };\n`;\n\nconst tanstackRoot = `import {\n createRootRoute,\n HeadContent,\n Outlet,\n Scripts,\n} from \"@tanstack/react-router\";\n\nimport { Theme } from \"@puzzle-ui/theme\";\nimport { AuthProvider } from \"@puzzle-ui/fullstack/auth/client\";\n\nconst RootComponent = () => (\n <html lang=\"en\">\n <head>\n <HeadContent />\n </head>\n <body>\n <Theme theme=\"system\">\n <AuthProvider options={{ basePath: \"/api/auth\" }}>\n <Outlet />\n </AuthProvider>\n </Theme>\n <Scripts />\n </body>\n </html>\n);\n\nexport const Route = createRootRoute({\n component: RootComponent,\n});\n`;\n\nconst tanstackSignIn = `import { createFileRoute } from \"@tanstack/react-router\";\n\nimport { AuthExperience } from \"@puzzle-ui/fullstack/auth/client\";\n\nconst SignInPage = () => <AuthExperience mode=\"sign-in\" />;\n\nexport const Route = createFileRoute(\"/sign-in\")({\n component: SignInPage,\n});\n`;\n\nconst tanstackSignUp = `import { createFileRoute } from \"@tanstack/react-router\";\n\nimport { AuthExperience } from \"@puzzle-ui/fullstack/auth/client\";\n\nconst SignUpPage = () => <AuthExperience mode=\"sign-up\" />;\n\nexport const Route = createFileRoute(\"/sign-up\")({\n component: SignUpPage,\n});\n`;\n\nconst tanstackAuthRoute = `import { createFileRoute } from \"@tanstack/react-router\";\n\nimport { createTanStackAuthHandler } from \"@puzzle-ui/fullstack/auth/tanstack\";\n\nimport { getAuthServer } from \"../../../lib/auth/server\";\nimport { initializePuzzleAuth } from \"../../../lib/auth/bootstrap\";\nimport { createAuthUnavailableResponse } from \"../../../lib/auth/unavailable\";\n\nconst handle = async (request: Request): Promise<Response> => {\n await initializePuzzleAuth();\n\n const auth = getAuthServer();\n\n if (!auth) {\n return createAuthUnavailableResponse();\n }\n\n return createTanStackAuthHandler({ auth })(request);\n};\n\nexport const Route = createFileRoute(\"/api/auth/$\")({\n server: {\n handlers: {\n GET: ({ request }) => handle(request),\n POST: ({ request }) => handle(request),\n },\n },\n});\n`;\n\nconst reactMain = `import React from \"react\";\nimport ReactDOM from \"react-dom/client\";\n\nimport { Theme } from \"@puzzle-ui/theme\";\nimport { AuthProvider } from \"@puzzle-ui/fullstack/auth/client\";\n\nimport App from \"./App\";\n\nimport \"./index.css\";\n\nReactDOM.createRoot(\n document.getElementById(\"root\")!,\n).render(\n <React.StrictMode>\n <Theme theme=\"system\">\n <AuthProvider options={{ basePath: \"/api/auth\" }}>\n <App />\n </AuthProvider>\n </Theme>\n </React.StrictMode>,\n);\n`;\n\nconst reactSignIn = `import { AuthExperience } from \"@puzzle-ui/fullstack/auth/client\";\n\nexport const SignInPage = () => <AuthExperience mode=\"sign-in\" />;\n`;\n\nconst reactSignUp = `import { AuthExperience } from \"@puzzle-ui/fullstack/auth/client\";\n\nexport const SignUpPage = () => <AuthExperience mode=\"sign-up\" />;\n`;\n\nconst authTemplates: Record<Framework, Record<string, string>> = {\n next: {\n \"src/app/providers.tsx\": nextProviders,\n \"src/app/sign-in/page.tsx\": nextSignIn,\n \"src/app/sign-up/page.tsx\": nextSignUp,\n \"src/app/api/auth/[...auth]/route.ts\": nextAuthRoute,\n \"src/lib/auth/server.ts\": authServer,\n \"src/lib/auth/bootstrap.ts\": authBootstrap,\n \"src/lib/auth/unavailable.ts\": authUnavailableResponse,\n },\n tanstack: {\n \"src/routes/__root.tsx\": tanstackRoot,\n \"src/routes/sign-in.tsx\": tanstackSignIn,\n \"src/routes/sign-up.tsx\": tanstackSignUp,\n \"src/routes/api/auth/$.ts\": tanstackAuthRoute,\n \"src/lib/auth/server.ts\": authServer,\n \"src/lib/auth/bootstrap.ts\": authBootstrap,\n \"src/lib/auth/unavailable.ts\": authUnavailableResponse,\n },\n react: {\n \"src/main.tsx\": reactMain,\n \"src/auth/sign-in.tsx\": reactSignIn,\n \"src/auth/sign-up.tsx\": reactSignUp,\n },\n};\n\nexport { authTemplates };\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport type { Framework } from \"../types\";\n\nimport { authTemplates } from \"./templates\";\n\nconst configureAuth = async (\n directory: string,\n framework: Framework,\n): Promise<void> => {\n const templates = authTemplates[framework];\n\n await Promise.all(\n Object.entries(templates).map(async ([relativePath, content]) => {\n const filePath = path.join(directory, relativePath);\n\n await mkdir(path.dirname(filePath), {\n recursive: true,\n });\n\n await writeFile(filePath, content, \"utf8\");\n }),\n );\n};\n\nexport { configureAuth };\n","import { access } from \"node:fs/promises\";\n\nimport path from \"node:path\";\n\nconst validateProjectDirectory = async (\n directory: string,\n cwd = process.cwd(),\n): Promise<string> => {\n const root = path.resolve(cwd);\n const target = path.resolve(root, directory);\n\n if (target === root || !target.startsWith(`${root}${path.sep}`)) {\n throw new Error(\"Invalid project directory.\");\n }\n\n try {\n await access(target);\n\n throw new Error(\n `The directory \"${directory}\" already exists. Choose another name.`,\n );\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"already exists\")) {\n throw error;\n }\n\n if (\n error &&\n typeof error === \"object\" &&\n \"code\" in error &&\n error.code === \"ENOENT\"\n ) {\n return target;\n }\n\n throw error;\n }\n};\n\nexport { validateProjectDirectory };\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\n\nimport path from \"node:path\";\n\nimport type { Framework } from \"../types\";\n\nconst readIfExists = async (filePath: string) => {\n try {\n return await readFile(filePath, \"utf8\");\n } catch {\n return null;\n }\n};\n\nconst writeIfMissingImport = async (\n filePath: string,\n importStatement: string,\n) => {\n const current = await readIfExists(filePath);\n\n if (current === null) {\n await mkdir(path.dirname(filePath), {\n recursive: true,\n });\n\n await writeFile(filePath, `${importStatement}\\n`, \"utf8\");\n\n return;\n }\n\n if (current.includes(importStatement)) {\n return;\n }\n\n await writeFile(filePath, `${importStatement}\\n\\n${current}`, \"utf8\");\n};\n\nconst prependCssImport = async (filePath: string) => {\n const importStatement = '@import \"tailwindcss\";';\n const current = await readIfExists(filePath);\n\n if (current === null) {\n await mkdir(path.dirname(filePath), {\n recursive: true,\n });\n\n await writeFile(filePath, `${importStatement}\\n`, \"utf8\");\n\n return;\n }\n\n if (current.includes(importStatement)) {\n return;\n }\n\n await writeFile(filePath, `${importStatement}\\n\\n${current}`, \"utf8\");\n};\n\nconst configureNextTailwind = async (directory: string) => {\n const cssPath = path.join(directory, \"src\", \"app\", \"globals.css\");\n\n await prependCssImport(cssPath);\n\n const postcssConfigPath = path.join(directory, \"postcss.config.mjs\");\n\n await writeFile(\n postcssConfigPath,\n `const config = {\n plugins: {\n \"@tailwindcss/postcss\": {},\n },\n};\n\nexport default config;\n`,\n \"utf8\",\n );\n};\n\nconst findTanStackCssPath = async (directory: string) => {\n const rootRoutePath = path.join(directory, \"src\", \"routes\", \"__root.tsx\");\n\n const rootRoute = await readFile(rootRoutePath, \"utf8\");\n\n const cssImportPattern =\n /import\\s+(?:[\\w{}\\s,*]+\\s+from\\s+)?[\"']([^\"']+\\.css(?:\\?url)?)[\"']/g;\n\n const matches = [...rootRoute.matchAll(cssImportPattern)];\n\n for (const match of matches) {\n const importedPath = match[1];\n\n if (!importedPath?.startsWith(\".\")) {\n continue;\n }\n\n const cleanPath = importedPath.replace(/\\?[^/]*$/, \"\");\n\n return path.resolve(path.dirname(rootRoutePath), cleanPath);\n }\n\n // Default stylesheet location used by TanStack Start templates.\n return path.join(directory, \"src\", \"styles.css\");\n};\n\nconst configureTanStackTailwind = async (directory: string) => {\n const cssPath = await findTanStackCssPath(directory);\n\n await prependCssImport(cssPath);\n\n const rootRoutePath = path.join(directory, \"src\", \"routes\", \"__root.tsx\");\n\n const rootRoute = await readFile(rootRoutePath, \"utf8\");\n\n if (!rootRoute.includes(\".css\")) {\n await writeFile(\n rootRoutePath,\n `import \"../styles.css\";\\n${rootRoute}`,\n \"utf8\",\n );\n }\n\n const viteConfigPath = path.join(directory, \"vite.config.ts\");\n\n let viteConfig = await readFile(viteConfigPath, \"utf8\");\n\n if (!viteConfig.includes(\"@tailwindcss/vite\")) {\n viteConfig = `import tailwindcss from \"@tailwindcss/vite\";\\n` + viteConfig;\n }\n\n if (!viteConfig.includes(\"tailwindcss()\")) {\n viteConfig = viteConfig.replace(\n /plugins:\\s*\\[/,\n \"plugins: [\\n tailwindcss(),\",\n );\n }\n\n if (!viteConfig.includes(\"noExternal\")) {\n viteConfig = viteConfig.replace(\n /defineConfig\\(\\s*\\{/,\n `defineConfig({\n ssr: {\n noExternal: [\"@puzzle-ui/ui\", \"@puzzle-ui/theme\"],\n },`,\n );\n }\n\n await writeFile(viteConfigPath, viteConfig, \"utf8\");\n};\n\nconst configureReactTailwind = async (directory: string) => {\n const cssPath = path.join(directory, \"src\", \"index.css\");\n\n await prependCssImport(cssPath);\n\n const viteConfigPath = path.join(directory, \"vite.config.ts\");\n\n let viteConfig = await readFile(viteConfigPath, \"utf8\");\n\n if (!viteConfig.includes(\"@tailwindcss/vite\")) {\n viteConfig = `import tailwindcss from \"@tailwindcss/vite\";\\n` + viteConfig;\n }\n\n if (!viteConfig.includes(\"tailwindcss()\")) {\n viteConfig = viteConfig.replace(\n /plugins:\\s*\\[/,\n \"plugins: [\\n tailwindcss(),\",\n );\n }\n\n await writeFile(viteConfigPath, viteConfig, \"utf8\");\n};\n\nconst configureTailwind = async (directory: string, framework: Framework) => {\n if (framework === \"next\") {\n await configureNextTailwind(directory);\n return;\n }\n\n if (framework === \"tanstack\") {\n await configureTanStackTailwind(directory);\n return;\n }\n\n await configureReactTailwind(directory);\n};\n\nexport { configureTailwind };\n","import type { CommandRunner, Framework, PackageManager } from \"../types\";\n\nconst getTailwindPackages = (framework: Framework) => {\n if (framework === \"next\") {\n return [\n \"tailwindcss@latest\",\n \"@tailwindcss/postcss@latest\",\n \"postcss@latest\",\n ];\n }\n\n return [\"tailwindcss@latest\", \"@tailwindcss/vite@latest\"];\n};\n\nconst getInstallArguments = (\n packageManager: PackageManager,\n packages: string[],\n) => {\n if (packageManager === \"npm\") {\n return [\"install\", \"--save-dev\", ...packages];\n }\n\n if (packageManager === \"yarn\") {\n return [\"add\", \"--dev\", ...packages];\n }\n\n return [\"add\", \"-D\", ...packages];\n};\n\nconst installTailwind = async ({\n directory,\n framework,\n packageManager,\n runner,\n}: {\n directory: string;\n framework: Framework;\n packageManager: PackageManager;\n runner: CommandRunner;\n}) => {\n const packages = getTailwindPackages(framework);\n const args = getInstallArguments(packageManager, packages);\n\n await runner(packageManager, args, {\n cwd: directory,\n });\n};\n\nexport { installTailwind };\n","import { readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport * as p from \"@clack/prompts\";\n\nimport type { CommandRunner, ProjectOptions } from \"./types\";\n\nimport { frameworkGenerators } from \"./frameworks\";\nimport { configureFramework } from \"./frameworks/configure-framework\";\nimport { configureTheme } from \"./theme/configure-theme\";\nimport { configureAuth } from \"./auth/configure-auth\";\nimport { runCommand } from \"./utils/execute\";\nimport { validateProjectDirectory } from \"./utils/validate-project\";\n\nimport { PUZZLE_PACKAGES, PUZZLE_AUTH_PACKAGES } from \"./constants\";\n\nimport { configureTailwind } from \"./tailwind/configure-tailwind\";\nimport { installTailwind } from \"./tailwind/install-tailwind\";\n\ntype CreateProjectContext = {\n cwd?: string;\n runner?: CommandRunner;\n};\n\nconst installDependencies = async (\n directory: string,\n packageManager: ProjectOptions[\"packageManager\"],\n auth: boolean,\n runner: CommandRunner,\n) => {\n const packages = [...PUZZLE_PACKAGES, ...(auth ? PUZZLE_AUTH_PACKAGES : [])];\n\n const args =\n packageManager === \"npm\" ? [\"install\", ...packages] : [\"add\", ...packages];\n\n await runner(packageManager, args, {\n cwd: directory,\n });\n};\n\nconst configureProjectName = async (directory: string, projectName: string) => {\n const packageJsonPath = path.join(directory, \"package.json\");\n\n const packageJson = JSON.parse(await readFile(packageJsonPath, \"utf8\")) as {\n name?: string;\n [key: string]: unknown;\n };\n\n packageJson.name = projectName;\n\n await writeFile(\n packageJsonPath,\n `${JSON.stringify(packageJson, null, 2)}\\n`,\n \"utf8\",\n );\n};\n\nconst createProject = async (\n options: ProjectOptions,\n { cwd = process.cwd(), runner = runCommand }: CreateProjectContext = {},\n) => {\n const targetDirectory = await validateProjectDirectory(\n options.directory,\n cwd,\n );\n\n const projectName = path.basename(targetDirectory);\n const projectParent = path.dirname(targetDirectory);\n\n const spinner = p.spinner();\n let spinnerActive = false;\n\n const startStep = (message: string) => {\n spinner.start(message);\n spinnerActive = true;\n };\n\n const finishStep = (message: string) => {\n spinner.stop(message);\n spinnerActive = false;\n };\n\n try {\n startStep(\"Generating framework\");\n\n if (options.framework === \"react\") {\n await frameworkGenerators.react(\n targetDirectory,\n options.packageManager,\n runner,\n );\n } else {\n await frameworkGenerators[options.framework](\n projectName,\n options.packageManager,\n runner,\n projectParent,\n );\n }\n\n finishStep(\"Framework generated\");\n\n startStep(\"Configuring framework\");\n\n await configureFramework(targetDirectory, options.framework, options.auth);\n\n finishStep(\"Framework configured\");\n\n startStep(\"Configuring Puzzle theme\");\n\n await configureTheme(targetDirectory, options.framework);\n await configureProjectName(targetDirectory, projectName);\n\n finishStep(\"Puzzle theme configured\");\n\n if (options.auth) {\n startStep(\"Configuring Puzzle Auth\");\n\n await configureAuth(targetDirectory, options.framework);\n\n finishStep(\"Puzzle Auth configured\");\n }\n\n if (options.tailwind) {\n startStep(\"Configuring Tailwind CSS\");\n\n await configureTailwind(targetDirectory, options.framework);\n\n finishStep(\"Tailwind CSS configured\");\n\n startStep(\"Installing Tailwind CSS\");\n\n await installTailwind({\n directory: targetDirectory,\n framework: options.framework,\n packageManager: options.packageManager,\n runner,\n });\n\n finishStep(\"Tailwind CSS installed\");\n }\n\n startStep(\"Installing Puzzle\");\n\n await installDependencies(\n targetDirectory,\n options.packageManager,\n options.auth,\n runner,\n );\n\n finishStep(options.auth ? \"Puzzle and Auth installed\" : \"Puzzle installed\");\n } catch (error) {\n if (spinnerActive) {\n spinner.error(\"Project creation failed\");\n }\n\n throw error;\n }\n\n p.log.success(`Project \"${projectName}\" created successfully.`);\n\n p.outro(\n `Next steps:\\n\\n cd ${path.relative(cwd, targetDirectory) || \".\"}\\n ${options.packageManager} run dev`,\n );\n};\n\nexport { createProject, type CreateProjectContext };\n","#!/usr/bin/env node\n\nimport * as p from \"@clack/prompts\";\n\nimport { getProjectOptions } from \"./prompts\";\n\nimport { createProject } from \"./create-project\";\n\nconst main = async (): Promise<void> => {\n const options = await getProjectOptions();\n\n if (!options) {\n p.cancel(\"Project creation cancelled.\");\n return;\n }\n\n await createProject(options);\n};\n\nmain().catch((error: unknown) => {\n p.log.error(error instanceof Error ? error.message : String(error));\n\n process.exitCode = 1;\n});\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@puzzle-ui/create",
3
- "version": "0.4.0",
4
- "description": "Create Beautiful React applications fast with Puzzle UI",
3
+ "version": "0.5.0",
4
+ "description": "Create React applications with Puzzle UI.",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "bin": {
@@ -11,6 +11,13 @@
11
11
  "dist",
12
12
  "README.md"
13
13
  ],
14
+ "keywords": [
15
+ "puzzle-ui",
16
+ "react",
17
+ "create",
18
+ "scaffolding",
19
+ "cli"
20
+ ],
14
21
  "engines": {
15
22
  "node": ">=20.19.0"
16
23
  },
@@ -27,7 +34,7 @@
27
34
  "devDependencies": {
28
35
  "@types/node": "^26.0.0",
29
36
  "tsdown": "^0.23.1",
30
- "typescript": "^6.0.3",
37
+ "typescript": "^7.0.2",
31
38
  "vitest": "^5.1.0"
32
39
  },
33
40
  "publishConfig": {