@puzzle-ui/create 0.4.0 → 0.5.1
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 +15 -23
- package/dist/index.js +394 -40
- package/dist/index.js.map +1 -1
- package/package.json +15 -3
package/README.md
CHANGED
|
@@ -1,41 +1,33 @@
|
|
|
1
1
|
# @puzzle-ui/create
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Generate a new React application with Puzzle UI and Theme configured. Choose Next.js, TanStack Start, or Basic React (React + Vite + TypeScript), then optionally add Tailwind CSS v4 or Puzzle Auth.
|
|
4
|
+
|
|
5
|
+
**Documentation:** [https://puzzle-ui.com/docs/create](https://puzzle-ui.com/docs/create)
|
|
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
|
+
- Internet access to download the framework template and dependencies
|
|
9
12
|
|
|
10
|
-
##
|
|
13
|
+
## Create a project
|
|
11
14
|
|
|
12
|
-
|
|
15
|
+
Run the interactive generator; it prompts for a project name, framework, Tailwind, and Puzzle Auth. The name is converted to kebab-case. The CLI does not overwrite an existing directory and has no command-line flags.
|
|
13
16
|
|
|
14
17
|
```bash
|
|
15
18
|
npx @puzzle-ui/create
|
|
16
19
|
```
|
|
17
20
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
bunx @puzzle-ui/create
|
|
22
|
-
```
|
|
21
|
+
Alternatives: `bunx @puzzle-ui/create`, `pnpm dlx @puzzle-ui/create`, or `yarn dlx @puzzle-ui/create` (Yarn 2+; Yarn Classic users can use `npx`).
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
The generator installs `@puzzle-ui/ui` and `@puzzle-ui/theme`, adds a themed starter page with a Puzzle `Button`, and uses the detected package manager for framework generation and dependency installation. Tailwind is enabled by default; Puzzle Auth is optional and disabled by default.
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
- TanStack Start
|
|
28
|
-
- Basic React (Vite + TypeScript)
|
|
25
|
+
When Auth is enabled, the CLI adds client auth components and, for Next.js and TanStack Start, an API route and server bootstrap. The generated bootstrap deliberately has no default security providers: configure the required storage, password hashing, rate limiting, sessions, MFA, step-up, cookies, CSRF, and trusted client IP handling before exposing the route. See the [Authentication setup guide](https://puzzle-ui.com/docs/developer/authentication).
|
|
29
26
|
|
|
30
|
-
|
|
27
|
+
See the [Create documentation](https://puzzle-ui.com/docs/create) for framework-specific generated files, Tailwind setup, and Auth requirements.
|
|
31
28
|
|
|
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
|
|
29
|
+
Puzzle is under active development and is not yet ready for production use. Review and test generated applications before using them in production.
|
|
38
30
|
|
|
39
|
-
##
|
|
31
|
+
## Package details
|
|
40
32
|
|
|
41
|
-
MIT
|
|
33
|
+
The published command is `create-puzzle`. The package is CLI-only; it does not provide an importable JavaScript API. License: MIT.
|
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":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@puzzle-ui/create",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Create
|
|
3
|
+
"version": "0.5.1",
|
|
4
|
+
"description": "Create React applications with Puzzle UI.",
|
|
5
|
+
"homepage": "https://puzzle-ui.com",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/senorprogramador/puzzle.git"
|
|
9
|
+
},
|
|
5
10
|
"license": "MIT",
|
|
6
11
|
"type": "module",
|
|
7
12
|
"bin": {
|
|
@@ -11,6 +16,13 @@
|
|
|
11
16
|
"dist",
|
|
12
17
|
"README.md"
|
|
13
18
|
],
|
|
19
|
+
"keywords": [
|
|
20
|
+
"puzzle-ui",
|
|
21
|
+
"react",
|
|
22
|
+
"create",
|
|
23
|
+
"scaffolding",
|
|
24
|
+
"cli"
|
|
25
|
+
],
|
|
14
26
|
"engines": {
|
|
15
27
|
"node": ">=20.19.0"
|
|
16
28
|
},
|
|
@@ -27,7 +39,7 @@
|
|
|
27
39
|
"devDependencies": {
|
|
28
40
|
"@types/node": "^26.0.0",
|
|
29
41
|
"tsdown": "^0.23.1",
|
|
30
|
-
"typescript": "^
|
|
42
|
+
"typescript": "^7.0.2",
|
|
31
43
|
"vitest": "^5.1.0"
|
|
32
44
|
},
|
|
33
45
|
"publishConfig": {
|