Add Claude commands, remote-exec script, and skills
- commands/remote.md for remote execution - remote-exec.sh script - skills: claudeception, kubernetes-latest-tag-image-pull, react-hooks-order-early-return
This commit is contained in:
parent
09631b3530
commit
fde360dbdc
44 changed files with 3053 additions and 0 deletions
|
|
@ -0,0 +1,118 @@
|
|||
---
|
||||
name: nextjs-server-side-error-debugging
|
||||
description: |
|
||||
Debug getServerSideProps and getStaticProps errors in Next.js. Use when:
|
||||
(1) Page shows generic error but browser console is empty, (2) API routes
|
||||
return 500 with no details, (3) Server-side code fails silently, (4) Error
|
||||
only occurs on refresh not client navigation. Check terminal/server logs
|
||||
instead of browser for actual error messages.
|
||||
author: Claude Code
|
||||
version: 1.0.0
|
||||
date: 2024-01-15
|
||||
---
|
||||
|
||||
# Next.js Server-Side Error Debugging
|
||||
|
||||
## Problem
|
||||
|
||||
Server-side errors in Next.js don't appear in the browser console, making debugging
|
||||
frustrating when you're looking in the wrong place. The browser shows a generic error
|
||||
page or 500 status, but no stack trace or useful error information appears in DevTools.
|
||||
|
||||
## Context / Trigger Conditions
|
||||
|
||||
This skill applies when:
|
||||
|
||||
- Page displays "Internal Server Error" or custom error page
|
||||
- Browser console shows no errors, or only a generic fetch failure
|
||||
- You're using `getServerSideProps`, `getStaticProps`, or API routes
|
||||
- Error only occurs on page refresh or direct navigation (not client-side transitions)
|
||||
- The error is intermittent and hard to reproduce in the browser
|
||||
|
||||
Common misleading symptoms:
|
||||
- "Unhandled Runtime Error" modal that doesn't show the real cause
|
||||
- Network tab shows 500 but response body is empty or generic
|
||||
- Error disappears when you add console.log (timing issue)
|
||||
|
||||
## Solution
|
||||
|
||||
### Step 1: Check the Terminal
|
||||
|
||||
The actual error with full stack trace appears in the terminal where `npm run dev`
|
||||
or `next dev` is running. This is the **first place to look**.
|
||||
|
||||
```bash
|
||||
# If you don't see the terminal, find the process
|
||||
ps aux | grep next
|
||||
# Or restart with visible output
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Step 2: Add Explicit Error Handling
|
||||
|
||||
For persistent debugging, wrap server-side code with try-catch:
|
||||
|
||||
```typescript
|
||||
export async function getServerSideProps(context) {
|
||||
try {
|
||||
const data = await fetchSomething();
|
||||
return { props: { data } };
|
||||
} catch (error) {
|
||||
console.error('getServerSideProps error:', error);
|
||||
// Return error state instead of throwing
|
||||
return { props: { error: error.message } };
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: For Production Errors
|
||||
|
||||
Check your hosting provider's logs:
|
||||
- **Vercel**: Dashboard → Project → Logs (Functions tab)
|
||||
- **AWS**: CloudWatch Logs
|
||||
- **Netlify**: Functions tab in dashboard
|
||||
- **Self-hosted**: Check your Node.js process logs
|
||||
|
||||
### Step 4: Common Causes
|
||||
|
||||
1. **Environment variables**: Missing in production but present locally
|
||||
2. **Database connections**: Connection string issues, cold starts
|
||||
3. **Import errors**: Server-only code accidentally imported on client
|
||||
4. **Async/await**: Missing await on async operations
|
||||
5. **JSON serialization**: Objects that can't be serialized (dates, functions)
|
||||
|
||||
## Verification
|
||||
|
||||
After checking the terminal, you should see:
|
||||
- Full stack trace with file name and line number
|
||||
- The actual error message (not generic 500)
|
||||
- Variable values if you added console.log statements
|
||||
|
||||
## Example
|
||||
|
||||
**Symptom**: User reports page shows "Internal Server Error" after clicking a link.
|
||||
|
||||
**Investigation**:
|
||||
1. Open browser DevTools → Console: Empty
|
||||
2. Network tab shows: `GET /dashboard → 500`
|
||||
3. Check terminal running `npm run dev`:
|
||||
|
||||
```
|
||||
Error: Cannot read property 'id' of undefined
|
||||
at getServerSideProps (/app/pages/dashboard.tsx:15:25)
|
||||
at renderToHTML (/app/node_modules/next/dist/server/render.js:428:22)
|
||||
```
|
||||
|
||||
**Cause found**: Database query returned `null` instead of user object.
|
||||
|
||||
## Notes
|
||||
|
||||
- In development, Next.js sometimes shows an error overlay, but it often has less
|
||||
detail than the terminal output
|
||||
- `reactStrictMode: true` in `next.config.js` causes double-execution of server
|
||||
functions in development, which can make debugging confusing
|
||||
- For API routes, the error appears in the same terminal as page errors
|
||||
- Client-side errors (in useEffect, event handlers) DO appear in browser console—
|
||||
this skill only applies to server-side code
|
||||
- If using `next start` (production mode locally), errors may be less verbose;
|
||||
check `NODE_ENV` and consider adding custom error logging
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
---
|
||||
name: prisma-connection-pool-exhaustion
|
||||
description: |
|
||||
Fix Prisma "Too many connections" and connection pool exhaustion errors in
|
||||
serverless environments (Vercel, AWS Lambda, Netlify). Use when: (1) Error
|
||||
"P2024: Timed out fetching a new connection from the pool", (2) PostgreSQL
|
||||
"too many connections for role", (3) Database works locally but fails in
|
||||
production serverless, (4) Intermittent database timeouts under load.
|
||||
author: Claude Code
|
||||
version: 1.0.0
|
||||
date: 2024-02-20
|
||||
---
|
||||
|
||||
# Prisma Connection Pool Exhaustion in Serverless
|
||||
|
||||
## Problem
|
||||
|
||||
Serverless functions create a new Prisma client instance on each cold start. Each
|
||||
instance opens multiple database connections (default: 5 per instance). With many
|
||||
concurrent requests, this quickly exhausts the database's connection limit (often
|
||||
20-100 for managed databases).
|
||||
|
||||
## Context / Trigger Conditions
|
||||
|
||||
This skill applies when you see:
|
||||
|
||||
- `P2024: Timed out fetching a new connection from the connection pool`
|
||||
- PostgreSQL: `FATAL: too many connections for role "username"`
|
||||
- MySQL: `Too many connections`
|
||||
- Works fine locally with `npm run dev` but fails in production
|
||||
- Errors appear during traffic spikes, then resolve
|
||||
- Database dashboard shows connections at or near limit
|
||||
|
||||
Environment indicators:
|
||||
- Deploying to Vercel, AWS Lambda, Netlify Functions, or similar
|
||||
- Using Prisma with PostgreSQL, MySQL, or another connection-based database
|
||||
- Database is managed (PlanetScale, Supabase, Neon, RDS, etc.)
|
||||
|
||||
## Solution
|
||||
|
||||
### Step 1: Use Connection Pooling Service
|
||||
|
||||
The recommended solution is to use a connection pooler like PgBouncer or Prisma
|
||||
Accelerate, which sits between your serverless functions and the database.
|
||||
|
||||
**For Supabase:**
|
||||
```
|
||||
# .env
|
||||
# Use the pooled connection string (port 6543, not 5432)
|
||||
DATABASE_URL="postgresql://user:pass@db.xxx.supabase.co:6543/postgres?pgbouncer=true"
|
||||
```
|
||||
|
||||
**For Neon:**
|
||||
```
|
||||
# .env
|
||||
DATABASE_URL="postgresql://user:pass@ep-xxx.us-east-2.aws.neon.tech/dbname?sslmode=require"
|
||||
# Neon has built-in pooling
|
||||
```
|
||||
|
||||
**For Prisma Accelerate:**
|
||||
```bash
|
||||
npx prisma generate --accelerate
|
||||
```
|
||||
|
||||
### Step 2: Configure Prisma Connection Limits
|
||||
|
||||
In your `schema.prisma`:
|
||||
|
||||
```prisma
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
// Limit connections per Prisma instance
|
||||
relationMode = "prisma"
|
||||
}
|
||||
```
|
||||
|
||||
In your connection URL or Prisma client:
|
||||
|
||||
```typescript
|
||||
// lib/prisma.ts
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
|
||||
const globalForPrisma = global as unknown as { prisma: PrismaClient }
|
||||
|
||||
export const prisma = globalForPrisma.prisma || new PrismaClient({
|
||||
datasources: {
|
||||
db: {
|
||||
url: process.env.DATABASE_URL + '?connection_limit=1'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma
|
||||
```
|
||||
|
||||
### Step 3: Singleton Pattern (Development)
|
||||
|
||||
Prevent hot-reload from creating new clients:
|
||||
|
||||
```typescript
|
||||
// lib/prisma.ts
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
|
||||
const globalForPrisma = globalThis as unknown as {
|
||||
prisma: PrismaClient | undefined
|
||||
}
|
||||
|
||||
export const prisma = globalForPrisma.prisma ?? new PrismaClient()
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma
|
||||
```
|
||||
|
||||
### Step 4: URL Parameters
|
||||
|
||||
Add these to your connection string:
|
||||
|
||||
```
|
||||
?connection_limit=1&pool_timeout=20&connect_timeout=10
|
||||
```
|
||||
|
||||
- `connection_limit=1`: One connection per serverless instance
|
||||
- `pool_timeout=20`: Wait up to 20s for available connection
|
||||
- `connect_timeout=10`: Fail fast if can't connect in 10s
|
||||
|
||||
## Verification
|
||||
|
||||
After applying fixes:
|
||||
|
||||
1. Deploy to production
|
||||
2. Run a load test: `npx autocannon -c 100 -d 30 https://your-app.com/api/test`
|
||||
3. Check database dashboard—connections should stay within limits
|
||||
4. No more P2024 errors in logs
|
||||
|
||||
## Example
|
||||
|
||||
**Before** (error under load):
|
||||
```
|
||||
[ERROR] PrismaClientKnownRequestError:
|
||||
Invalid `prisma.user.findMany()` invocation:
|
||||
Timed out fetching a new connection from the connection pool.
|
||||
```
|
||||
|
||||
**After** (with connection pooling):
|
||||
```
|
||||
# Using Supabase pooler URL
|
||||
DATABASE_URL="postgresql://...@db.xxx.supabase.co:6543/postgres?pgbouncer=true&connection_limit=1"
|
||||
```
|
||||
|
||||
Database connections stable at 10-15 even under heavy load.
|
||||
|
||||
## Notes
|
||||
|
||||
- Different managed databases have different pooling solutions—check your provider's docs
|
||||
- PlanetScale (MySQL) uses a different architecture and doesn't have this issue
|
||||
- `connection_limit=1` is aggressive; start there and increase if you see latency
|
||||
- The singleton pattern only helps in development; in production serverless, each
|
||||
instance is isolated
|
||||
- If using Prisma with Next.js API routes, each route invocation may be a separate
|
||||
serverless function
|
||||
- Consider Prisma Accelerate for built-in caching + pooling: https://www.prisma.io/accelerate
|
||||
|
|
@ -0,0 +1,237 @@
|
|||
---
|
||||
name: typescript-circular-dependency
|
||||
description: |
|
||||
Detect and resolve TypeScript/JavaScript circular import dependencies. Use when:
|
||||
(1) "Cannot access 'X' before initialization" at runtime, (2) Import returns
|
||||
undefined unexpectedly, (3) "ReferenceError: Cannot access X before initialization",
|
||||
(4) Type errors that disappear when you change import order, (5) Jest/Vitest tests
|
||||
fail with undefined imports that work in browser.
|
||||
author: Claude Code
|
||||
version: 1.0.0
|
||||
date: 2024-03-10
|
||||
---
|
||||
|
||||
# TypeScript Circular Dependency Detection and Resolution
|
||||
|
||||
## Problem
|
||||
|
||||
Circular dependencies occur when module A imports from module B, which imports
|
||||
(directly or indirectly) from module A. TypeScript compiles successfully, but at
|
||||
runtime, one of the imports evaluates to `undefined` because the module hasn't
|
||||
finished initializing yet.
|
||||
|
||||
## Context / Trigger Conditions
|
||||
|
||||
Common error messages:
|
||||
|
||||
```
|
||||
ReferenceError: Cannot access 'UserService' before initialization
|
||||
```
|
||||
|
||||
```
|
||||
TypeError: Cannot read properties of undefined (reading 'create')
|
||||
```
|
||||
|
||||
```
|
||||
TypeError: (0 , _service.doSomething) is not a function
|
||||
```
|
||||
|
||||
Symptoms that suggest circular imports:
|
||||
|
||||
- Import is `undefined` even though the export exists
|
||||
- Error only appears at runtime, not during TypeScript compilation
|
||||
- Moving an import statement changes which import is undefined
|
||||
- Tests fail but the app works (or vice versa)
|
||||
- Adding `console.log` at the top of a file changes behavior
|
||||
|
||||
## Solution
|
||||
|
||||
### Step 1: Detect the Cycle
|
||||
|
||||
Use a tool to visualize dependencies:
|
||||
|
||||
```bash
|
||||
# Install madge
|
||||
npm install -g madge
|
||||
|
||||
# Find circular dependencies
|
||||
madge --circular --extensions ts,tsx src/
|
||||
|
||||
# Generate visual graph
|
||||
madge --circular --image graph.svg src/
|
||||
```
|
||||
|
||||
Or use the TypeScript compiler:
|
||||
|
||||
```bash
|
||||
# Check for cycles (requires tsconfig setting)
|
||||
npx tsc --listFiles | head -50
|
||||
```
|
||||
|
||||
### Step 2: Identify the Pattern
|
||||
|
||||
Common circular dependency patterns:
|
||||
|
||||
**Pattern A: Service-to-Service**
|
||||
```
|
||||
services/userService.ts → services/orderService.ts → services/userService.ts
|
||||
```
|
||||
|
||||
**Pattern B: Type imports**
|
||||
```
|
||||
types/user.ts → types/order.ts → types/user.ts
|
||||
```
|
||||
|
||||
**Pattern C: Index barrel files**
|
||||
```
|
||||
components/index.ts → components/Button.tsx → components/index.ts
|
||||
```
|
||||
|
||||
### Step 3: Resolution Strategies
|
||||
|
||||
**Strategy 1: Extract Shared Dependencies**
|
||||
|
||||
Before:
|
||||
```typescript
|
||||
// userService.ts
|
||||
import { OrderService } from './orderService';
|
||||
export class UserService { ... }
|
||||
|
||||
// orderService.ts
|
||||
import { UserService } from './userService';
|
||||
export class OrderService { ... }
|
||||
```
|
||||
|
||||
After:
|
||||
```typescript
|
||||
// types/interfaces.ts (new file - no imports from services)
|
||||
export interface IUserService { ... }
|
||||
export interface IOrderService { ... }
|
||||
|
||||
// userService.ts
|
||||
import { IOrderService } from '../types/interfaces';
|
||||
export class UserService implements IUserService { ... }
|
||||
```
|
||||
|
||||
**Strategy 2: Dependency Injection**
|
||||
|
||||
```typescript
|
||||
// orderService.ts
|
||||
export class OrderService {
|
||||
constructor(private userService: IUserService) {}
|
||||
|
||||
// Instead of importing UserService directly
|
||||
}
|
||||
|
||||
// main.ts
|
||||
const userService = new UserService();
|
||||
const orderService = new OrderService(userService);
|
||||
```
|
||||
|
||||
**Strategy 3: Dynamic Imports**
|
||||
|
||||
```typescript
|
||||
// Only import when needed, not at module level
|
||||
async function processOrder() {
|
||||
const { UserService } = await import('./userService');
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
**Strategy 4: Use Type-Only Imports**
|
||||
|
||||
If you only need types (not values), use type-only imports:
|
||||
|
||||
```typescript
|
||||
// This doesn't create a runtime dependency
|
||||
import type { User } from './userService';
|
||||
```
|
||||
|
||||
**Strategy 5: Restructure Barrel Files**
|
||||
|
||||
Before (problematic):
|
||||
```typescript
|
||||
// components/index.ts
|
||||
export * from './Button';
|
||||
export * from './Modal'; // Modal imports Button from './index'
|
||||
```
|
||||
|
||||
After:
|
||||
```typescript
|
||||
// components/Modal.tsx
|
||||
import { Button } from './Button'; // Direct import, not from index
|
||||
```
|
||||
|
||||
### Step 4: Prevent Future Cycles
|
||||
|
||||
Add to your CI/build process:
|
||||
|
||||
```json
|
||||
// package.json
|
||||
{
|
||||
"scripts": {
|
||||
"check:circular": "madge --circular --extensions ts,tsx src/"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Or configure ESLint:
|
||||
|
||||
```javascript
|
||||
// .eslintrc.js
|
||||
module.exports = {
|
||||
plugins: ['import'],
|
||||
rules: {
|
||||
'import/no-cycle': ['error', { maxDepth: 10 }]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
1. Run `madge --circular src/` - should report no cycles
|
||||
2. Run your test suite - previously undefined imports should work
|
||||
3. Delete `node_modules` and reinstall - app should still work
|
||||
4. Build for production - no runtime errors
|
||||
|
||||
## Example
|
||||
|
||||
**Problem**: `OrderService` is undefined when imported in `UserService`
|
||||
|
||||
**Detection**:
|
||||
```bash
|
||||
$ madge --circular src/
|
||||
Circular dependencies found!
|
||||
src/services/userService.ts → src/services/orderService.ts → src/services/userService.ts
|
||||
```
|
||||
|
||||
**Fix**: Extract shared interface
|
||||
|
||||
```typescript
|
||||
// NEW: src/types/services.ts
|
||||
export interface IOrderService {
|
||||
createOrder(userId: string): Promise<Order>;
|
||||
}
|
||||
|
||||
// MODIFIED: src/services/userService.ts
|
||||
import type { IOrderService } from '../types/services';
|
||||
|
||||
export class UserService {
|
||||
constructor(private orderService: IOrderService) {}
|
||||
}
|
||||
|
||||
// MODIFIED: src/services/orderService.ts
|
||||
// No longer imports UserService
|
||||
export class OrderService implements IOrderService {
|
||||
async createOrder(userId: string): Promise<Order> { ... }
|
||||
}
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- TypeScript `import type` is your friend—it's erased at runtime and can't cause cycles
|
||||
- Barrel files (`index.ts`) are a common source of accidental cycles
|
||||
- The order of exports in a file can matter when there's a cycle
|
||||
- Jest/Vitest may handle module resolution differently than your bundler
|
||||
- Some bundlers (Webpack, Vite) have better cycle handling than others
|
||||
- `require()` can sometimes mask circular dependency issues that `import` exposes
|
||||
Loading…
Add table
Add a link
Reference in a new issue