stackfit 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +170 -2
- package/bin/stackfit.mjs +124 -0
- package/package.json +42 -4
- package/schemas/project-config.schema.json +71 -0
- package/schemas/skill-sources.schema.json +97 -0
- package/schemas/stackfit.local.schema.json +132 -0
- package/schemas/stackfit.schema.json +110 -0
- package/src/audit.mjs +87 -0
- package/src/catalog.mjs +115 -0
- package/src/detect.mjs +110 -0
- package/src/projects.mjs +117 -0
- package/src/refresh.mjs +64 -0
- package/src/render.mjs +93 -0
- package/src/report.mjs +57 -0
- package/src/scaffold.mjs +88 -0
- package/src/sync.mjs +279 -0
- package/starter/.env.example +10 -0
- package/starter/README.md +12 -0
- package/starter/gitignore +4 -0
- package/starter/rules/defaults.mdc +11 -0
- package/starter/skill-sources.json +310 -0
- package/starter/skills/next-server-security/SKILL.md +63 -0
- package/starter/skills/playwright-e2e-testing/SKILL.md +34 -0
- package/starter/stackfit.json +169 -0
- package/starter/stackfit.local.example.json +20 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://unpkg.com/stackfit/schemas/skill-sources.schema.json",
|
|
3
|
+
"schemaVersion": 2,
|
|
4
|
+
"skills": {
|
|
5
|
+
"animation-vocabulary": {
|
|
6
|
+
"kind": "external",
|
|
7
|
+
"source": {
|
|
8
|
+
"repository": "https://github.com/emilkowalski/skills.git",
|
|
9
|
+
"path": "skills/animation-vocabulary"
|
|
10
|
+
},
|
|
11
|
+
"reviewed": "2026-10-26"
|
|
12
|
+
},
|
|
13
|
+
"apple-design": {
|
|
14
|
+
"kind": "external",
|
|
15
|
+
"source": {
|
|
16
|
+
"repository": "https://github.com/emilkowalski/skills.git",
|
|
17
|
+
"path": "skills/apple-design"
|
|
18
|
+
},
|
|
19
|
+
"reviewed": "2026-10-26"
|
|
20
|
+
},
|
|
21
|
+
"baseline-ui": {
|
|
22
|
+
"kind": "external",
|
|
23
|
+
"source": {
|
|
24
|
+
"repository": "https://github.com/ibelick/ui-skills.git",
|
|
25
|
+
"path": "skills/baseline-ui"
|
|
26
|
+
},
|
|
27
|
+
"reviewed": "2026-10-26"
|
|
28
|
+
},
|
|
29
|
+
"emil-design-eng": {
|
|
30
|
+
"kind": "external",
|
|
31
|
+
"source": {
|
|
32
|
+
"repository": "https://github.com/emilkowalski/skills.git",
|
|
33
|
+
"path": "skills/emil-design-eng"
|
|
34
|
+
},
|
|
35
|
+
"reviewed": "2026-10-26"
|
|
36
|
+
},
|
|
37
|
+
"fixing-accessibility": {
|
|
38
|
+
"kind": "external",
|
|
39
|
+
"source": {
|
|
40
|
+
"repository": "https://github.com/ibelick/ui-skills.git",
|
|
41
|
+
"path": "skills/fixing-accessibility"
|
|
42
|
+
},
|
|
43
|
+
"reviewed": "2026-10-26"
|
|
44
|
+
},
|
|
45
|
+
"fixing-motion-performance": {
|
|
46
|
+
"kind": "external",
|
|
47
|
+
"source": {
|
|
48
|
+
"repository": "https://github.com/ibelick/ui-skills.git",
|
|
49
|
+
"path": "skills/fixing-motion-performance"
|
|
50
|
+
},
|
|
51
|
+
"reviewed": "2026-10-26"
|
|
52
|
+
},
|
|
53
|
+
"frontend-design": {
|
|
54
|
+
"kind": "external",
|
|
55
|
+
"source": {
|
|
56
|
+
"repository": "https://github.com/anthropics/skills.git",
|
|
57
|
+
"path": "skills/frontend-design"
|
|
58
|
+
},
|
|
59
|
+
"reviewed": "2026-10-26"
|
|
60
|
+
},
|
|
61
|
+
"grilling": {
|
|
62
|
+
"kind": "external",
|
|
63
|
+
"source": {
|
|
64
|
+
"repository": "https://github.com/mattpocock/skills.git",
|
|
65
|
+
"path": "skills/productivity/grilling"
|
|
66
|
+
},
|
|
67
|
+
"reviewed": "2026-10-26"
|
|
68
|
+
},
|
|
69
|
+
"improve": {
|
|
70
|
+
"kind": "external",
|
|
71
|
+
"source": {
|
|
72
|
+
"repository": "https://github.com/shadcn/improve.git",
|
|
73
|
+
"path": "skills/improve"
|
|
74
|
+
},
|
|
75
|
+
"reviewed": "2026-10-26"
|
|
76
|
+
},
|
|
77
|
+
"improve-animations": {
|
|
78
|
+
"kind": "external",
|
|
79
|
+
"source": {
|
|
80
|
+
"repository": "https://github.com/emilkowalski/skills.git",
|
|
81
|
+
"path": "skills/improve-animations"
|
|
82
|
+
},
|
|
83
|
+
"reviewed": "2026-10-26"
|
|
84
|
+
},
|
|
85
|
+
"interface-design": {
|
|
86
|
+
"kind": "external",
|
|
87
|
+
"source": {
|
|
88
|
+
"repository": "https://github.com/Dammyjay93/interface-design.git",
|
|
89
|
+
"path": ".claude/skills/interface-design"
|
|
90
|
+
},
|
|
91
|
+
"reviewed": "2026-10-26"
|
|
92
|
+
},
|
|
93
|
+
"make-interfaces-feel-better": {
|
|
94
|
+
"kind": "external",
|
|
95
|
+
"source": {
|
|
96
|
+
"repository": "https://github.com/jakubkrehel/make-interfaces-feel-better.git",
|
|
97
|
+
"path": "skills/make-interfaces-feel-better"
|
|
98
|
+
},
|
|
99
|
+
"reviewed": "2026-10-26"
|
|
100
|
+
},
|
|
101
|
+
"next-bundle-optimizer": {
|
|
102
|
+
"kind": "external",
|
|
103
|
+
"source": {
|
|
104
|
+
"repository": "https://github.com/vercel/next.js.git",
|
|
105
|
+
"path": "skills/next-bundle-optimizer"
|
|
106
|
+
},
|
|
107
|
+
"reviewed": "2026-10-26"
|
|
108
|
+
},
|
|
109
|
+
"next-cache-components-adoption": {
|
|
110
|
+
"kind": "external",
|
|
111
|
+
"source": {
|
|
112
|
+
"repository": "https://github.com/vercel/next.js.git",
|
|
113
|
+
"path": "skills/next-cache-components-adoption"
|
|
114
|
+
},
|
|
115
|
+
"reviewed": "2026-10-26",
|
|
116
|
+
"render": {
|
|
117
|
+
"frontmatter": {
|
|
118
|
+
"disable-model-invocation": true
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
"next-cache-components-optimizer": {
|
|
123
|
+
"kind": "external",
|
|
124
|
+
"source": {
|
|
125
|
+
"repository": "https://github.com/vercel/next.js.git",
|
|
126
|
+
"path": "skills/next-cache-components-optimizer"
|
|
127
|
+
},
|
|
128
|
+
"reviewed": "2026-10-26",
|
|
129
|
+
"render": {
|
|
130
|
+
"frontmatter": {
|
|
131
|
+
"disable-model-invocation": true
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
"next-dev-loop": {
|
|
136
|
+
"kind": "external",
|
|
137
|
+
"source": {
|
|
138
|
+
"repository": "https://github.com/vercel/next.js.git",
|
|
139
|
+
"path": "skills/next-dev-loop"
|
|
140
|
+
},
|
|
141
|
+
"reviewed": "2026-10-26"
|
|
142
|
+
},
|
|
143
|
+
"next-partial-prefetching-adoption": {
|
|
144
|
+
"kind": "external",
|
|
145
|
+
"source": {
|
|
146
|
+
"repository": "https://github.com/vercel/next.js.git",
|
|
147
|
+
"path": "skills/next-partial-prefetching-adoption"
|
|
148
|
+
},
|
|
149
|
+
"reviewed": "2026-10-26",
|
|
150
|
+
"render": {
|
|
151
|
+
"frontmatter": {
|
|
152
|
+
"disable-model-invocation": true
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
"next-partial-prefetching-optimizer": {
|
|
157
|
+
"kind": "external",
|
|
158
|
+
"source": {
|
|
159
|
+
"repository": "https://github.com/vercel/next.js.git",
|
|
160
|
+
"path": "skills/next-partial-prefetching-optimizer"
|
|
161
|
+
},
|
|
162
|
+
"reviewed": "2026-10-26",
|
|
163
|
+
"render": {
|
|
164
|
+
"frontmatter": {
|
|
165
|
+
"disable-model-invocation": true
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
"next-server-security": {
|
|
170
|
+
"kind": "custom",
|
|
171
|
+
"reviewed": "2026-10-26",
|
|
172
|
+
"note": "First-party stackfit starter skill."
|
|
173
|
+
},
|
|
174
|
+
"playwright-e2e-testing": {
|
|
175
|
+
"kind": "custom",
|
|
176
|
+
"reviewed": "2026-10-26",
|
|
177
|
+
"note": "First-party stackfit starter skill."
|
|
178
|
+
},
|
|
179
|
+
"react-doctor": {
|
|
180
|
+
"kind": "external",
|
|
181
|
+
"source": {
|
|
182
|
+
"repository": "https://github.com/millionco/react-doctor.git",
|
|
183
|
+
"path": "skills/react-doctor"
|
|
184
|
+
},
|
|
185
|
+
"reviewed": "2026-10-26"
|
|
186
|
+
},
|
|
187
|
+
"review-animations": {
|
|
188
|
+
"kind": "external",
|
|
189
|
+
"source": {
|
|
190
|
+
"repository": "https://github.com/emilkowalski/skills.git",
|
|
191
|
+
"path": "skills/review-animations"
|
|
192
|
+
},
|
|
193
|
+
"reviewed": "2026-10-26"
|
|
194
|
+
},
|
|
195
|
+
"shadcn": {
|
|
196
|
+
"kind": "external",
|
|
197
|
+
"source": {
|
|
198
|
+
"repository": "https://github.com/shadcn-ui/ui.git",
|
|
199
|
+
"path": "skills/shadcn"
|
|
200
|
+
},
|
|
201
|
+
"reviewed": "2026-10-26",
|
|
202
|
+
"render": {
|
|
203
|
+
"exclude": [
|
|
204
|
+
"evals/evals.json"
|
|
205
|
+
]
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
"stripe-best-practices": {
|
|
209
|
+
"kind": "external",
|
|
210
|
+
"source": {
|
|
211
|
+
"repository": "https://github.com/stripe/ai.git",
|
|
212
|
+
"path": "skills/stripe-best-practices"
|
|
213
|
+
},
|
|
214
|
+
"reviewed": "2026-10-26"
|
|
215
|
+
},
|
|
216
|
+
"stripe-projects": {
|
|
217
|
+
"kind": "external",
|
|
218
|
+
"source": {
|
|
219
|
+
"repository": "https://github.com/stripe/ai.git",
|
|
220
|
+
"path": "skills/stripe-projects"
|
|
221
|
+
},
|
|
222
|
+
"reviewed": "2026-10-26",
|
|
223
|
+
"render": {
|
|
224
|
+
"frontmatter": {
|
|
225
|
+
"disable-model-invocation": true
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
"ui-ux-pro-max": {
|
|
230
|
+
"kind": "external",
|
|
231
|
+
"source": {
|
|
232
|
+
"repository": "https://github.com/nextlevelbuilder/ui-ux-pro-max-skill.git",
|
|
233
|
+
"path": ".claude/skills/ui-ux-pro-max"
|
|
234
|
+
},
|
|
235
|
+
"reviewed": "2026-10-26"
|
|
236
|
+
},
|
|
237
|
+
"upgrade-stripe": {
|
|
238
|
+
"kind": "external",
|
|
239
|
+
"source": {
|
|
240
|
+
"repository": "https://github.com/stripe/ai.git",
|
|
241
|
+
"path": "skills/upgrade-stripe"
|
|
242
|
+
},
|
|
243
|
+
"reviewed": "2026-10-26",
|
|
244
|
+
"render": {
|
|
245
|
+
"frontmatter": {
|
|
246
|
+
"disable-model-invocation": true
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
"vercel-composition-patterns": {
|
|
251
|
+
"kind": "external",
|
|
252
|
+
"source": {
|
|
253
|
+
"repository": "https://github.com/vercel-labs/agent-skills.git",
|
|
254
|
+
"path": "skills/composition-patterns"
|
|
255
|
+
},
|
|
256
|
+
"reviewed": "2026-10-26",
|
|
257
|
+
"render": {
|
|
258
|
+
"exclude": [
|
|
259
|
+
"AGENTS.md",
|
|
260
|
+
"README.md",
|
|
261
|
+
"metadata.json"
|
|
262
|
+
]
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
"vercel-react-best-practices": {
|
|
266
|
+
"kind": "external",
|
|
267
|
+
"source": {
|
|
268
|
+
"repository": "https://github.com/vercel-labs/agent-skills.git",
|
|
269
|
+
"path": "skills/react-best-practices"
|
|
270
|
+
},
|
|
271
|
+
"reviewed": "2026-10-26",
|
|
272
|
+
"render": {
|
|
273
|
+
"exclude": [
|
|
274
|
+
"AGENTS.md",
|
|
275
|
+
"README.md",
|
|
276
|
+
"metadata.json"
|
|
277
|
+
]
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
"vercel-react-view-transitions": {
|
|
281
|
+
"kind": "external",
|
|
282
|
+
"source": {
|
|
283
|
+
"repository": "https://github.com/vercel-labs/agent-skills.git",
|
|
284
|
+
"path": "skills/react-view-transitions"
|
|
285
|
+
},
|
|
286
|
+
"reviewed": "2026-10-26",
|
|
287
|
+
"render": {
|
|
288
|
+
"exclude": [
|
|
289
|
+
"AGENTS.md",
|
|
290
|
+
"README.md",
|
|
291
|
+
"metadata.json"
|
|
292
|
+
],
|
|
293
|
+
"frontmatter": {
|
|
294
|
+
"disable-model-invocation": true
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
},
|
|
298
|
+
"web-design-guidelines": {
|
|
299
|
+
"kind": "external",
|
|
300
|
+
"source": {
|
|
301
|
+
"repository": "https://github.com/vercel-labs/agent-skills.git",
|
|
302
|
+
"path": "skills/web-design-guidelines"
|
|
303
|
+
},
|
|
304
|
+
"reviewed": "2026-10-26",
|
|
305
|
+
"render": {
|
|
306
|
+
"exclude": []
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: next-server-security
|
|
3
|
+
description: Next.js App Router server-side security - Server Actions as public endpoints, data access layer and DTOs, authz in proxy.ts vs at the data, Cache Components with user data, route handler CSRF, secrets and client-boundary leaks. Use when writing or reviewing Server Actions, route.ts, proxy/middleware, auth, data fetching, or caching of user-specific data.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Next.js server security
|
|
7
|
+
|
|
8
|
+
Next.js-specific failure modes that generic OWASP checklists miss. For the general OWASP pass, also use `owasp-security-check`. Canonical reference: https://nextjs.org/docs/app/guides/data-security.
|
|
9
|
+
|
|
10
|
+
## Entry points (audit every one)
|
|
11
|
+
|
|
12
|
+
| Entry point | Why it is public |
|
|
13
|
+
| --- | --- |
|
|
14
|
+
| Every exported function in a `"use server"` file that the app uses | Reachable by direct `POST`, not only through your UI. Encrypted action IDs and dead-code elimination reduce exposure; they are not access control. |
|
|
15
|
+
| Inline `"use server"` functions in components | Same. A page-level auth check or `redirect()` does **not** protect the actions defined on that page. |
|
|
16
|
+
| `route.ts` handlers | Plain HTTP. No built-in Origin check (unlike Server Actions). |
|
|
17
|
+
| `proxy.ts` (Next 16; `middleware.ts` before) | Runs on matched requests only and is easy to bypass or mis-match. |
|
|
18
|
+
| `[param]` segments, `searchParams`, headers, cookies | User input. |
|
|
19
|
+
|
|
20
|
+
## Rules
|
|
21
|
+
|
|
22
|
+
1. **Authorize at the data, not the route.** Put auth + authorization in a server-only data access layer (DAL): `import "server-only"`, a `cache()`d `getCurrentUser()`, then ownership checks before every read or write. `proxy.ts` is for optimistic redirects only. (CVE-2025-29927 let attackers skip middleware entirely with one header; apps that also checked in the DAL were safe.)
|
|
23
|
+
2. **Every Server Action re-verifies.** Inside the action (or the DAL function it calls): authenticate, authorize the specific resource (IDOR), then mutate. Identity comes from the session, never from an argument, a hidden input, or a `.bind()` value.
|
|
24
|
+
3. **Validate every action argument at runtime.** TypeScript types are erased; parse `FormData` and arguments with a schema (`z.safeParse` or the repo's validator) and return a typed error state instead of throwing raw errors.
|
|
25
|
+
4. **Return DTOs, not records.** Action return values and props passed to Client Components are serialized to the browser (RSC payload / HTML). Select only the fields the UI needs. Never pass a full ORM row, user object, or session to a `"use client"` component. For defense in depth enable `experimental.taint` and use `experimental_taintObjectReference` / `experimental_taintUniqueValue` on secrets and raw records.
|
|
26
|
+
5. **Secrets stay in the DAL.** Only server-only modules read `process.env` secrets and DB clients. Anything prefixed `NEXT_PUBLIC_` ships in the client bundle; never put keys there. Validate env at startup with a schema.
|
|
27
|
+
6. **Cache Components and user data.**
|
|
28
|
+
- `"use cache"` output is shared across users and requests. `cookies()`, `headers()`, and `searchParams` are not allowed inside it; pass values in as arguments, and they become part of the cache key.
|
|
29
|
+
- A cached function that takes `userId` returns that user's data to *any* caller who passes the id: authorize **before** calling it, outside the cache boundary.
|
|
30
|
+
- Per-user personalized results: `"use cache: private"` (never stored in a server cache across requests) or no cache.
|
|
31
|
+
- After a mutation, invalidate what you changed: `updateTag(tag)` inside the action for read-your-own-writes, `revalidateTag(tag, "max")` for stale-while-revalidate, or `revalidatePath`.
|
|
32
|
+
7. **Route handlers that mutate with cookie auth need CSRF protection.** Prefer Server Actions (Next checks `Origin` against `Host`). Otherwise verify the `Origin` header, require a non-simple content type or a CSRF token, and keep session cookies `SameSite=Lax` or stricter, `HttpOnly`, `Secure`. Behind a reverse proxy or alternate domain, set `serverActions.allowedOrigins` instead of disabling checks.
|
|
33
|
+
8. **No mutations during render.** Logging out, writing, or revalidating from a page because of a `searchParams` value is a GET side effect. Use an action.
|
|
34
|
+
9. **Redirects.** `redirect(searchParams.callbackUrl)` is an open redirect. Allow only same-origin relative paths (starts with `/`, not `//`).
|
|
35
|
+
10. **Headers.** Static security headers go in `next.config` `headers()`. A nonce-based CSP is generated in `proxy.ts` and forces dynamic rendering for those routes; choose that trade-off deliberately.
|
|
36
|
+
11. **Self-hosting multiple instances:** set a stable `NEXT_SERVER_ACTIONS_ENCRYPTION_KEY` so closure encryption works across instances. Encryption of closed-over values is not a reason to close over secrets.
|
|
37
|
+
12. **Rate-limit expensive actions** (email, signup, AI calls, uploads) by user and IP.
|
|
38
|
+
13. **Stay on the latest patch of your Next.js and React line.** RSC protocol bugs are critical (React2Shell, CVE-2025-55182, was unauthenticated RCE in Next 15.x/16.0 App Router apps). Check the repo's audit command and https://github.com/vercel/next.js/security/advisories when touching dependencies.
|
|
39
|
+
|
|
40
|
+
## Server Action shape
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
// app/posts/actions.ts
|
|
44
|
+
"use server";
|
|
45
|
+
|
|
46
|
+
import { z } from "zod";
|
|
47
|
+
import { updateTag } from "next/cache";
|
|
48
|
+
import { deletePost } from "@/data/posts"; // server-only DAL: auth + ownership inside
|
|
49
|
+
|
|
50
|
+
const Input = z.object({ postId: z.string().uuid() });
|
|
51
|
+
|
|
52
|
+
export async function deletePostAction(_prev: unknown, formData: FormData) {
|
|
53
|
+
const parsed = Input.safeParse({ postId: formData.get("postId") });
|
|
54
|
+
if (!parsed.success) return { ok: false as const, error: "Invalid input" };
|
|
55
|
+
await deletePost(parsed.data.postId); // throws/returns forbidden if not the owner
|
|
56
|
+
updateTag(`posts`);
|
|
57
|
+
return { ok: true as const }; // minimal result, no DB row
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Review output
|
|
62
|
+
|
|
63
|
+
For each finding: entry point, file:line, what an attacker sends, impact, fix. Check the repo's actual auth library and DAL location first; do not assume paths.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: playwright-e2e-testing
|
|
3
|
+
description: Write, fix, or review Playwright end-to-end tests, especially for Next.js apps - locators, auth via storageState, flaky waits, server-side fetch mocking, CI against a production build. Use for *.spec.ts / e2e/ / playwright.config changes or flaky browser tests. For unit and component tests use frontend-testing.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Playwright E2E
|
|
7
|
+
|
|
8
|
+
## Start from repository evidence
|
|
9
|
+
|
|
10
|
+
1. Read `AGENTS.md` and the testing page linked from `docs/agent/index.md`.
|
|
11
|
+
2. Read `playwright.config.*` (`testDir`, `projects`, `webServer`, `use.baseURL`, `testIdAttribute`), existing fixtures, page objects, and the auth setup project.
|
|
12
|
+
3. Use the repo's package manager and scripts. Match existing file names, tags, and fixture style; do not introduce page objects or new fixtures if the suite does not use them.
|
|
13
|
+
|
|
14
|
+
## Rules that prevent flaky tests
|
|
15
|
+
|
|
16
|
+
- **Locators:** `getByRole` with `name`, then `getByLabel`, `getByText`, then `getByTestId` (respect a configured `testIdAttribute`). No CSS chains, XPath, or `.nth()` on unstable lists.
|
|
17
|
+
- **Waiting:** only web-first assertions (`await expect(locator).toBeVisible()`, `toHaveURL`, `toHaveText`). Never `waitForTimeout`. Avoid `waitForLoadState("networkidle")`: Next.js prefetching and streaming keep the network busy. After navigation use `await expect(page).toHaveURL(...)` or `page.waitForURL`.
|
|
18
|
+
- **Hydration:** a click on a server-rendered button before hydration can be lost. Assert the result of the interaction (a visible state change), not just that the click ran; if the suite has a hydration-ready helper, use it.
|
|
19
|
+
- **Server Actions / forms:** assert on the UI that the action produces (toast, updated row, redirect URL), not on internal network calls.
|
|
20
|
+
- **Isolation:** every test creates the data it needs (API or DB fixture) and can run in parallel and in any order. No dependence on a previous test.
|
|
21
|
+
- **Auth:** log in once in a setup project and save `storageState` per role; tests reuse it. Do not log in through the UI in every test.
|
|
22
|
+
|
|
23
|
+
## Next.js specifics
|
|
24
|
+
|
|
25
|
+
- **CI runs against a production build** (`next build` then `next start`) through `webServer`; `next dev` compiles routes on first hit and causes timeouts. Use `reuseExistingServer: !process.env.CI` locally.
|
|
26
|
+
- **`page.route` only intercepts browser requests.** Fetches made by Server Components, Route Handlers, or Server Actions run on the server and are not intercepted. Point the server at a test backend/database via env, or use the repo's existing server-side mocking (MSW in the server, or `next/experimental/testmode/playwright` if already set up).
|
|
27
|
+
- **Instant navigation / static shell guards** under Cache Components: use the `next-cache-components-optimizer` skill (`@next/playwright` `instant()`).
|
|
28
|
+
- **Visual snapshots:** fixed viewport, `animations: "disabled"`, mask dynamic regions (dates, avatars). Snapshots are per OS/browser; only update them on the platform CI uses.
|
|
29
|
+
|
|
30
|
+
## Run and debug
|
|
31
|
+
|
|
32
|
+
- Narrow first: `<pm> playwright test <file> -g "<title>" --project=chromium`.
|
|
33
|
+
- Flaky: `--repeat-each=10 --workers=1`, then `--trace on` and `playwright show-trace`.
|
|
34
|
+
- Report the exact command, pass/fail, and any test you could not run (for example missing env or seed data).
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://unpkg.com/stackfit/schemas/stackfit.schema.json",
|
|
3
|
+
"schemaVersion": 3,
|
|
4
|
+
"skills": [
|
|
5
|
+
"animation-vocabulary",
|
|
6
|
+
"apple-design",
|
|
7
|
+
"baseline-ui",
|
|
8
|
+
"emil-design-eng",
|
|
9
|
+
"fixing-accessibility",
|
|
10
|
+
"fixing-motion-performance",
|
|
11
|
+
"frontend-design",
|
|
12
|
+
"grilling",
|
|
13
|
+
"improve",
|
|
14
|
+
"improve-animations",
|
|
15
|
+
"interface-design",
|
|
16
|
+
"make-interfaces-feel-better",
|
|
17
|
+
"next-bundle-optimizer",
|
|
18
|
+
"next-cache-components-adoption",
|
|
19
|
+
"next-cache-components-optimizer",
|
|
20
|
+
"next-dev-loop",
|
|
21
|
+
"next-partial-prefetching-adoption",
|
|
22
|
+
"next-partial-prefetching-optimizer",
|
|
23
|
+
"next-server-security",
|
|
24
|
+
"playwright-e2e-testing",
|
|
25
|
+
"react-doctor",
|
|
26
|
+
"review-animations",
|
|
27
|
+
"shadcn",
|
|
28
|
+
"stripe-best-practices",
|
|
29
|
+
"stripe-projects",
|
|
30
|
+
"ui-ux-pro-max",
|
|
31
|
+
"upgrade-stripe",
|
|
32
|
+
"vercel-composition-patterns",
|
|
33
|
+
"vercel-react-best-practices",
|
|
34
|
+
"vercel-react-view-transitions",
|
|
35
|
+
"web-design-guidelines"
|
|
36
|
+
],
|
|
37
|
+
"packs": {
|
|
38
|
+
"core": {
|
|
39
|
+
"description": "Every repository: codebase review planning and decision grilling.",
|
|
40
|
+
"always": true,
|
|
41
|
+
"skills": [
|
|
42
|
+
"grilling",
|
|
43
|
+
"improve"
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
"react": {
|
|
47
|
+
"description": "React performance, composition, and diagnostics.",
|
|
48
|
+
"detect": {
|
|
49
|
+
"dependencies": [
|
|
50
|
+
"react"
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
"skills": [
|
|
54
|
+
"react-doctor",
|
|
55
|
+
"vercel-composition-patterns",
|
|
56
|
+
"vercel-react-best-practices"
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
"nextjs": {
|
|
60
|
+
"description": "Next.js App Router: server security, runtime verification, bundle and navigation workflows (manual-only ones cost no context). Framework reference knowledge comes from node_modules/next/dist/docs (16.2+).",
|
|
61
|
+
"detect": {
|
|
62
|
+
"dependencies": [
|
|
63
|
+
"next"
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
"skills": [
|
|
67
|
+
"next-bundle-optimizer",
|
|
68
|
+
"next-cache-components-adoption",
|
|
69
|
+
"next-cache-components-optimizer",
|
|
70
|
+
"next-dev-loop",
|
|
71
|
+
"next-partial-prefetching-adoption",
|
|
72
|
+
"next-partial-prefetching-optimizer",
|
|
73
|
+
"next-server-security",
|
|
74
|
+
"vercel-react-view-transitions"
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
"e2e": {
|
|
78
|
+
"description": "Playwright browser tests.",
|
|
79
|
+
"detect": {
|
|
80
|
+
"dependencies": [
|
|
81
|
+
"@playwright/test",
|
|
82
|
+
"playwright"
|
|
83
|
+
]
|
|
84
|
+
},
|
|
85
|
+
"skills": [
|
|
86
|
+
"playwright-e2e-testing"
|
|
87
|
+
]
|
|
88
|
+
},
|
|
89
|
+
"ui": {
|
|
90
|
+
"description": "Interface design, accessibility, and polish.",
|
|
91
|
+
"detect": {
|
|
92
|
+
"dependencies": [
|
|
93
|
+
"react-dom",
|
|
94
|
+
"vue",
|
|
95
|
+
"svelte",
|
|
96
|
+
"tailwindcss",
|
|
97
|
+
"@angular/core",
|
|
98
|
+
"solid-js"
|
|
99
|
+
]
|
|
100
|
+
},
|
|
101
|
+
"skills": [
|
|
102
|
+
"baseline-ui",
|
|
103
|
+
"fixing-accessibility",
|
|
104
|
+
"frontend-design",
|
|
105
|
+
"interface-design",
|
|
106
|
+
"make-interfaces-feel-better",
|
|
107
|
+
"web-design-guidelines"
|
|
108
|
+
]
|
|
109
|
+
},
|
|
110
|
+
"shadcn": {
|
|
111
|
+
"description": "shadcn/ui components and registries.",
|
|
112
|
+
"detect": {
|
|
113
|
+
"files": [
|
|
114
|
+
"components.json"
|
|
115
|
+
]
|
|
116
|
+
},
|
|
117
|
+
"skills": [
|
|
118
|
+
"shadcn"
|
|
119
|
+
]
|
|
120
|
+
},
|
|
121
|
+
"motion": {
|
|
122
|
+
"description": "Animation craft, review, and performance. Auto-detected from motion libraries; add it by hand for CSS-only motion work.",
|
|
123
|
+
"detect": {
|
|
124
|
+
"dependencies": [
|
|
125
|
+
"motion",
|
|
126
|
+
"framer-motion",
|
|
127
|
+
"gsap",
|
|
128
|
+
"@react-spring/web"
|
|
129
|
+
]
|
|
130
|
+
},
|
|
131
|
+
"skills": [
|
|
132
|
+
"animation-vocabulary",
|
|
133
|
+
"apple-design",
|
|
134
|
+
"emil-design-eng",
|
|
135
|
+
"fixing-motion-performance",
|
|
136
|
+
"improve-animations",
|
|
137
|
+
"review-animations"
|
|
138
|
+
]
|
|
139
|
+
},
|
|
140
|
+
"design-research": {
|
|
141
|
+
"description": "Large searchable UI/UX database (about 1.7 MB). Opt-in only.",
|
|
142
|
+
"skills": [
|
|
143
|
+
"ui-ux-pro-max"
|
|
144
|
+
]
|
|
145
|
+
},
|
|
146
|
+
"stripe": {
|
|
147
|
+
"description": "Stripe integrations and upgrades.",
|
|
148
|
+
"detect": {
|
|
149
|
+
"dependencies": [
|
|
150
|
+
"stripe",
|
|
151
|
+
"@stripe/stripe-js",
|
|
152
|
+
"@stripe/react-stripe-js"
|
|
153
|
+
]
|
|
154
|
+
},
|
|
155
|
+
"skills": [
|
|
156
|
+
"stripe-best-practices",
|
|
157
|
+
"stripe-projects",
|
|
158
|
+
"upgrade-stripe"
|
|
159
|
+
]
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
"adapters": {
|
|
163
|
+
"agents": [],
|
|
164
|
+
"commands": [],
|
|
165
|
+
"rules": [
|
|
166
|
+
"defaults.mdc"
|
|
167
|
+
]
|
|
168
|
+
}
|
|
169
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://unpkg.com/stackfit/schemas/stackfit.local.schema.json",
|
|
3
|
+
"schemaVersion": 1,
|
|
4
|
+
"machines": [
|
|
5
|
+
{
|
|
6
|
+
"id": "mac",
|
|
7
|
+
"match": { "platform": "darwin" },
|
|
8
|
+
"roots": ["~/code"],
|
|
9
|
+
"projects": [
|
|
10
|
+
"my-next-app",
|
|
11
|
+
{ "name": "client-site", "scaffold": false, "packs": ["motion"] }
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"id": "windows",
|
|
16
|
+
"match": { "platform": "win32" },
|
|
17
|
+
"roots": ["C:/Users/you/code"]
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|