nextjs-hackathon-stack 0.1.2 → 0.1.4
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/dist/index.js +13 -5
- package/package.json +1 -1
- package/template/.cursor/agents/security-researcher.md +1 -1
- package/template/.cursor/agents/test-qa.md +2 -2
- package/template/.cursor/rules/security.mdc +1 -1
- package/template/.cursor/skills/create-api-route/SKILL.md +3 -3
- package/template/.cursor/skills/create-feature/SKILL.md +5 -5
- package/template/.cursor/skills/review-branch/SKILL.md +3 -3
- package/template/.cursor/skills/security-audit/SKILL.md +1 -1
- package/template/.env.example +1 -1
- package/template/README.md +12 -12
- package/template/package.json.tmpl +3 -1
- package/template/playwright.config.ts +1 -1
- package/template/src/features/auth/components/login-form.tsx +4 -4
- package/template/src/shared/lib/utils.ts +6 -0
package/dist/index.js
CHANGED
|
@@ -101,13 +101,13 @@ async function scaffold(projectName, skipInstall) {
|
|
|
101
101
|
if (!skipInstall) {
|
|
102
102
|
spinner2.start("Installing dependencies (this may take a minute)");
|
|
103
103
|
try {
|
|
104
|
-
execSync("
|
|
104
|
+
execSync("pnpm install", { cwd: targetDir, stdio: "pipe" });
|
|
105
105
|
spinner2.stop("Dependencies installed");
|
|
106
106
|
} catch (err) {
|
|
107
107
|
spinner2.stop("Failed to install dependencies");
|
|
108
108
|
const stderr = err instanceof Error && "stderr" in err ? err.stderr?.toString() : String(err);
|
|
109
|
-
p3.log.error(stderr || "
|
|
110
|
-
p3.log.info("You can install manually: cd " + projectName + " &&
|
|
109
|
+
p3.log.error(stderr || "pnpm install failed");
|
|
110
|
+
p3.log.info("You can install manually: cd " + projectName + " && pnpm install");
|
|
111
111
|
}
|
|
112
112
|
spinner2.start("Initializing shadcn/ui");
|
|
113
113
|
try {
|
|
@@ -133,6 +133,14 @@ async function scaffold(projectName, skipInstall) {
|
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
|
+
spinner2.start("Creating initial commit");
|
|
137
|
+
try {
|
|
138
|
+
execSync("git add -A", { cwd: targetDir, stdio: "ignore" });
|
|
139
|
+
execSync('git commit -m "chore: initial scaffold"', { cwd: targetDir, stdio: "ignore" });
|
|
140
|
+
spinner2.stop("Initial commit created");
|
|
141
|
+
} catch {
|
|
142
|
+
spinner2.stop("Could not create initial commit");
|
|
143
|
+
}
|
|
136
144
|
success(pc2.bold(`Project "${projectName}" created!`));
|
|
137
145
|
console.log(`
|
|
138
146
|
${pc2.dim("Next steps:")}`);
|
|
@@ -143,13 +151,13 @@ async function scaffold(projectName, skipInstall) {
|
|
|
143
151
|
console.log(` ${pc2.dim("DATABASE_URL")} \u2014 from supabase.com > Project Settings > Database`);
|
|
144
152
|
console.log(` ${pc2.dim("AI_GATEWAY_URL")} \u2014 Vercel AI Gateway URL`);
|
|
145
153
|
console.log(` ${pc2.dim("MINIMAX_API_KEY")} \u2014 from minimaxi.chat`);
|
|
146
|
-
console.log(` ${pc2.cyan("
|
|
154
|
+
console.log(` ${pc2.cyan("pnpm dev")}
|
|
147
155
|
`);
|
|
148
156
|
}
|
|
149
157
|
|
|
150
158
|
// src/index.ts
|
|
151
159
|
var program = new Command();
|
|
152
|
-
program.name("nextjs-hackathon-stack").description("Scaffold a full-stack Next.js 15 hackathon starter").version("0.1.0").argument("[project-name]", "Name of the project to create").option("--skip-install", "Skip
|
|
160
|
+
program.name("nextjs-hackathon-stack").description("Scaffold a full-stack Next.js 15 hackathon starter").version("0.1.0").argument("[project-name]", "Name of the project to create").option("--skip-install", "Skip pnpm install and shadcn/ui init", false).action(async (projectName, opts) => {
|
|
153
161
|
try {
|
|
154
162
|
const options = await runCli(projectName, opts.skipInstall);
|
|
155
163
|
await scaffold(options.projectName, options.skipInstall);
|
package/package.json
CHANGED
|
@@ -27,7 +27,7 @@ readonly: true
|
|
|
27
27
|
- [ ] `.env.example` has no real values
|
|
28
28
|
|
|
29
29
|
### Dependencies
|
|
30
|
-
- [ ] Run `
|
|
30
|
+
- [ ] Run `pnpm audit` — report Critical/High findings
|
|
31
31
|
- [ ] Review new dependencies for malicious packages
|
|
32
32
|
|
|
33
33
|
### Headers & Cookies
|
|
@@ -11,7 +11,7 @@ readonly: false
|
|
|
11
11
|
1. **RED** — write failing test that describes the desired behavior
|
|
12
12
|
2. **GREEN** — write minimum code to make test pass
|
|
13
13
|
3. **REFACTOR** — clean up while keeping tests green
|
|
14
|
-
4. **VERIFY** — run `
|
|
14
|
+
4. **VERIFY** — run `pnpm test:coverage` and confirm 100%
|
|
15
15
|
|
|
16
16
|
## AAA Pattern (Arrange-Act-Assert)
|
|
17
17
|
|
|
@@ -56,7 +56,7 @@ statements: 100%
|
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
After every change:
|
|
59
|
-
1. Run `
|
|
59
|
+
1. Run `pnpm test:coverage`
|
|
60
60
|
2. If below 100%, add missing tests
|
|
61
61
|
3. Never mark work complete without full coverage
|
|
62
62
|
|
|
@@ -12,7 +12,7 @@ alwaysApply: true
|
|
|
12
12
|
4. **XSS** — never use `dangerouslySetInnerHTML`, escape user input
|
|
13
13
|
5. **Broken Access Control** — RLS on all tables, auth check in all protected routes
|
|
14
14
|
6. **Security Misconfiguration** — CSP, HSTS, X-Frame-Options in `next.config.ts`
|
|
15
|
-
7. **Insecure Dependencies** — run `
|
|
15
|
+
7. **Insecure Dependencies** — run `pnpm audit` regularly
|
|
16
16
|
8. **SSRF** — validate URLs before fetch
|
|
17
17
|
|
|
18
18
|
## Environment Variables
|
|
@@ -28,22 +28,22 @@ Write ALL test files first:
|
|
|
28
28
|
- `__tests__/use-<feature>.test.ts` — hook tests
|
|
29
29
|
- `__tests__/<action>.test.ts` — action tests
|
|
30
30
|
|
|
31
|
-
Run `
|
|
31
|
+
Run `pnpm test:unit` — all tests must FAIL (RED).
|
|
32
32
|
|
|
33
33
|
### 4. TDD: GREEN Phase
|
|
34
34
|
Implement minimum code to pass each test:
|
|
35
35
|
- Components → actions → hooks → API routes
|
|
36
36
|
|
|
37
|
-
Run `
|
|
37
|
+
Run `pnpm test:unit` — all tests must PASS (GREEN).
|
|
38
38
|
|
|
39
39
|
### 5. Refactor
|
|
40
40
|
Clean up while keeping tests green.
|
|
41
41
|
|
|
42
42
|
### 6. Verify
|
|
43
43
|
```bash
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
pnpm test:coverage # Must show 100%
|
|
45
|
+
pnpm lint # Must pass with 0 warnings
|
|
46
|
+
pnpm typecheck # Must pass with 0 errors
|
|
47
47
|
```
|
|
48
48
|
|
|
49
49
|
## Guardrails
|
package/template/.env.example
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# =============================================================================
|
|
2
|
-
# REQUIRED — fill these in before running
|
|
2
|
+
# REQUIRED — fill these in before running pnpm dev
|
|
3
3
|
# =============================================================================
|
|
4
4
|
|
|
5
5
|
# Supabase — https://supabase.com > Project Settings > API
|
package/template/README.md
CHANGED
|
@@ -39,28 +39,28 @@ AI_GATEWAY_URL=https://gateway.ai.vercel.app/v1/your-team-id/your-gateway-id
|
|
|
39
39
|
### 2. Run the dev server
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
|
-
|
|
42
|
+
pnpm dev
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
### 3. Apply database migrations
|
|
46
46
|
|
|
47
47
|
```bash
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
pnpm db:generate
|
|
49
|
+
pnpm db:migrate
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
## Scripts
|
|
53
53
|
|
|
54
54
|
```bash
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
55
|
+
pnpm dev # Start dev server
|
|
56
|
+
pnpm build # Production build
|
|
57
|
+
pnpm lint # Lint (0 warnings allowed)
|
|
58
|
+
pnpm typecheck # TypeScript check
|
|
59
|
+
pnpm test # Unit tests
|
|
60
|
+
pnpm test:coverage # Tests with coverage (100% required)
|
|
61
|
+
pnpm test:e2e # Playwright e2e tests
|
|
62
|
+
pnpm db:generate # Generate Drizzle migrations
|
|
63
|
+
pnpm db:migrate # Apply migrations
|
|
64
64
|
```
|
|
65
65
|
|
|
66
66
|
## Environment Variables
|
|
@@ -5,10 +5,10 @@ import { useForm } from "react-hook-form";
|
|
|
5
5
|
import { zodResolver } from "@hookform/resolvers/zod";
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
import { loginAction, type LoginActionState } from "../actions/login.action";
|
|
8
|
-
import { Button } from "@/components/ui/button";
|
|
9
|
-
import { Input } from "@/components/ui/input";
|
|
10
|
-
import { Label } from "@/components/ui/label";
|
|
11
|
-
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card";
|
|
8
|
+
import { Button } from "@/shared/components/ui/button";
|
|
9
|
+
import { Input } from "@/shared/components/ui/input";
|
|
10
|
+
import { Label } from "@/shared/components/ui/label";
|
|
11
|
+
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/shared/components/ui/card";
|
|
12
12
|
|
|
13
13
|
const schema = z.object({
|
|
14
14
|
email: z.string().email("Invalid email"),
|