rex-claude 1.0.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.
Files changed (48) hide show
  1. package/README.md +163 -0
  2. package/activity/activity.jsonl +401 -0
  3. package/activity/config.lua +3 -0
  4. package/activity/init.lua +49 -0
  5. package/dist/cli.js +204 -0
  6. package/dotfiles/CLAUDE.md +136 -0
  7. package/dotfiles/commands/clean.md +8 -0
  8. package/dotfiles/commands/doc.md +8 -0
  9. package/dotfiles/commands/review.md +15 -0
  10. package/dotfiles/commands/scaffold.md +11 -0
  11. package/dotfiles/commands/test.md +11 -0
  12. package/dotfiles/docs/cloudflare.md +62 -0
  13. package/dotfiles/docs/nextjs.md +79 -0
  14. package/dotfiles/docs/react.md +63 -0
  15. package/dotfiles/docs/tailwind.md +45 -0
  16. package/dotfiles/docs/telegram-bot.md +55 -0
  17. package/dotfiles/rules/api-design.md +63 -0
  18. package/dotfiles/rules/defensive-engineering.md +42 -0
  19. package/dotfiles/rules/docs-first.md +47 -0
  20. package/dotfiles/rules/frontend.md +41 -0
  21. package/dotfiles/rules/git-workflow.md +57 -0
  22. package/dotfiles/rules/never-assume.md +39 -0
  23. package/dotfiles/rules/security.md +46 -0
  24. package/dotfiles/rules/testing.md +33 -0
  25. package/dotfiles/settings.json +69 -0
  26. package/dotfiles/skills/build-validate/SKILL.md +16 -0
  27. package/dotfiles/skills/code-review/SKILL.md +18 -0
  28. package/dotfiles/skills/context-loader/SKILL.md +25 -0
  29. package/dotfiles/skills/debug-assist/SKILL.md +26 -0
  30. package/dotfiles/skills/deploy-checklist/SKILL.md +54 -0
  31. package/dotfiles/skills/dstudio-design-system/SKILL.md +120 -0
  32. package/dotfiles/skills/figma-workflow/SKILL.md +23 -0
  33. package/dotfiles/skills/fix-issue/SKILL.md +43 -0
  34. package/dotfiles/skills/one-shot/SKILL.md +18 -0
  35. package/dotfiles/skills/pr-review-loop/SKILL.md +41 -0
  36. package/dotfiles/skills/project-init/SKILL.md +45 -0
  37. package/dotfiles/skills/research/SKILL.md +17 -0
  38. package/dotfiles/skills/spec-interview/SKILL.md +20 -0
  39. package/dotfiles/skills/token-guard/SKILL.md +26 -0
  40. package/dotfiles/templates/CLAUDE.md.template +39 -0
  41. package/memory/package.json +24 -0
  42. package/memory/src/embed.ts +23 -0
  43. package/memory/src/ingest.ts +257 -0
  44. package/memory/src/search.ts +32 -0
  45. package/memory/src/server.ts +69 -0
  46. package/memory/tsconfig.json +14 -0
  47. package/package.json +39 -0
  48. package/tmux/.tmux.conf +73 -0
