diff --git a/README.md b/README.md index 8204dac5..53252c20 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,7 @@ By adding selected `.mdc` files to `.cursor/rules/`, you can use these rules dir ### Backend and Full-Stack +- [Anthropic Claude API (TypeScript, Next.js)](https://github.com/PatrickJS/awesome-cursorrules/blob/main/rules/anthropic-claude-api-typescript.mdc) - Claude API integration with streaming responses, tool use, model selection guide, and production-grade error handling with exponential backoff. - [Cloudflare Workers (Hono, Angular)](https://github.com/PatrickJS/awesome-cursorrules/blob/main/rules/cloudflare-workers-hono-angular-saas-cursorrules-prompt-file.mdc) - Full-stack SaaS applications on Cloudflare Workers with Hono APIs, Angular frontends, typed RPC, D1/Neon, and production observability. - [Convex Best Practices](https://github.com/PatrickJS/awesome-cursorrules/blob/main/rules/convex-cursorrules-prompt-file.mdc) - Convex development with best practices. - [Deno Integration](https://github.com/PatrickJS/awesome-cursorrules/blob/main/rules/deno-integration-techniques-cursorrules-prompt-fil.mdc) - Deno development with integration techniques. @@ -208,6 +209,7 @@ By adding selected `.mdc` files to `.cursor/rules/`, you can use these rules dir - [Snowflake Cortex AI](https://github.com/PatrickJS/awesome-cursorrules/blob/main/rules/snowflake-cortex-ai-cursorrules-prompt-file.mdc) - AI_COMPLETE, AI_CLASSIFY, AI_EXTRACT, Cortex Search, and RAG applications. - [Snowflake Data Engineering](https://github.com/PatrickJS/awesome-cursorrules/blob/main/rules/snowflake-data-engineering-cursorrules-prompt-file.mdc) - Snowflake SQL, data pipelines (Dynamic Tables, Streams, Tasks, Snowpipe), semi-structured data, Snowflake PostgreSQL, and cost optimization. - [Snowflake Snowpark Python & dbt](https://github.com/PatrickJS/awesome-cursorrules/blob/main/rules/snowflake-snowpark-dbt-cursorrules-prompt-file.mdc) - Snowpark Python (DataFrames, UDFs, stored procedures) and dbt with the Snowflake adapter. +- [Stripe (Next.js, TypeScript)](https://github.com/PatrickJS/awesome-cursorrules/blob/main/rules/stripe-integration-nextjs-typescript.mdc) - Secure checkout sessions, idempotent webhook verification with signature validation, subscription lifecycle handling, and customer portal. - [TypeScript (Axios)](https://github.com/PatrickJS/awesome-cursorrules/blob/main/rules/typescript-axios-cursorrules-prompt-file.mdc) - TypeScript development with Axios integration. ### Testing @@ -322,6 +324,7 @@ By adding selected `.mdc` files to `.cursor/rules/`, you can use these rules dir - [CursorList](https://cursorlist.com) - [CursorDirectory](https://cursor.directory/) +- [Cursor Rules & AI Coding Config Pack](https://moukie76.github.io/cursor-rules-free/) - 27 production-ready rules for 16 stacks: Next.js, React, Python FastAPI, Go, Stripe, Anthropic Claude, Tailwind, Docker, and more. ## How to Use diff --git a/rules/anthropic-claude-api-typescript.mdc b/rules/anthropic-claude-api-typescript.mdc new file mode 100644 index 00000000..71be09e0 --- /dev/null +++ b/rules/anthropic-claude-api-typescript.mdc @@ -0,0 +1,115 @@ +--- +description: Anthropic Claude API integration with streaming responses, tool use, and production-grade error handling for TypeScript and Next.js +globs: **/claude.ts, **/anthropic.ts, **/api/chat/route.ts, **/*.ts +alwaysApply: false +--- + +# Anthropic Claude API — TypeScript / Next.js + +## Client Setup +```ts +import Anthropic from "@anthropic-ai/sdk" + +// Singleton — reuse across requests +const anthropic = new Anthropic({ + apiKey: process.env.ANTHROPIC_API_KEY, +}) +``` + +## Basic Message +```ts +const message = await anthropic.messages.create({ + model: "claude-opus-4-6", + max_tokens: 1024, + messages: [ + { role: "user", content: "Explain this code: ..." } + ], +}) + +const text = message.content[0].type === "text" ? message.content[0].text : "" +``` + +## Streaming (Next.js Edge) +```ts +// app/api/chat/route.ts +import Anthropic from "@anthropic-ai/sdk" + +export const runtime = "edge" + +export async function POST(req: Request) { + const { messages } = await req.json() + + const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY }) + + const stream = anthropic.messages.stream({ + model: "claude-opus-4-6", + max_tokens: 2048, + system: "You are a helpful assistant.", + messages, + }) + + return new Response(stream.toReadableStream(), { + headers: { "Content-Type": "text/event-stream" }, + }) +} +``` + +## Tool Use +```ts +const response = await anthropic.messages.create({ + model: "claude-opus-4-6", + max_tokens: 1024, + tools: [{ + name: "get_weather", + description: "Get current weather for a location", + input_schema: { + type: "object", + properties: { + location: { type: "string", description: "City name" }, + }, + required: ["location"], + }, + }], + messages: [{ role: "user", content: "What is the weather in Paris?" }], +}) +``` + +## System Prompts +```ts +const system = `You are [role]. + +Your task: [specific task] + +Rules: +- [rule 1] +- [rule 2] + +Output format: [format]` +``` + +## Error Handling +```ts +try { + const message = await anthropic.messages.create(...) +} catch (err) { + if (err instanceof Anthropic.APIStatusError) { + if (err.status === 429) { /* rate limited — backoff and retry */ } + if (err.status === 529) { /* overloaded — retry with exponential backoff */ } + } + throw err +} +``` + +## Model Selection +- claude-haiku-4-5-20251001: fast and cheap, good for classification, short tasks +- claude-sonnet-4-6: balanced speed/intelligence for most tasks +- claude-opus-4-6: maximum intelligence for complex reasoning + +## Rules +- Always set max_tokens explicitly — the default may truncate responses +- Use a singleton client instance, not a new one per request +- Handle 429 (rate limit) and 529 (overloaded) with exponential backoff +- Monitor usage.input_tokens + usage.output_tokens per request for cost control +- Trim conversation history before sending — avoid token bloat on long sessions +- Never hardcode API keys — use process.env.ANTHROPIC_API_KEY +- Do not use deprecated claude-1 or claude-2 model IDs diff --git a/rules/stripe-integration-nextjs-typescript.mdc b/rules/stripe-integration-nextjs-typescript.mdc new file mode 100644 index 00000000..8e1d1c34 --- /dev/null +++ b/rules/stripe-integration-nextjs-typescript.mdc @@ -0,0 +1,109 @@ +--- +description: Secure Stripe integration with typed checkout sessions, idempotent webhook verification, and subscription lifecycle handling in Next.js TypeScript +globs: **/stripe.ts, **/webhook/route.ts, **/checkout/route.ts, **/*.ts +alwaysApply: false +--- + +# Stripe Integration — Next.js TypeScript + +## Client Setup +```ts +// lib/stripe.ts +import Stripe from "stripe" + +export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { + apiVersion: "2024-12-18.acacia", + typescript: true, +}) +``` + +## Checkout Session +```ts +export async function createCheckoutSession({ + priceId, + userId, + successUrl, + cancelUrl, +}: { + priceId: string + userId: string + successUrl: string + cancelUrl: string +}) { + return stripe.checkout.sessions.create({ + mode: "subscription", + payment_method_types: ["card"], + line_items: [{ price: priceId, quantity: 1 }], + success_url: successUrl, + cancel_url: cancelUrl, + metadata: { userId }, + subscription_data: { + metadata: { userId }, + }, + }) +} +``` + +## Webhooks — Critical Patterns +```ts +// app/api/stripe/webhook/route.ts +import { headers } from "next/headers" + +export async function POST(req: Request) { + const body = await req.text() + const signature = headers().get("stripe-signature")! + + let event: Stripe.Event + try { + event = stripe.webhooks.constructEvent( + body, + signature, + process.env.STRIPE_WEBHOOK_SECRET! + ) + } catch { + return new Response("Webhook signature verification failed", { status: 400 }) + } + + switch (event.type) { + case "checkout.session.completed": { + const session = event.data.object as Stripe.Checkout.Session + await handleCheckoutComplete(session) + break + } + case "customer.subscription.deleted": { + const sub = event.data.object as Stripe.Subscription + await handleSubscriptionCancelled(sub) + break + } + } + + return new Response("ok") +} +``` + +## Customer Portal +```ts +export async function createPortalSession(customerId: string, returnUrl: string) { + return stripe.billingPortal.sessions.create({ + customer: customerId, + return_url: returnUrl, + }) +} +``` + +## Environment Variables +```env +STRIPE_SECRET_KEY=sk_live_... +NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_... +STRIPE_WEBHOOK_SECRET=whsec_... +NEXT_PUBLIC_STRIPE_PRICE_ID=price_... +``` + +## Rules +- Webhook body: always read as raw text (req.text()), never parse as JSON before constructEvent +- Idempotent handlers: webhooks can fire multiple times — check if already processed before writing to DB +- Fast response: return 200 immediately, offload heavy work to a queue if needed +- Metadata: always attach userId to both metadata and subscription_data.metadata +- Never trust client-submitted amounts — verify server-side via webhook +- Never store raw card data — delegate PCI scope to Stripe +- Never skip signature verification — call constructEvent on every webhook