@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 +186 -16
- package/dist/index.js +394 -40
- package/dist/index.js.map +1 -1
- package/package.json +10 -3
package/README.md
CHANGED
|
@@ -1,40 +1,210 @@
|
|
|
1
1
|
# @puzzle-ui/create
|
|
2
2
|
|
|
3
|
-
Create React
|
|
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
|
|
8
|
-
- npm or
|
|
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
|
-
##
|
|
13
|
+
## Quick start
|
|
11
14
|
|
|
12
|
-
|
|
15
|
+
### npm
|
|
13
16
|
|
|
14
17
|
```bash
|
|
15
18
|
npx @puzzle-ui/create
|
|
16
19
|
```
|
|
17
20
|
|
|
18
|
-
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
126
|
+
`--use-${packageManager}`
|
|
100
127
|
];
|
|
101
|
-
const
|
|
102
|
-
|
|
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
|
|
125
|
-
|
|
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
|
|
505
|
-
|
|
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
|
-
]
|
|
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
|
-
|
|
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(
|
|
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":";;;;;;AAIA,MAAa,kBAAkB,CAC7B,wBACA,yBACF;AAEA,MAAa,uBAAuB;CAClC;CACA;CACA;AACF;AAEA,MAAa,aAIP;CACJ;EACE,OAAO;EACP,OAAO;EACP,MAAM;CACR;CACA;EACE,OAAO;EACP,OAAO;EACP,MAAM;CACR;CACA;EACE,OAAO;EACP,OAAO;EACP,MAAM;CACR;AACF;;ACnCA,MAAM,eAAe,UACnB,MACG,UAAU,MAAM,CAAC,CACjB,QAAQ,oBAAoB,EAAE,CAAC,CAC/B,QAAQ,sBAAsB,OAAO,CAAC,CACtC,QAAQ,wBAAwB,OAAO,CAAC,CACxC,QAAQ,kBAAkB,GAAG,CAAC,CAC9B,QAAQ,YAAY,EAAE,CAAC,CACvB,YAAY;;ACNjB,MAAM,wBACJ,YAAY,QAAQ,IAAI,yBAAyB,OAC9B;CAGnB,OAFc,UAAU,MAAM,qCAElB,CAAC,GAAG,MAAqC;AACvD;;ACEA,MAAM,oBAAoB,YAA4C;CACpE,EAAE,MAAM,6BAA6B;CAErC,MAAM,OAAO,MAAM,EAAE,KAAK;EACxB,SAAS;EACT,aAAa;EACb,WAAW,UAAU;GACnB,IAAI,CAAC,OAAO,KAAK,GACf,OAAO;GAGT,IAAI,CAAC,YAAY,KAAK,GACpB,OAAO;EAEX;CACF,CAAC;CAED,IAAI,EAAE,SAAS,IAAI,GACjB,OAAO;CAGT,MAAM,YAAY,YAAY,IAAI;CAElC,MAAM,YAAY,MAAM,EAAE,OAAO;EAC/B,SAAS;EACT,SAAS,WAAW,KAAK,UAAU;GACjC,OAAO,KAAK;GACZ,OAAO,KAAK;GACZ,MAAM,KAAK;EACb,EAAE;CACJ,CAAC;CAED,IAAI,EAAE,SAAS,SAAS,GACtB,OAAO;CAGT,MAAM,WAAW,MAAM,EAAE,QAAQ;EAC/B,SAAS;EACT,cAAc;CAChB,CAAC;CAED,IAAI,EAAE,SAAS,QAAQ,GAAG;EACxB,EAAE,OAAO,6BAA6B;EACtC,OAAO;CACT;CAEA,MAAM,OAAO,MAAM,EAAE,QAAQ;EAC3B,SAAS;EACT,cAAc;CAChB,CAAC;CAED,IAAI,EAAE,SAAS,IAAI,GAAG;EACpB,EAAE,OAAO,6BAA6B;EACtC,OAAO;CACT;CAEA,OAAO;EACL,MAAM;EACN;EACW;EACX,gBAAgB,qBAAqB;EACrC;EACA;CACF;AACF;;ACtEA,MAAM,cAA6B,SAAS,MAAM,UAAU,CAAC,MAC3D,IAAI,SAAS,SAAS,WAAW;CAC/B,MAAM,QAAQ,MAAM,SAAS,MAAM;EACjC,KAAK,QAAQ,OAAO,QAAQ,IAAI;EAChC,OAAO,QAAQ,SAAS;EACxB,OAAO;EACP,KAAK,QAAQ;CACf,CAAC;CAED,MAAM,KAAK,SAAS,MAAM;CAE1B,MAAM,KAAK,UAAU,MAAM,WAAW;EACpC,IAAI,SAAS,GAAG;GACd,QAAQ;GACR;EACF;EAEA,uBACE,IAAI,MACF,SACI,GAAG,QAAQ,0BAA0B,WACrC,GAAG,QAAQ,oBAAoB,QAAQ,WAC7C,CACF;CACF,CAAC;AACH,CAAC;;ACzBH,MAAMA,iBAAe,mBAAmC;CACtD,IAAI,mBAAmB,OACrB,OAAO;EACL,SAAS;EACT,QAAQ,CAAC;CACX;CAGF,IAAI,mBAAmB,UAAU,mBAAmB,QAClD,OAAO;EACL,SAAS;EACT,QAAQ,CAAC,KAAK;CAChB;CAGF,OAAO;EACL,SAAS;EACT,QAAQ,CAAC,OAAO;CAClB;AACF;AAEA,MAAM,oBAAwC,OAC5C,WACA,gBACA,SAAS,YACT,QACG;CACH,MAAM,OAAO;EACX;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,SAAS;CACX;CAEA,MAAM,WAAWA,cAAY,cAAc;CAE3C,MAAM,OACJ,SAAS,SACT,CAAC,GAAG,SAAS,QAAQ,GAAG,IAAI,GAC5B,MAAM,EAAE,IAAI,IAAI,KAAA,CAClB;AACF;;AC/CA,MAAM,eAAe,mBAAmC;CACtD,IAAI,mBAAmB,OACrB,OAAO;EACL,SAAS;EACT,QAAQ,CAAC;CACX;CAGF,IAAI,mBAAmB,UAAU,mBAAmB,QAClD,OAAO;EACL,SAAS;EACT,QAAQ,CAAC,KAAK;CAChB;CAGF,OAAO;EACL,SAAS;EACT,QAAQ,CAAC,OAAO;CAClB;AACF;AAEA,MAAM,wBAA4C,OAChD,WACA,gBACA,SAAS,YACT,QACG;CACH,MAAM,OAAO;EACX;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CAEA,MAAM,WAAW,YAAY,cAAc;CAE3C,MAAM,OACJ,SAAS,SACT,CAAC,GAAG,SAAS,QAAQ,GAAG,IAAI,GAC5B,MAAM,EAAE,IAAI,IAAI,KAAA,CAClB;AACF;;AC9CA,MAAM,qBAAyC,OAC7C,WACA,iBACA,YACG;CACH,MAAM,MAAM,KAAK,KAAK,WAAW,KAAK,GAAG,EACvC,WAAW,KACb,CAAC;CAED,MAAM,cAAc;EAClB,MAAM,KAAK,SAAS,SAAS;EAC7B,SAAS;EACT,SAAS;EACT,MAAM;EACN,SAAS;GACP,KAAK;GACL,OAAO;GACP,SAAS;EACX;EACA,cAAc;GACZ,OAAO;GACP,aAAa;EACf;EACA,iBAAiB;GACf,eAAe;GACf,gBAAgB;GAChB,oBAAoB;GACpB,wBAAwB;GACxB,YAAY;GACZ,MAAM;EACR;CACF;CAEA,MAAM,QAAgC;EACpC,gBAAgB,KAAK,UAAU,aAAa,MAAM,CAAC;EAEnD,cAAc;;;;;;;;;;;;EAad,iBAAiB,KAAK,UACpB;GACE,OAAO,CAAC;GACR,YAAY,CACV,EAAE,MAAM,sBAAsB,GAC9B,EAAE,MAAM,uBAAuB,CACjC;EACF,GACA,MACA,CACF;EAEA,qBAAqB,KAAK,UACxB;GACE,iBAAiB;IACf,iBAAiB;IACjB,QAAQ;IACR,yBAAyB;IACzB,KAAK;KAAC;KAAU;KAAO;IAAc;IACrC,QAAQ;IACR,cAAc;IACd,kBAAkB;IAClB,4BAA4B;IAC5B,sBAAsB;IACtB,iBAAiB;IACjB,QAAQ;IACR,KAAK;IACL,QAAQ;IACR,gBAAgB;IAChB,oBAAoB;IACpB,4BAA4B;IAC5B,OAAO,CAAC,aAAa;GACvB;GACA,SAAS,CAAC,KAAK;EACjB,GACA,MACA,CACF;EAEA,sBAAsB,KAAK,UACzB;GACE,iBAAiB;IACf,iBAAiB;IACjB,QAAQ;IACR,KAAK,CAAC,QAAQ;IACd,QAAQ;IACR,cAAc;IACd,kBAAkB;IAClB,4BAA4B;IAC5B,sBAAsB;IACtB,iBAAiB;IACjB,QAAQ;IACR,QAAQ;GACV;GACA,SAAS,CAAC,gBAAgB;EAC5B,GACA,MACA,CACF;EAEA,kBAAkB;;;;;;EAOlB,gBAAgB;EAChB,eAAe;EACf,iBAAiB;;;;;;;;;;;;;;CAcnB;CAEA,MAAM,QAAQ,IACZ,OAAO,QAAQ,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,aAChC,UAAU,KAAK,KAAK,WAAW,IAAI,GAAG,SAAS,MAAM,CACvD,CACF;AACF;;AC3IA,MAAM,sBAA6D;CACjE,MAAM;CACN,UAAU;CACV,OAAO;AACT;;ACLA,MAAM,yBAAyB,SAAkB;CAC/C;CACA;CACA,GAAI,OAAO,CAAC,sBAAsB,IAAI,CAAC;AACzC;AAEA,MAAM,gBAAgB,OAAO,WAAmB,SAAkB;CAChE,MAAM,aAAa,KAAK,KAAK,WAAW,gBAAgB;CACxD,MAAM,WAAW,sBAAsB,IAAI;CAE3C,MAAM,SAAS;;;uBAGM,KAAK,UAAU,UAAU,MAAM,CAAC,EAAE;;;;;CAMvD,MAAM,UAAU,YAAY,QAAQ,MAAM;AAC5C;AAEA,MAAM,oBAAoB,OAAO,WAAmB,SAAkB;CACpE,MAAM,aAAa,KAAK,KAAK,WAAW,gBAAgB;CAExD,IAAI,SAAS,MAAM,SAAS,YAAY,MAAM;CAE9C,MAAM,WAAW,sBAAsB,IAAI;CAE3C,IAAI,CAAC,OAAO,SAAS,YAAY,GAC/B,SAAS,OAAO,QACd,uBACA;;kBAEY,KAAK,UAAU,QAAQ,EAAE;KAEvC;MACK,IAAI,QAAQ,CAAC,OAAO,SAAS,0BAAwB,GAC1D,SAAS,OAAO,QACd,8BACA,0CACF;CAGF,MAAM,UAAU,YAAY,QAAQ,MAAM;AAC5C;AAEA,MAAM,qBAAqB,OACzB,WACA,WACA,OAAO,UACJ;CACH,IAAI,cAAc,QAAQ;EACxB,MAAM,cAAc,WAAW,IAAI;EACnC;CACF;CAEA,IAAI,cAAc,YAChB,MAAM,kBAAkB,WAAW,IAAI;AAE3C;AC8EA,MAAM,iBAAiB;CACrB,MAAM;EACJ,yBAAyB;;;;;;;;;;;;;;;;;;EACzB,sBAAsB;;;;;;;;;;;;;;;;;;;;;;EACtB,oBAAoB;;;;;;;;;;;;;;;;CACtB;CACA,UAAU;EACR,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;EACzB,wBAAwB;;;;;;;;;;;;;;;;;;;CAC1B;CACA,OAAO;EACL,gBAAgB;;;;;;;;;;;;;;;;;;;EAChB,eAAe;;;;;;;;;;;;;;;CACjB;AACF;;ACrJA,MAAM,iBAAiB,OACrB,WACA,cACkB;CAClB,MAAM,YAAY,eAAe;CAEjC,MAAM,QAAQ,IACZ,OAAO,QAAQ,SAAS,CAAC,CAAC,IAAI,OAAO,CAAC,cAAc,aAAa;EAC/D,MAAM,WAAW,KAAK,KAAK,WAAW,YAAY;EAElD,MAAM,MAAM,KAAK,QAAQ,QAAQ,GAAG,EAClC,WAAW,KACb,CAAC;EAED,MAAM,UAAU,UAAU,SAAS,MAAM;CAC3C,CAAC,CACH;AACF;;ACvBA,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;AA0BnB,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCtB,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;AA0MhC,MAAM,gBAA2D;CAC/D,MAAM;EACJ,yBAAyB;;;;;;;;;;;;;;;;;;;;;EACzB,4BAA4B;;;;;;;;EAC5B,4BAA4B;;;;;;;;EAC5B,uCAAuC;;;;;;;;;;;;;;;;;;;;;;;;EACvC,0BAA0B;EAC1B,6BAA6B;EAC7B,+BAA+B;CACjC;CACA,UAAU;EACR,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EACzB,0BAA0B;;;;;;;;;;EAC1B,0BAA0B;;;;;;;;;;EAC1B,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAC5B,0BAA0B;EAC1B,6BAA6B;EAC7B,+BAA+B;CACjC;CACA,OAAO;EACL,gBAAgB;;;;;;;;;;;;;;;;;;;;;;EAChB,wBAAwB;;;;EACxB,wBAAwB;;;;CAC1B;AACF;;AC9RA,MAAM,gBAAgB,OACpB,WACA,cACkB;CAClB,MAAM,YAAY,cAAc;CAEhC,MAAM,QAAQ,IACZ,OAAO,QAAQ,SAAS,CAAC,CAAC,IAAI,OAAO,CAAC,cAAc,aAAa;EAC/D,MAAM,WAAW,KAAK,KAAK,WAAW,YAAY;EAElD,MAAM,MAAM,KAAK,QAAQ,QAAQ,GAAG,EAClC,WAAW,KACb,CAAC;EAED,MAAM,UAAU,UAAU,SAAS,MAAM;CAC3C,CAAC,CACH;AACF;;ACpBA,MAAM,2BAA2B,OAC/B,WACA,MAAM,QAAQ,IAAI,MACE;CACpB,MAAM,OAAO,KAAK,QAAQ,GAAG;CAC7B,MAAM,SAAS,KAAK,QAAQ,MAAM,SAAS;CAE3C,IAAI,WAAW,QAAQ,CAAC,OAAO,WAAW,GAAG,OAAO,KAAK,KAAK,GAC5D,MAAM,IAAI,MAAM,4BAA4B;CAG9C,IAAI;EACF,MAAM,OAAO,MAAM;EAEnB,MAAM,IAAI,MACR,kBAAkB,UAAU,uCAC9B;CACF,SAAS,OAAO;EACd,IAAI,iBAAiB,SAAS,MAAM,QAAQ,SAAS,gBAAgB,GACnE,MAAM;EAGR,IACE,SACA,OAAO,UAAU,YACjB,UAAU,SACV,MAAM,SAAS,UAEf,OAAO;EAGT,MAAM;CACR;AACF;;AC/BA,MAAM,eAAe,OAAO,aAAqB;CAC/C,IAAI;EACF,OAAO,MAAM,SAAS,UAAU,MAAM;CACxC,QAAQ;EACN,OAAO;CACT;AACF;AAyBA,MAAM,mBAAmB,OAAO,aAAqB;CACnD,MAAM,kBAAkB;CACxB,MAAM,UAAU,MAAM,aAAa,QAAQ;CAE3C,IAAI,YAAY,MAAM;EACpB,MAAM,MAAM,KAAK,QAAQ,QAAQ,GAAG,EAClC,WAAW,KACb,CAAC;EAED,MAAM,UAAU,UAAU,GAAG,gBAAgB,KAAK,MAAM;EAExD;CACF;CAEA,IAAI,QAAQ,SAAS,eAAe,GAClC;CAGF,MAAM,UAAU,UAAU,GAAG,gBAAgB,MAAM,WAAW,MAAM;AACtE;AAEA,MAAM,wBAAwB,OAAO,cAAsB;CACzD,MAAM,UAAU,KAAK,KAAK,WAAW,OAAO,OAAO,aAAa;CAEhE,MAAM,iBAAiB,OAAO;CAE9B,MAAM,oBAAoB,KAAK,KAAK,WAAW,oBAAoB;CAEnE,MAAM,UACJ,mBACA;;;;;;;GAQA,MACF;AACF;AAEA,MAAM,sBAAsB,OAAO,cAAsB;CACvD,MAAM,gBAAgB,KAAK,KAAK,WAAW,OAAO,UAAU,YAAY;CAOxE,MAAM,UAAU,CAAC,IAAG,MALI,SAAS,eAAe,MAAM,EAAA,CAKxB,SAAS,qEAAgB,CAAC;CAExD,KAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,eAAe,MAAM;EAE3B,IAAI,CAAC,cAAc,WAAW,GAAG,GAC/B;EAGF,MAAM,YAAY,aAAa,QAAQ,YAAY,EAAE;EAErD,OAAO,KAAK,QAAQ,KAAK,QAAQ,aAAa,GAAG,SAAS;CAC5D;CAGA,OAAO,KAAK,KAAK,WAAW,OAAO,YAAY;AACjD;AAEA,MAAM,4BAA4B,OAAO,cAAsB;CAC7D,MAAM,UAAU,MAAM,oBAAoB,SAAS;CAEnD,MAAM,iBAAiB,OAAO;CAE9B,MAAM,gBAAgB,KAAK,KAAK,WAAW,OAAO,UAAU,YAAY;CAExE,MAAM,YAAY,MAAM,SAAS,eAAe,MAAM;CAEtD,IAAI,CAAC,UAAU,SAAS,MAAM,GAC5B,MAAM,UACJ,eACA,4BAA4B,aAC5B,MACF;CAGF,MAAM,iBAAiB,KAAK,KAAK,WAAW,gBAAgB;CAE5D,IAAI,aAAa,MAAM,SAAS,gBAAgB,MAAM;CAEtD,IAAI,CAAC,WAAW,SAAS,mBAAmB,GAC1C,aAAa,mDAAmD;CAGlE,IAAI,CAAC,WAAW,SAAS,eAAe,GACtC,aAAa,WAAW,QACtB,iBACA,gCACF;CAGF,IAAI,CAAC,WAAW,SAAS,YAAY,GACnC,aAAa,WAAW,QACtB,uBACA;;;KAIF;CAGF,MAAM,UAAU,gBAAgB,YAAY,MAAM;AACpD;AAEA,MAAM,yBAAyB,OAAO,cAAsB;CAC1D,MAAM,UAAU,KAAK,KAAK,WAAW,OAAO,WAAW;CAEvD,MAAM,iBAAiB,OAAO;CAE9B,MAAM,iBAAiB,KAAK,KAAK,WAAW,gBAAgB;CAE5D,IAAI,aAAa,MAAM,SAAS,gBAAgB,MAAM;CAEtD,IAAI,CAAC,WAAW,SAAS,mBAAmB,GAC1C,aAAa,mDAAmD;CAGlE,IAAI,CAAC,WAAW,SAAS,eAAe,GACtC,aAAa,WAAW,QACtB,iBACA,gCACF;CAGF,MAAM,UAAU,gBAAgB,YAAY,MAAM;AACpD;AAEA,MAAM,oBAAoB,OAAO,WAAmB,cAAyB;CAC3E,IAAI,cAAc,QAAQ;EACxB,MAAM,sBAAsB,SAAS;EACrC;CACF;CAEA,IAAI,cAAc,YAAY;EAC5B,MAAM,0BAA0B,SAAS;EACzC;CACF;CAEA,MAAM,uBAAuB,SAAS;AACxC;;ACvLA,MAAM,uBAAuB,cAAyB;CACpD,IAAI,cAAc,QAChB,OAAO;EACL;EACA;EACA;CACF;CAGF,OAAO,CAAC,sBAAsB,0BAA0B;AAC1D;AAEA,MAAM,uBACJ,gBACA,aACG;CACH,IAAI,mBAAmB,OACrB,OAAO;EAAC;EAAW;EAAc,GAAG;CAAQ;CAG9C,IAAI,mBAAmB,QACrB,OAAO;EAAC;EAAO;EAAS,GAAG;CAAQ;CAGrC,OAAO;EAAC;EAAO;EAAM,GAAG;CAAQ;AAClC;AAEA,MAAM,kBAAkB,OAAO,EAC7B,WACA,WACA,gBACA,aAMI;CACJ,MAAM,WAAW,oBAAoB,SAAS;CAG9C,MAAM,OAAO,gBAFA,oBAAoB,gBAAgB,QAEjB,GAAG,EACjC,KAAK,UACP,CAAC;AACH;;ACtBA,MAAM,sBAAsB,OAC1B,WACA,gBACA,MACA,WACG;CACH,MAAM,WAAW,CAAC,GAAG,iBAAiB,GAAI,OAAO,uBAAuB,CAAC,CAAE;CAK3E,MAAM,OAAO,gBAFX,mBAAmB,QAAQ,CAAC,WAAW,GAAG,QAAQ,IAAI,CAAC,OAAO,GAAG,QAAQ,GAExC,EACjC,KAAK,UACP,CAAC;AACH;AAEA,MAAM,uBAAuB,OAAO,WAAmB,gBAAwB;CAC7E,MAAM,kBAAkB,KAAK,KAAK,WAAW,cAAc;CAE3D,MAAM,cAAc,KAAK,MAAM,MAAM,SAAS,iBAAiB,MAAM,CAAC;CAKtE,YAAY,OAAO;CAEnB,MAAM,UACJ,iBACA,GAAG,KAAK,UAAU,aAAa,MAAM,CAAC,EAAE,KACxC,MACF;AACF;AAEA,MAAM,gBAAgB,OACpB,SACA,EAAE,MAAM,QAAQ,IAAI,GAAG,SAAS,eAAqC,CAAC,MACnE;CACH,MAAM,kBAAkB,MAAM,yBAC5B,QAAQ,WACR,GACF;CAEA,MAAM,cAAc,KAAK,SAAS,eAAe;CACjD,MAAM,gBAAgB,KAAK,QAAQ,eAAe;CAElD,MAAM,UAAU,EAAE,QAAQ;CAC1B,IAAI,gBAAgB;CAEpB,MAAM,aAAa,YAAoB;EACrC,QAAQ,MAAM,OAAO;EACrB,gBAAgB;CAClB;CAEA,MAAM,cAAc,YAAoB;EACtC,QAAQ,KAAK,OAAO;EACpB,gBAAgB;CAClB;CAEA,IAAI;EACF,UAAU,sBAAsB;EAEhC,IAAI,QAAQ,cAAc,SACxB,MAAM,oBAAoB,MACxB,iBACA,QAAQ,gBACR,MACF;OAEA,MAAM,oBAAoB,QAAQ,UAAU,CAC1C,aACA,QAAQ,gBACR,QACA,aACF;EAGF,WAAW,qBAAqB;EAEhC,UAAU,uBAAuB;EAEjC,MAAM,mBAAmB,iBAAiB,QAAQ,WAAW,QAAQ,IAAI;EAEzE,WAAW,sBAAsB;EAEjC,UAAU,0BAA0B;EAEpC,MAAM,eAAe,iBAAiB,QAAQ,SAAS;EACvD,MAAM,qBAAqB,iBAAiB,WAAW;EAEvD,WAAW,yBAAyB;EAEpC,IAAI,QAAQ,MAAM;GAChB,UAAU,yBAAyB;GAEnC,MAAM,cAAc,iBAAiB,QAAQ,SAAS;GAEtD,WAAW,wBAAwB;EACrC;EAEA,IAAI,QAAQ,UAAU;GACpB,UAAU,0BAA0B;GAEpC,MAAM,kBAAkB,iBAAiB,QAAQ,SAAS;GAE1D,WAAW,yBAAyB;GAEpC,UAAU,yBAAyB;GAEnC,MAAM,gBAAgB;IACpB,WAAW;IACX,WAAW,QAAQ;IACnB,gBAAgB,QAAQ;IACxB;GACF,CAAC;GAED,WAAW,wBAAwB;EACrC;EAEA,UAAU,mBAAmB;EAE7B,MAAM,oBACJ,iBACA,QAAQ,gBACR,QAAQ,MACR,MACF;EAEA,WAAW,QAAQ,OAAO,8BAA8B,kBAAkB;CAC5E,SAAS,OAAO;EACd,IAAI,eACF,QAAQ,MAAM,yBAAyB;EAGzC,MAAM;CACR;CAEA,EAAE,IAAI,QAAQ,YAAY,YAAY,wBAAwB;CAE9D,EAAE,MACA,uBAAuB,KAAK,SAAS,KAAK,eAAe,KAAK,IAAI,MAAM,QAAQ,eAAe,SACjG;AACF;;AC7JA,MAAM,OAAO,YAA2B;CACtC,MAAM,UAAU,MAAM,kBAAkB;CAExC,IAAI,CAAC,SAAS;EACZ,EAAE,OAAO,6BAA6B;EACtC;CACF;CAEA,MAAM,cAAc,OAAO;AAC7B;AAEA,KAAK,CAAC,CAAC,OAAO,UAAmB;CAC/B,EAAE,IAAI,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;CAElE,QAAQ,WAAW;AACrB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@puzzle-ui/create",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Create
|
|
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": "^
|
|
37
|
+
"typescript": "^7.0.2",
|
|
31
38
|
"vitest": "^5.1.0"
|
|
32
39
|
},
|
|
33
40
|
"publishConfig": {
|