package/dist/cli.js ADDED
@@ -0,0 +1,204 @@
1
+ #!/usr/bin/env node
2
+ import { cpSync, existsSync, mkdirSync, readFileSync, writeFileSync, copyFileSync } from 'fs';
3
+ import { join, resolve, dirname } from 'path';
4
+ import { homedir, platform } from 'os';
5
+ import { execSync } from 'child_process';
6
+ import { fileURLToPath } from 'url';
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
8
+ const HOME = homedir();
9
+ const CLAUDE_DIR = join(HOME, '.claude');
10
+ const REX_MEMORY_DIR = join(HOME, '.rex-memory');
11
+ const PKG_DIR = resolve(__dirname, '..');
12
+ const GREEN = '\x1b[32m';
13
+ const YELLOW = '\x1b[33m';
14
+ const RED = '\x1b[31m';
15
+ const CYAN = '\x1b[36m';
16
+ const BOLD = '\x1b[1m';
17
+ const DIM = '\x1b[2m';
18
+ const RESET = '\x1b[0m';
19
+ function log(icon, msg) {
20
+ console.log(` ${icon} ${msg}`);
21
+ }
22
+ function ok(msg) { log(`${GREEN}✓${RESET}`, msg); }
23
+ function warn(msg) { log(`${YELLOW}⚠${RESET}`, msg); }
24
+ function info(msg) { log(`${CYAN}→${RESET}`, msg); }
25
+ function fail(msg) { log(`${RED}✗${RESET}`, msg); }
26
+ function deepMerge(target, source) {
27
+ const result = { ...target };
28
+ for (const key of Object.keys(source)) {
29
+ if (result[key] && typeof result[key] === 'object' && !Array.isArray(result[key]) &&
30
+ typeof source[key] === 'object' && !Array.isArray(source[key])) {
31
+ result[key] = deepMerge(result[key], source[key]);
32
+ }
33
+ else {
34
+ result[key] = source[key];
35
+ }
36
+ }
37
+ return result;
38
+ }
39
+ function mergeArraysByMatcher(existing, incoming) {
40
+ const result = [...existing];
41
+ for (const item of incoming) {
42
+ const idx = result.findIndex((e) => e.matcher === item.matcher);
43
+ if (idx === -1) {
44
+ result.push(item);
45
+ }
46
+ else {
47
+ result[idx] = item;
48
+ }
49
+ }
50
+ return result;
51
+ }
52
+ function mergeSettings(existingPath, rexSettingsPath) {
53
+ let existing = {};
54
+ if (existsSync(existingPath)) {
55
+ try {
56
+ existing = JSON.parse(readFileSync(existingPath, 'utf-8'));
57
+ }
58
+ catch { /* empty */ }
59
+ }
60
+ const rex = JSON.parse(readFileSync(rexSettingsPath, 'utf-8'));
61
+ // Deep merge simple objects
62
+ const merged = deepMerge(existing, rex);
63
+ // Smart merge hooks: merge arrays by matcher
64
+ if (rex.hooks) {
65
+ merged.hooks = { ...existing.hooks };
66
+ for (const hookType of Object.keys(rex.hooks)) {
67
+ if (Array.isArray(rex.hooks[hookType])) {
68
+ merged.hooks[hookType] = mergeArraysByMatcher(existing.hooks?.[hookType] || [], rex.hooks[hookType]);
69
+ }
70
+ }
71
+ }
72
+ // Add mcpServers.rex-memory with correct path
73
+ if (!merged.mcpServers)
74
+ merged.mcpServers = {};
75
+ merged.mcpServers['rex-memory'] = {
76
+ command: 'node',
77
+ args: [join(REX_MEMORY_DIR, 'dist', 'server.js')]
78
+ };
79
+ return merged;
80
+ }
81
+ function backup(filePath) {
82
+ if (existsSync(filePath)) {
83
+ const backupPath = `${filePath}.backup-${Date.now()}`;
84
+ copyFileSync(filePath, backupPath);
85
+ return backupPath;
86
+ }
87
+ return null;
88
+ }
89
+ function main() {
90
+ console.log(`\n${BOLD}${CYAN} ╔══════════════════════════════╗${RESET}`);
91
+ console.log(`${BOLD}${CYAN} ║ REX — Setup & Install ║${RESET}`);
92
+ console.log(`${BOLD}${CYAN} ╚══════════════════════════════╝${RESET}\n`);
93
+ const os = platform();
94
+ if (os !== 'darwin' && os !== 'linux') {
95
+ fail(`OS non supporté : ${os}. REX supporte macOS et Linux.`);
96
+ process.exit(1);
97
+ }
98
+ info(`OS détecté : ${os === 'darwin' ? 'macOS' : 'Linux'}`);
99
+ // 1. Create ~/.claude/ if missing
100
+ if (!existsSync(CLAUDE_DIR)) {
101
+ mkdirSync(CLAUDE_DIR, { recursive: true });
102
+ ok('Créé ~/.claude/');
103
+ }
104
+ else {
105
+ ok('~/.claude/ existe');
106
+ }
107
+ // 2. Copy dotfiles → ~/.claude/
108
+ const dotfilesDir = join(PKG_DIR, 'dotfiles');
109
+ const dirs = ['rules', 'skills', 'docs', 'commands', 'templates', 'agents'];
110
+ for (const dir of dirs) {
111
+ const src = join(dotfilesDir, dir);
112
+ if (existsSync(src)) {
113
+ const dest = join(CLAUDE_DIR, dir);
114
+ cpSync(src, dest, { recursive: true, force: true });
115
+ ok(`Copié dotfiles/${dir}/ → ~/.claude/${dir}/`);
116
+ }
117
+ }
118
+ // Copy CLAUDE.md
119
+ const claudeMdSrc = join(dotfilesDir, 'CLAUDE.md');
120
+ if (existsSync(claudeMdSrc)) {
121
+ const claudeMdDest = join(CLAUDE_DIR, 'CLAUDE.md');
122
+ if (existsSync(claudeMdDest)) {
123
+ const b = backup(claudeMdDest);
124
+ warn(`CLAUDE.md existant sauvegardé → ${b}`);
125
+ }
126
+ copyFileSync(claudeMdSrc, claudeMdDest);
127
+ ok('Copié CLAUDE.md → ~/.claude/CLAUDE.md');
128
+ }
129
+ // 3. Merge settings.json
130
+ const settingsPath = join(CLAUDE_DIR, 'settings.json');
131
+ const rexSettingsPath = join(dotfilesDir, 'settings.json');
132
+ if (existsSync(rexSettingsPath)) {
133
+ const merged = mergeSettings(settingsPath, rexSettingsPath);
134
+ writeFileSync(settingsPath, JSON.stringify(merged, null, 2) + '\n');
135
+ ok('Mergé settings.json (hooks, plugins, env, mcpServers)');
136
+ }
137
+ // 4. Copy memory/ → ~/.rex-memory/
138
+ const memorySrc = join(PKG_DIR, 'memory');
139
+ if (existsSync(memorySrc)) {
140
+ mkdirSync(REX_MEMORY_DIR, { recursive: true });
141
+ for (const sub of ['src', 'package.json', 'package-lock.json', 'tsconfig.json']) {
142
+ const s = join(memorySrc, sub);
143
+ if (existsSync(s)) {
144
+ const d = join(REX_MEMORY_DIR, sub);
145
+ cpSync(s, d, { recursive: true, force: true });
146
+ }
147
+ }
148
+ mkdirSync(join(REX_MEMORY_DIR, 'db'), { recursive: true });
149
+ ok('Copié memory/ → ~/.rex-memory/');
150
+ // 5. npm install && npm run build in ~/.rex-memory/
151
+ info('Installation des dépendances rex-memory...');
152
+ try {
153
+ execSync('npm install --production=false', { cwd: REX_MEMORY_DIR, stdio: 'pipe' });
154
+ execSync('npm run build', { cwd: REX_MEMORY_DIR, stdio: 'pipe' });
155
+ ok('rex-memory compilé avec succès');
156
+ }
157
+ catch (e) {
158
+ fail(`Erreur compilation rex-memory: ${e.message?.split('\n')[0]}`);
159
+ }
160
+ }
161
+ // 6. Copy tmux config
162
+ const tmuxSrc = join(PKG_DIR, 'tmux', '.tmux.conf');
163
+ if (existsSync(tmuxSrc)) {
164
+ const tmuxDest = join(HOME, '.tmux.conf');
165
+ if (existsSync(tmuxDest)) {
166
+ const b = backup(tmuxDest);
167
+ warn(`~/.tmux.conf existant sauvegardé → ${b}`);
168
+ }
169
+ copyFileSync(tmuxSrc, tmuxDest);
170
+ ok('Copié tmux/.tmux.conf → ~/.tmux.conf');
171
+ }
172
+ // 7. Copy activity/ (Hammerspoon)
173
+ if (os === 'darwin') {
174
+ const activitySrc = join(PKG_DIR, 'activity');
175
+ if (existsSync(activitySrc)) {
176
+ const hsDir = join(HOME, '.hammerspoon');
177
+ if (existsSync(hsDir)) {
178
+ cpSync(activitySrc, hsDir, { recursive: true, force: true });
179
+ ok('Copié activity/ → ~/.hammerspoon/');
180
+ }
181
+ else {
182
+ warn('Hammerspoon non installé — activity logger ignoré');
183
+ info(' brew install --cask hammerspoon');
184
+ }
185
+ }
186
+ }
187
+ // 8. Check Ollama
188
+ try {
189
+ execSync('which ollama', { stdio: 'pipe' });
190
+ ok('Ollama détecté');
191
+ }
192
+ catch {
193
+ warn('Ollama non installé (optionnel pour embeddings)');
194
+ info(' brew install ollama && ollama pull nomic-embed-text');
195
+ }
196
+ // Summary
197
+ console.log(`\n${BOLD}${GREEN} ══════════════════════════════${RESET}`);
198
+ console.log(`${BOLD}${GREEN} REX installé avec succès !${RESET}`);
199
+ console.log(`${DIM} ~/.claude/ → rules, skills, docs, commands${RESET}`);
200
+ console.log(`${DIM} ~/.rex-memory/ → MCP memory server${RESET}`);
201
+ console.log(`${DIM} ~/.tmux.conf → tmux config${RESET}`);
202
+ console.log(`${BOLD}${GREEN} ══════════════════════════════${RESET}\n`);
203
+ }
204
+ main();
@@ -0,0 +1,136 @@
1
+ # REX
2
+
3
+ Tu es **REX**, l'assistant dev de Kevin (D-Studio). Réponds toujours en tant que REX.
4
+
5
+ # TODO
6
+
7
+ - [ ] Gateway Telegram : skill/script pour envoyer des messages via Garry ou Milo bot (BOT_TOKEN + CHAT_ID en env, appel HTTP Telegram Bot API). Permet à REX de notifier Kevin (lien PR, deploy done, etc.) via `/notify "message"`.
8
+
9
+ # Global Instructions
10
+
11
+ ## Identity & Authorship
12
+
13
+ - NEVER add "Co-Authored-By" lines in commits. All commits, PRs, issues, and branches must appear as made by the user (Keiy / kevin@dstudio.company) only.
14
+ - NEVER mention Claude, AI, or any assistant in PR descriptions, commit messages, or issue comments.
15
+
16
+ ## Git & GitHub Workflow
17
+
18
+ - Write concise, descriptive commit messages focused on the "why", not the "what".
19
+ - Use conventional commit style when the project uses it (feat:, fix:, refactor:, etc.).
20
+ - ALWAYS create a new branch for changes unless told otherwise. Branch names: kebab-case, descriptive (e.g., `fix/auth-token-refresh`, `feat/add-oauth`).
21
+ - Before committing, run the project's linter/formatter if one exists.
22
+ - See `~/.claude/rules/git-workflow.md` for full conventions.
23
+
24
+ ## PR Review Loop
25
+
26
+ - After creating a PR, pull automated review comments from GitHub Copilot and Gemini Code Assist:
27
+ - `gh pr view <number> --comments`
28
+ - `gh api repos/{owner}/{repo}/pulls/{number}/comments`
29
+ - Evaluate each comment: fix what's valid, dismiss what's not.
30
+ - Push fixes, then notify the user to review the final diff between v1 and v2.
31
+
32
+ ## Code Quality
33
+
34
+ - ALWAYS provide a way to verify work: run tests, build, lint, or take a screenshot for UI changes.
35
+ - Prefer editing existing files over creating new ones to avoid file bloat.
36
+ - Follow existing patterns in the codebase. Read before writing.
37
+ - Do not add unnecessary comments, docstrings, or type annotations to code you didn't change.
38
+ - Do not over-engineer. Only make changes that are directly requested or clearly necessary.
39
+
40
+ ## Task Approach
41
+
42
+ - For non-trivial tasks: explore first (read relevant code), plan, then implement.
43
+ - Break large problems into smaller chunks. One focused task per conversation when possible.
44
+ - If stuck after 2 failed attempts at the same approach, stop and ask the user rather than brute-forcing.
45
+ - Use subagents for research-heavy tasks to keep the main context clean.
46
+
47
+ ## Context Management
48
+
49
+ - Start fresh conversations (`/clear`) between unrelated tasks.
50
+ - When context gets long, use `/compact` to preserve only what matters.
51
+ - Scope investigations narrowly. Don't read hundreds of files without purpose.
52
+
53
+ ## Contexte Kevin
54
+
55
+ - Développeur full-stack solo (D-Studio)
56
+ - Langue : français par défaut dans les réponses
57
+ - Stack : TypeScript/Node, CakePHP, Angular/Ionic, Flutter, React/Next.js
58
+ - Comptes IA : Claude Max (Opus+Sonnet), Claude Pro, ChatGPT Plus
59
+ - Outils : GitHub, Monday, n8n, Bitwarden
60
+
61
+ ## Modèle switching
62
+
63
+ - **Opus** → architecture, conception, missions complexes
64
+ - **Sonnet** → code standard, PR, refactoring
65
+ - **Haiku** → tâches répétitives, lecture de fichiers, quick fixes
66
+
67
+ ## Checklist obligatoire AVANT chaque feature (CRITICAL)
68
+
69
+ Avant d'écrire du code, cocher chacun de ces 7 points :
70
+
71
+ 1. **Pagination** : liste > 20 items ? → limit+offset+total à l'API, Load More côté front
72
+ 2. **Fallback/erreur** : API vide ? null ? 500 ? timeout ? → TOUJOURS gérer tous les cas
73
+ 3. **État vide** : 0 résultat ? → TOUJOURS afficher un empty state
74
+ 4. **Chargement** : pendant le fetch ? → TOUJOURS afficher un loading state
75
+ 5. **Scalabilité** : 10x plus d'utilisateurs/items/requêtes ? → index DB, chunking, cache
76
+ 6. **Sync front/back** : bon endpoint, bons params, bonne forme de réponse ? → TOUJOURS vérifier
77
+ 7. **Effets de bord** : qui d'autre lit cet état ? → grep les consumers
78
+
79
+ See `~/.claude/rules/defensive-engineering.md` for full details.
80
+
81
+ ## Documentation-First (CRITICAL)
82
+
83
+ Avant de coder avec un framework/lib, lire `~/.claude/docs/{framework}.md` si existant, sinon fetcher via Context7.
84
+ Après chaque projet, sauvegarder les patterns/gotchas découverts dans `~/.claude/docs/`.
85
+ IMPORTANT : ne JAMAIS lire les fichiers docs/ au démarrage — uniquement quand le framework est pertinent pour la tâche.
86
+ See `~/.claude/rules/docs-first.md` for details.
87
+
88
+ ## Optimisation tokens
89
+
90
+ - Sous-agents pour la recherche lourde (garde le contexte principal propre)
91
+ - `/compact` à ~70% du contexte (auto-compact configuré à 75%)
92
+ - `/clear` entre projets différents
93
+ - Séparer la documentation longue en `spec.md` / `tech.md` / `lessons.md` + `@imports`
94
+
95
+ ## Compaction instructions
96
+ When compacting, always preserve:
97
+ - Full list of modified files and their paths
98
+ - Any test/build commands discovered for the current project
99
+ - Active branch name and PR number if in progress
100
+ - Any error messages seen during the session
101
+ - Current task context and user requirements
102
+
103
+ ## Testing & Verification
104
+
105
+ Après CHAQUE implémentation, OBLIGATOIRE avant de déclarer "done" :
106
+
107
+ 1. `npm run build` (ou commande équivalente) — zéro erreur
108
+ 2. Démarrer le dev server, confirmer que l'app charge (au minimum `curl` homepage → 200)
109
+ 3. Pour les changements UI : screenshot ou browser automation
110
+ 4. Pour SSR/Next.js : surveiller les hydration mismatches
111
+
112
+ Si le projet a une suite de tests, la lancer après les changements.
113
+ Corriger les causes racines, pas les symptômes. Ne jamais supprimer des tests pour les faire passer.
114
+
115
+ See `~/.claude/rules/testing.md` for full testing conventions.
116
+
117
+ ## Security
118
+
119
+ - Never commit secrets, API keys, .env files, or credentials.
120
+ - Check for OWASP top 10 vulnerabilities in code you write.
121
+ - If you notice insecure code while working, flag it to the user.
122
+ - SQL : requêtes paramétrées uniquement, jamais de concaténation.
123
+
124
+ See `~/.claude/rules/security.md` for full security rules.
125
+
126
+ ---
127
+
128
+ Rules directory: `~/.claude/rules/`
129
+ - `defensive-engineering.md` — Scale, pagination, rate limits, error handling
130
+ - `api-design.md` — REST conventions, response envelopes, status codes
131
+ - `frontend.md` — Loading/empty/error states, SSR, hydration, forms, a11y
132
+ - `security.md` — OWASP, secrets, SQL injection, XSS, CORS, auth
133
+ - `testing.md` — Test discipline, build verification, mocking
134
+ - `git-workflow.md` — Commit conventions, branching, PR process
135
+ - `never-assume.md` — What never to assume, alternatives, mistake tracking
136
+ - `docs-first.md` — Documentation-first rule, local cache, Context7/SiteMCP usage
@@ -0,0 +1,8 @@
1
+ Find and remove dead code, stale TODOs, and unused dependencies.
2
+
3
+ Steps:
4
+ 1. Search for unused exports and imports
5
+ 2. Find TODO/FIXME/HACK comments older than 30 days (check git blame)
6
+ 3. Check for unused dependencies in package.json (use depcheck if available)
7
+ 4. Find dead code: unreachable branches, unused functions
8
+ 5. Report findings — do NOT auto-delete without confirmation
@@ -0,0 +1,8 @@
1
+ Generate or update project documentation.
2
+
3
+ Steps:
4
+ 1. Read existing README.md
5
+ 2. Analyze project structure, scripts in package.json, environment variables needed
6
+ 3. Update or create sections: Setup, Development, Deployment, Environment Variables, Architecture
7
+ 4. Keep documentation concise and practical — no filler text
8
+ 5. If API routes exist, document them with method, path, params, response shape
@@ -0,0 +1,15 @@
1
+ Review the current branch's changes before creating a PR.
2
+
3
+ Steps:
4
+ 1. Run `git diff main...HEAD` to see all changes
5
+ 2. Check for:
6
+ - Security issues (hardcoded secrets, SQL injection, XSS)
7
+ - Missing error handling (uncaught promises, missing try/catch)
8
+ - Missing loading/empty/error states in UI components
9
+ - Pagination missing on list endpoints
10
+ - TypeScript `any` or `@ts-ignore` without justification
11
+ - Console.log left in production code
12
+ - Unused imports or variables
13
+ 3. Run the project's linter if available
14
+ 4. Run `npm run build` to verify compilation
15
+ 5. Report findings with severity (critical/warning/info) and suggested fixes
@@ -0,0 +1,11 @@
1
+ Create a new project from the template structure.
2
+
3
+ Usage: /scaffold <project-name> <category>
4
+ Categories: keiy (personal), dstudio (client), bots (telegram)
5
+
6
+ Steps:
7
+ 1. Ask for project name and category if not provided
8
+ 2. Create directory in ~/Documents/Developer/<category>/<project-name>/
9
+ 3. Initialize with: git init, package.json, tsconfig.json, .env.example, .gitignore, .claudeignore
10
+ 4. Create CLAUDE.md from ~/.claude/templates/CLAUDE.md.template
11
+ 5. Report the created structure
@@ -0,0 +1,11 @@
1
+ Run the project's test suite and analyze results.
2
+
3
+ Steps:
4
+ 1. Detect test framework (look for vitest.config, jest.config, playwright.config)
5
+ 2. Run the appropriate test command
6
+ 3. If tests fail:
7
+ - Analyze each failure
8
+ - Identify root cause
9
+ - Suggest fixes (NEVER modify tests to make them pass — fix the code)
10
+ 4. Report: total tests, passed, failed, skipped
11
+ 5. If no test suite exists, report that and suggest setting one up
@@ -0,0 +1,62 @@
1
+ # Cloudflare Workers — Doc Cache Local
2
+
3
+ > Dernière mise à jour : 2026-03-03
4
+
5
+ ## Workers Basics
6
+
7
+ ### Limite clé : 50 subrequests/invocation
8
+ Pour les opérations en batch : chunking + self-invoke pattern.
9
+
10
+ ```ts
11
+ export default {
12
+ async fetch(request: Request, env: Env): Promise<Response> {
13
+ const url = new URL(request.url);
14
+ // routing
15
+ if (url.pathname === '/api/items') return handleItems(request, env);
16
+ return new Response('Not found', { status: 404 });
17
+ }
18
+ };
19
+ ```
20
+
21
+ ### D1 (SQLite)
22
+ ```ts
23
+ const { results } = await env.DB.prepare('SELECT * FROM users WHERE id = ?')
24
+ .bind(userId)
25
+ .all();
26
+ // TOUJOURS requêtes paramétrées, jamais de concaténation
27
+ ```
28
+
29
+ ### KV
30
+ ```ts
31
+ await env.KV.put('key', JSON.stringify(value), { expirationTtl: 3600 });
32
+ const data = await env.KV.get('key', 'json');
33
+ // KV est eventually consistent — pas pour les données critiques temps réel
34
+ ```
35
+
36
+ ### Durable Objects
37
+ Pour state persistent + WebSocket — utilisé dans les bots Telegram.
38
+
39
+ ## wrangler.toml
40
+ ```toml
41
+ name = "my-worker"
42
+ main = "src/index.ts"
43
+ compatibility_date = "2025-01-01"
44
+
45
+ [[d1_databases]]
46
+ binding = "DB"
47
+ database_name = "my-db"
48
+ database_id = "xxx"
49
+
50
+ [[kv_namespaces]]
51
+ binding = "KV"
52
+ id = "xxx"
53
+ ```
54
+
55
+ ## Gotchas
56
+
57
+ 1. **50 subrequests max** — inclut fetch(), D1, KV, tout appel réseau
58
+ 2. **10ms CPU time** (free) / 30s (paid) — pas de boucles longues
59
+ 3. **KV est eventually consistent** — délai de propagation ~60s
60
+ 4. **D1 est en beta** — pas de transactions imbriquées
61
+ 5. **CORS** : doit être géré manuellement dans le Worker
62
+ 6. **`ctx.waitUntil()`** pour les tâches background après la réponse
@@ -0,0 +1,79 @@
1
+ # Next.js — Doc Cache Local
2
+
3
+ > Dernière mise à jour : 2026-03-03
4
+ > Version : Next.js 15.x / 16.x (App Router)
5
+
6
+ ## App Router Essentials
7
+
8
+ ### Route Files
9
+ - `page.tsx` — route UI
10
+ - `layout.tsx` — layout partagé (ne re-render pas à la navigation)
11
+ - `loading.tsx` — Suspense boundary automatique
12
+ - `error.tsx` — error boundary (`'use client'` obligatoire)
13
+ - `not-found.tsx` — 404 page
14
+ - `route.ts` — API route (GET, POST, PUT, DELETE)
15
+
16
+ ### Server vs Client Components
17
+ - **Par défaut** : Server Component (pas de state, pas de hooks)
18
+ - `'use client'` en haut du fichier pour un Client Component
19
+ - Server Components peuvent importer Client Components, pas l'inverse
20
+ - Les props passées de Server → Client doivent être sérialisables
21
+
22
+ ### Data Fetching (App Router)
23
+ ```tsx
24
+ // Server Component — fetch direct, pas de useEffect
25
+ async function Page() {
26
+ const data = await fetch('https://api.example.com/data', {
27
+ cache: 'force-cache', // static (default)
28
+ // cache: 'no-store', // dynamic
29
+ // next: { revalidate: 60 } // ISR
30
+ });
31
+ return <div>{data}</div>;
32
+ }
33
+ ```
34
+
35
+ ### Server Actions
36
+ ```tsx
37
+ 'use server'
38
+
39
+ async function createItem(formData: FormData) {
40
+ const name = formData.get('name');
41
+ await db.insert(items).values({ name });
42
+ revalidatePath('/items');
43
+ }
44
+ ```
45
+
46
+ ## Gotchas / Pièges courants
47
+
48
+ 1. **Hydration mismatch** : ne jamais utiliser `Date.now()`, `Math.random()`, ou `localStorage` dans le render initial — toujours dans `useEffect`
49
+ 2. **`useSearchParams()`** : doit être wrappé dans `<Suspense>` sinon erreur en production
50
+ 3. **Metadata** : export `metadata` ou `generateMetadata` uniquement dans `page.tsx` et `layout.tsx`
51
+ 4. **Redirects dans Server Components** : utiliser `redirect()` de `next/navigation`, pas `router.push()`
52
+ 5. **Route handlers** : `NextRequest` et `NextResponse` — pas `req`/`res` Express-style
53
+ 6. **Middleware** : un seul fichier `middleware.ts` à la racine, matcher via config
54
+
55
+ ## Patterns récurrents
56
+
57
+ ### API Route avec validation
58
+ ```tsx
59
+ import { NextRequest, NextResponse } from 'next/server';
60
+
61
+ export async function POST(request: NextRequest) {
62
+ try {
63
+ const body = await request.json();
64
+ // validate...
65
+ return NextResponse.json({ data: result }, { status: 201 });
66
+ } catch (error) {
67
+ return NextResponse.json({ error: 'Invalid request' }, { status: 400 });
68
+ }
69
+ }
70
+ ```
71
+
72
+ ### Dynamic metadata
73
+ ```tsx
74
+ export async function generateMetadata({ params }: { params: Promise<{ id: string }> }) {
75
+ const { id } = await params; // Next.js 15+ : params is async
76
+ const item = await getItem(id);
77
+ return { title: item.name };
78
+ }
79
+ ```
@@ -0,0 +1,63 @@
1
+ # React 19 — Doc Cache Local
2
+
3
+ > Dernière mise à jour : 2026-03-03
4
+
5
+ ## React 19 Nouveautés
6
+
7
+ ### `use()` hook
8
+ ```tsx
9
+ function Component({ dataPromise }: { dataPromise: Promise<Data> }) {
10
+ const data = use(dataPromise); // suspend until resolved
11
+ return <div>{data.name}</div>;
12
+ }
13
+ ```
14
+
15
+ ### Server Components
16
+ - Pas de state, pas de hooks (sauf `use()`)
17
+ - Accès direct aux données (DB, fichiers, APIs)
18
+ - Ne sont jamais envoyés au client (0 JS)
19
+
20
+ ### Actions (form)
21
+ ```tsx
22
+ function Form() {
23
+ const [state, formAction, isPending] = useActionState(async (prev, formData) => {
24
+ const result = await submitForm(formData);
25
+ return result;
26
+ }, null);
27
+
28
+ return (
29
+ <form action={formAction}>
30
+ <input name="email" />
31
+ <button disabled={isPending}>Submit</button>
32
+ </form>
33
+ );
34
+ }
35
+ ```
36
+
37
+ ### `useOptimistic()`
38
+ ```tsx
39
+ const [optimisticItems, addOptimistic] = useOptimistic(items, (state, newItem) => [...state, newItem]);
40
+ ```
41
+
42
+ ## Patterns récurrents
43
+
44
+ ### Loading + Error + Empty states (OBLIGATOIRE)
45
+ ```tsx
46
+ function ItemList() {
47
+ const { data, isLoading, error } = useQuery(...);
48
+
49
+ if (isLoading) return <Skeleton />;
50
+ if (error) return <ErrorMessage retry={refetch} />;
51
+ if (!data?.length) return <EmptyState message="Aucun élément" />;
52
+
53
+ return <ul>{data.map(item => <li key={item.id}>{item.name}</li>)}</ul>;
54
+ }
55
+ ```
56
+
57
+ ## Gotchas
58
+
59
+ 1. **StrictMode** double-render en dev — normal, pas un bug
60
+ 2. **Key prop** : ne jamais utiliser l'index comme key si la liste peut être réordonnée
61
+ 3. **Closure stale** dans useEffect — utiliser ref ou functional update
62
+ 4. **Ref callback** : React 19 supporte le cleanup `return () => {}` dans les ref callbacks
63
+ 5. **`forwardRef` deprecated** en React 19 — `ref` est maintenant une prop normale
@@ -0,0 +1,45 @@
1
+ # Tailwind CSS v4 — Doc Cache Local
2
+
3
+ > Dernière mise à jour : 2026-03-03
4
+
5
+ ## v4 Breaking Changes
6
+
7
+ - Config via CSS (`@theme`), plus de `tailwind.config.js`
8
+ - Import : `@import "tailwindcss"` (plus de `@tailwind base/components/utilities`)
9
+ - Content detection automatique (plus besoin de `content: [...]`)
10
+
11
+ ```css
12
+ @import "tailwindcss";
13
+
14
+ @theme {
15
+ --color-primary: #3b82f6;
16
+ --font-sans: "Inter", sans-serif;
17
+ }
18
+ ```
19
+
20
+ ## Classes les plus utilisées
21
+
22
+ ### Layout
23
+ - `flex` `flex-col` `items-center` `justify-between` `gap-4`
24
+ - `grid` `grid-cols-3` `col-span-2`
25
+ - `container` `mx-auto` `max-w-7xl`
26
+
27
+ ### Spacing
28
+ - `p-4` `px-6` `py-2` `m-auto` `mt-8` `space-y-4`
29
+
30
+ ### Typography
31
+ - `text-sm` `text-lg` `text-xl` `font-bold` `font-medium`
32
+ - `text-gray-600` `text-primary` `leading-relaxed`
33
+
34
+ ### Responsive
35
+ - `sm:` (640px) `md:` (768px) `lg:` (1024px) `xl:` (1280px)
36
+
37
+ ### Dark mode
38
+ - `dark:bg-gray-900` `dark:text-white`
39
+
40
+ ## Gotchas
41
+
42
+ 1. **v4 pas de config JS** — tout est en CSS maintenant
43
+ 2. **`@apply`** fonctionne toujours mais déconseillé — préférer les classes directes
44
+ 3. **Arbitrary values** : `w-[calc(100%-2rem)]` `text-[#1a1a1a]`
45
+ 4. **Group/peer** : `group-hover:opacity-100` `peer-invalid:text-red-500`