diff --git a/.agents/skills/add-custom-domain/SKILL.md b/.agents/skills/add-custom-domain/SKILL.md new file mode 100644 index 0000000000..37baafdcfb --- /dev/null +++ b/.agents/skills/add-custom-domain/SKILL.md @@ -0,0 +1,210 @@ +--- +name: add-custom-domain +description: | + Configure custom domains for Temps deployments with automatic SSL/TLS certificates via Let's Encrypt. Supports HTTP-01 and DNS-01 challenges, wildcard domains, and Cloudflare DNS integration. Use when the user wants to: (1) Add a custom domain to their Temps app, (2) Set up SSL certificates, (3) Configure DNS for Temps, (4) Add a wildcard domain, (5) Set up HTTPS for their deployment, (6) Configure Cloudflare with Temps. Triggers: "custom domain", "add domain", "ssl certificate", "https setup", "wildcard domain", "dns configuration", "cloudflare temps". +--- + +# Add Custom Domain + +Configure custom domains with automatic SSL/TLS certificates. + +## Quick Setup + +### 1. Add Domain in Dashboard + +1. Go to Project > Settings > Domains +2. Click "Add Domain" +3. Enter your domain (e.g., `app.example.com`) + +### 2. Configure DNS + +Add a CNAME record pointing to your Temps deployment: + +| Type | Name | Value | +|------|------|-------| +| CNAME | app | your-project.temps.io | + +For apex domains (example.com without subdomain), use an A record: + +| Type | Name | Value | +|------|------|-------| +| A | @ | [Temps IP address] | + +### 3. Verify & Get Certificate + +Temps automatically: +1. Verifies DNS configuration +2. Provisions Let's Encrypt certificate +3. Enables HTTPS + +## Challenge Types + +### HTTP-01 (Default) + +Used for standard domains. Temps handles automatically. + +**Requirements:** +- Domain must point to Temps +- Port 80 must be accessible + +### DNS-01 (Wildcard & Private) + +Required for wildcard domains (`*.example.com`). + +**Setup with Cloudflare:** + +1. Add Cloudflare API token in Temps: + - Go to Settings > DNS Providers + - Add Cloudflare with Zone API token + +2. Add wildcard domain: + ``` + *.example.com + ``` + +3. Temps creates DNS TXT record automatically + +## Wildcard Domains + +For `*.example.com` to match `app.example.com`, `api.example.com`, etc: + +1. **Requires DNS-01 challenge** (HTTP-01 doesn't support wildcards) +2. **Requires DNS provider integration** (Cloudflare supported) + +### Cloudflare Setup + +1. **Create API Token:** + - Go to Cloudflare Dashboard > Profile > API Tokens + - Create token with "Zone:DNS:Edit" permission + - Limit to specific zone (your domain) + +2. **Add to Temps:** + ``` + Settings > DNS Providers > Add Cloudflare + - API Token: [your-token] + - Zone ID: [from Cloudflare domain overview] + ``` + +3. **Add Wildcard Domain:** + ``` + *.example.com + ``` + +## DNS Records Reference + +### Subdomain (Recommended) + +``` +app.example.com -> CNAME -> your-project.temps.io +``` + +### Apex Domain + +``` +example.com -> A -> [Temps IP] +``` + +Or with Cloudflare (CNAME flattening): +``` +example.com -> CNAME -> your-project.temps.io (proxied) +``` + +### Wildcard + +``` +*.example.com -> CNAME -> your-project.temps.io +``` + +## Certificate Management + +### Automatic Renewal + +Temps automatically renews certificates 30 days before expiration. + +### Certificate Status + +Check certificate status in Dashboard > Domains: +- **Pending**: DNS verification in progress +- **Active**: Certificate issued and active +- **Expiring**: Renewal scheduled +- **Failed**: Check DNS configuration + +### Force Renewal + +If needed, manually trigger renewal: +1. Go to Domains +2. Click domain +3. Click "Renew Certificate" + +## Multiple Domains + +Add multiple domains to the same project: + +``` +app.example.com -> Production +staging.example.com -> Staging +api.example.com -> API routes +``` + +Each domain gets its own certificate. + +## Redirects + +### www to non-www + +Add both domains and configure redirect: + +1. Add `example.com` (primary) +2. Add `www.example.com` (redirect) +3. Set `www.example.com` to redirect to `example.com` + +### HTTP to HTTPS + +Automatic - all HTTP requests redirect to HTTPS. + +## Troubleshooting + +**DNS not propagating?** +- Wait up to 48 hours for propagation +- Check with: `dig app.example.com` +- Use DNS checker: dnschecker.org + +**Certificate stuck pending?** +- Verify CNAME/A record is correct +- Check no conflicting records exist +- Ensure domain isn't proxied (orange cloud in Cloudflare) during verification + +**Wildcard not working?** +- Requires DNS provider integration +- Verify Cloudflare API token has correct permissions +- Check Zone ID is correct + +**SSL certificate errors?** +- Clear browser cache +- Check certificate in browser: `https://app.example.com` +- Verify intermediate certificates are served + +## API Reference + +### Add Domain + +```bash +curl -X POST https://your-temps.com/api/projects/123/domains \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"domain": "app.example.com"}' +``` + +### List Domains + +```bash +curl https://your-temps.com/api/projects/123/domains \ + -H "Authorization: Bearer $TOKEN" +``` + +### Delete Domain + +```bash +curl -X DELETE https://your-temps.com/api/projects/123/domains/456 \ + -H "Authorization: Bearer $TOKEN" +``` diff --git a/.agents/skills/add-node-sdk/SKILL.md b/.agents/skills/add-node-sdk/SKILL.md new file mode 100644 index 0000000000..11e7b291b7 --- /dev/null +++ b/.agents/skills/add-node-sdk/SKILL.md @@ -0,0 +1,262 @@ +--- +name: add-node-sdk +description: | + Integrate the Temps Node.js SDK for server-side analytics, KV storage, blob storage, and platform management. Use when the user wants to: (1) Track server-side events, (2) Use Temps KV (key-value) storage, (3) Use Temps Blob storage for files, (4) Access Temps API from Node.js, (5) Server-side analytics integration, (6) Backend event tracking. Triggers: "temps node sdk", "server-side analytics", "temps kv", "temps blob", "backend integration", "node.js temps". +--- + +# Add Node.js SDK + +Integrate Temps platform features in Node.js applications. + +## Installation + +```bash +# Core SDK +npm install @temps-sdk/node + +# Individual packages (optional) +npm install @temps-sdk/kv # Key-Value storage +npm install @temps-sdk/blob # Blob/file storage +``` + +## Configuration + +```typescript +import { Temps } from '@temps-sdk/node'; + +const temps = new Temps({ + apiKey: process.env.TEMPS_API_KEY, + projectId: process.env.TEMPS_PROJECT_ID, +}); +``` + +## Server-Side Event Tracking + +Track events from your backend: + +```typescript +import { Temps } from '@temps-sdk/node'; + +const temps = new Temps({ + apiKey: process.env.TEMPS_API_KEY, + projectId: process.env.TEMPS_PROJECT_ID, +}); + +// Track an event +await temps.track('purchase_completed', { + userId: 'user_123', + orderId: 'order_456', + amount: 99.99, + currency: 'USD', + items: ['product_1', 'product_2'], +}); + +// Identify a user +await temps.identify('user_123', { + email: 'user@example.com', + name: 'John Doe', + plan: 'premium', + createdAt: new Date().toISOString(), +}); +``` + +### Express Middleware + +```typescript +import express from 'express'; +import { Temps } from '@temps-sdk/node'; + +const app = express(); +const temps = new Temps({ apiKey: process.env.TEMPS_API_KEY }); + +// Track all API requests +app.use((req, res, next) => { + const start = Date.now(); + + res.on('finish', () => { + temps.track('api_request', { + method: req.method, + path: req.path, + statusCode: res.statusCode, + duration: Date.now() - start, + userId: req.user?.id, + }); + }); + + next(); +}); +``` + +## KV Storage + +Simple key-value storage with automatic JSON serialization: + +```typescript +import { KV } from '@temps-sdk/kv'; + +const kv = new KV({ + apiKey: process.env.TEMPS_API_KEY, + namespace: 'my-app', // Optional namespace +}); + +// Store values +await kv.set('user:123', { name: 'John', email: 'john@example.com' }); +await kv.set('session:abc', { userId: '123' }, { ttl: 3600 }); // 1 hour TTL + +// Retrieve values +const user = await kv.get('user:123'); +// { name: 'John', email: 'john@example.com' } + +// Check existence +const exists = await kv.has('user:123'); + +// Delete +await kv.delete('user:123'); + +// List keys +const keys = await kv.list({ prefix: 'user:' }); +// ['user:123', 'user:456', ...] +``` + +### KV Options + +```typescript +// Set with TTL (seconds) +await kv.set('key', value, { ttl: 3600 }); + +// Set with metadata +await kv.set('key', value, { + metadata: { version: 1, updatedBy: 'system' } +}); + +// Get with metadata +const { value, metadata } = await kv.getWithMetadata('key'); + +// List with pagination +const result = await kv.list({ + prefix: 'user:', + limit: 100, + cursor: 'next-cursor', +}); +``` + +## Blob Storage + +Store and retrieve files: + +```typescript +import { Blob } from '@temps-sdk/blob'; + +const blob = new Blob({ + apiKey: process.env.TEMPS_API_KEY, +}); + +// Upload file from buffer +const file = await blob.put('avatars/user-123.png', imageBuffer, { + contentType: 'image/png', + metadata: { userId: '123' }, +}); + +// Upload from stream +import { createReadStream } from 'fs'; +await blob.put('backups/data.json', createReadStream('./data.json'), { + contentType: 'application/json', +}); + +// Get file +const data = await blob.get('avatars/user-123.png'); + +// Get as stream (for large files) +const stream = await blob.getStream('backups/data.json'); + +// Get signed URL (for client-side access) +const url = await blob.getSignedUrl('avatars/user-123.png', { + expiresIn: 3600, // 1 hour +}); + +// Delete +await blob.delete('avatars/user-123.png'); + +// List files +const files = await blob.list({ prefix: 'avatars/' }); +``` + +### Upload from Client + +Generate presigned upload URLs: + +```typescript +// Server: Generate upload URL +const uploadUrl = await blob.createUploadUrl('uploads/file.pdf', { + contentType: 'application/pdf', + maxSize: 10 * 1024 * 1024, // 10MB + expiresIn: 300, // 5 minutes +}); + +// Client: Upload directly to storage +await fetch(uploadUrl, { + method: 'PUT', + body: file, + headers: { 'Content-Type': 'application/pdf' }, +}); +``` + +## Error Handling + +```typescript +import { TempsError, RateLimitError, NotFoundError } from '@temps-sdk/node'; + +try { + await temps.track('event', data); +} catch (error) { + if (error instanceof RateLimitError) { + // Retry after delay + await sleep(error.retryAfter * 1000); + await temps.track('event', data); + } else if (error instanceof NotFoundError) { + console.error('Resource not found:', error.message); + } else if (error instanceof TempsError) { + console.error('Temps error:', error.message, error.code); + } else { + throw error; + } +} +``` + +## TypeScript Support + +Full TypeScript support with generics: + +```typescript +interface User { + name: string; + email: string; + plan: 'free' | 'premium'; +} + +// Typed KV operations +const user = await kv.get('user:123'); +// user is User | null + +await kv.set('user:123', { + name: 'John', + email: 'john@example.com', + plan: 'premium', +}); +``` + +## Environment Variables + +| Variable | Required | Description | +|----------|----------|-------------| +| `TEMPS_API_KEY` | Yes | API key from dashboard | +| `TEMPS_PROJECT_ID` | For tracking | Project ID for analytics | +| `TEMPS_API_URL` | No | Custom API URL (self-hosted) | + +## Best Practices + +1. **Initialize once**: Create SDK instance at app startup +2. **Use environment variables**: Never hardcode API keys +3. **Handle errors gracefully**: Wrap SDK calls in try/catch +4. **Use namespaces in KV**: Organize keys by feature/domain +5. **Set TTLs appropriately**: Don't store temporary data forever diff --git a/.agents/skills/add-react-analytics/SKILL.md b/.agents/skills/add-react-analytics/SKILL.md new file mode 100644 index 0000000000..db7bcb8530 --- /dev/null +++ b/.agents/skills/add-react-analytics/SKILL.md @@ -0,0 +1,189 @@ +--- +name: add-react-analytics +description: | + Add Temps analytics to React applications with comprehensive tracking capabilities including page views, custom events, scroll tracking, engagement monitoring, session recording, and Web Vitals performance metrics. Use when the user wants to: (1) Add analytics to a React app (Next.js App Router, Next.js Pages Router, Vite, Create React App, or Remix), (2) Track user events or interactions, (3) Monitor scroll depth or element visibility, (4) Add session recording/replay, (5) Track Web Vitals or performance metrics, (6) Measure user engagement or time on page, (7) Identify users for analytics, (8) Set up product analytics or telemetry. Triggers: "add analytics", "track events", "session recording", "web vitals", "user tracking", "temps analytics", "react analytics". +--- + +# Add React Analytics + +Integrate Temps analytics SDK into React applications with full tracking capabilities. + +## Installation + +```bash +npm install @temps-sdk/react-analytics +# or: yarn add / pnpm add / bun add +``` + +## Framework Setup + +Detect the user's framework and apply the appropriate setup: + +### Next.js App Router (13+) + +```tsx +// app/layout.tsx +import { TempsAnalyticsProvider } from '@temps-sdk/react-analytics'; + +export default function RootLayout({ children }: { children: React.ReactNode }) { + return ( + + + + {children} + + + + ); +} +``` + +### Next.js Pages Router + +```tsx +// pages/_app.tsx +import { TempsAnalyticsProvider } from '@temps-sdk/react-analytics'; +import type { AppProps } from 'next/app'; + +export default function App({ Component, pageProps }: AppProps) { + return ( + + + + ); +} +``` + +### Vite / Create React App + +```tsx +// src/main.tsx or src/index.tsx +import { TempsAnalyticsProvider } from '@temps-sdk/react-analytics'; + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + +); +``` + +### Remix + +```tsx +// app/root.tsx +import { TempsAnalyticsProvider } from '@temps-sdk/react-analytics'; + +export default function App() { + return ( + + + + + + + + ); +} +``` + +## Provider Configuration + +```tsx + + {children} + +``` + +## Available Hooks + +For detailed API reference, see [HOOKS_REFERENCE.md](references/HOOKS_REFERENCE.md). + +### Quick Reference + +| Hook | Purpose | +|------|---------| +| `useTrackEvent` | Track custom events | +| `useAnalytics` | Access analytics context, identify users | +| `useScrollVisibility` | Track element visibility on scroll | +| `usePageLeave` | Track page leave and time on page | +| `useEngagementTracking` | Heartbeat engagement monitoring | +| `useSpeedAnalytics` | Web Vitals (LCP, FCP, CLS, TTFB, INP) | +| `useTrackPageview` | Manual page view tracking | + +### Track Custom Events + +```tsx +'use client'; +import { useTrackEvent } from '@temps-sdk/react-analytics'; + +function MyComponent() { + const trackEvent = useTrackEvent(); + + const handleClick = () => { + trackEvent('button_click', { + button_id: 'subscribe', + plan: 'premium' + }); + }; + + return ; +} +``` + +### Identify Users + +```tsx +'use client'; +import { useAnalytics } from '@temps-sdk/react-analytics'; +import { useEffect } from 'react'; + +function UserProfile({ user }) { + const { identify } = useAnalytics(); + + useEffect(() => { + if (user) { + identify(user.id, { + email: user.email, + name: user.name, + plan: user.subscription?.plan + }); + } + }, [user, identify]); + + return
Profile
; +} +``` + +## Session Recording + +For privacy-aware session replay, see [SESSION_RECORDING.md](references/SESSION_RECORDING.md). + +```tsx +import { SessionRecordingProvider } from '@temps-sdk/react-analytics'; + + + {children} + +``` + +## Verification Checklist + +After implementation: +1. Check browser DevTools Network tab for `/api/_temps` requests +2. Verify events appear in Temps dashboard +3. Test session recording playback +4. Confirm Web Vitals are being captured diff --git a/.agents/skills/add-react-analytics/references/HOOKS_REFERENCE.md b/.agents/skills/add-react-analytics/references/HOOKS_REFERENCE.md new file mode 100644 index 0000000000..1576237fc7 --- /dev/null +++ b/.agents/skills/add-react-analytics/references/HOOKS_REFERENCE.md @@ -0,0 +1,225 @@ +# Hooks API Reference + +Complete reference for all Temps React Analytics hooks. + +## useTrackEvent + +Track custom events with arbitrary properties. + +```tsx +'use client'; +import { useTrackEvent } from '@temps-sdk/react-analytics'; + +function ProductPage() { + const trackEvent = useTrackEvent(); + + const handleAddToCart = (productId: string, price: number) => { + trackEvent('add_to_cart', { + product_id: productId, + price: price, + currency: 'USD', + timestamp: new Date().toISOString(), + }); + }; + + return ( + + ); +} +``` + +## useAnalytics + +Access the analytics context for user identification and core analytics functions. + +```tsx +'use client'; +import { useAnalytics } from '@temps-sdk/react-analytics'; + +function App() { + const { identify, reset, getVisitorId } = useAnalytics(); + + // Identify a user + identify('user_123', { + email: 'user@example.com', + name: 'John Doe', + plan: 'premium' + }); + + // Reset analytics (on logout) + reset(); + + // Get anonymous visitor ID + const visitorId = getVisitorId(); +} +``` + +## useScrollVisibility + +Track when elements scroll into view using Intersection Observer. + +```tsx +'use client'; +import { useScrollVisibility } from '@temps-sdk/react-analytics'; + +function ProductCard({ product }) { + const scrollRef = useScrollVisibility('product_viewed', { + product_id: product.id, + product_name: product.name, + price: product.price, + }, { + threshold: 0.5, // Trigger when 50% visible + once: true, // Track only once + enabled: true, // Enable tracking + }); + + return ( +
+

{product.name}

+

${product.price}

+
+ ); +} + +// Track multiple visibility thresholds +function HeroSection() { + const heroRef = useScrollVisibility('hero_visible', { + section: 'hero', + }, { + threshold: [0, 0.25, 0.5, 0.75, 1.0], + once: false, + }); + + return
Welcome
; +} +``` + +**Options:** +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `threshold` | `number \| number[]` | `0` | Visibility percentage (0-1) | +| `once` | `boolean` | `true` | Track only on first visibility | +| `enabled` | `boolean` | `true` | Enable/disable tracking | +| `root` | `Element` | viewport | Viewport reference | +| `rootMargin` | `string` | `'0px'` | Margin around root | + +## usePageLeave + +Track when users leave pages and time spent. + +```tsx +'use client'; +import { usePageLeave } from '@temps-sdk/react-analytics'; + +function ArticlePage({ articleId }) { + usePageLeave((data) => { + console.log('User spent', data.timeOnPage, 'ms on article', articleId); + // Data automatically sent to analytics + }); + + return
Content
; +} +``` + +**Callback data:** +- `timeOnPage`: Time in milliseconds +- `page`: Current URL +- `timestamp`: ISO timestamp + +**Features:** +- Uses `sendBeacon` for reliable transmission +- Handles page refresh, tab close, navigation +- No configuration needed + +## useEngagementTracking + +Monitor active engagement with heartbeat tracking. + +```tsx +'use client'; +import { useEngagementTracking } from '@temps-sdk/react-analytics'; + +function VideoPage() { + useEngagementTracking({ + heartbeatInterval: 5000, // Heartbeat every 5 seconds + engagementThreshold: 2000, // Engaged after 2 seconds + inactivityTimeout: 30000, // Inactive after 30 seconds + onEngagementUpdate: (data) => { + console.log('Engaged for', data.engagementTime, 'ms'); + }, + onPageLeave: (data) => { + console.log('Final engagement:', data.totalEngagementTime, 'ms'); + }, + }); + + return