tribunal-kit 6.0.0 → 7.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.
- package/.agent/.manifest.json +78 -0
- package/.agent/ARCHITECTURE.md +19 -241
- package/.agent/agents/accessibility-reviewer.md +23 -16
- package/.agent/agents/ai-code-reviewer.md +25 -21
- package/.agent/agents/anti-pattern-reviewer.md +12 -7
- package/.agent/agents/api-architect.md +1 -0
- package/.agent/agents/backend-specialist.md +23 -22
- package/.agent/agents/cloud-engineer.md +1 -0
- package/.agent/agents/code-archaeologist.md +1 -0
- package/.agent/agents/complexity-reviewer.md +10 -7
- package/.agent/agents/database-architect.md +3 -2
- package/.agent/agents/db-latency-auditor.md +6 -2
- package/.agent/agents/debugger.md +3 -2
- package/.agent/agents/dependency-reviewer.md +1 -0
- package/.agent/agents/devops-engineer.md +9 -8
- package/.agent/agents/documentation-writer.md +6 -5
- package/.agent/agents/explorer-agent.md +1 -0
- package/.agent/agents/frontend-reviewer.md +21 -17
- package/.agent/agents/frontend-specialist.md +23 -20
- package/.agent/agents/game-developer.md +1 -0
- package/.agent/agents/interaction-reviewer.md +10 -5
- package/.agent/agents/logic-reviewer.md +3 -0
- package/.agent/agents/minimalist-reviewer.md +6 -0
- package/.agent/agents/mobile-developer.md +7 -6
- package/.agent/agents/mobile-reviewer.md +14 -13
- package/.agent/agents/orchestrator.md +3 -0
- package/.agent/agents/penetration-tester.md +1 -0
- package/.agent/agents/performance-optimizer.md +6 -5
- package/.agent/agents/performance-reviewer.md +6 -6
- package/.agent/agents/pipeline-reviewer.md +144 -0
- package/.agent/agents/precedence-reviewer.md +1 -0
- package/.agent/agents/product-manager.md +1 -0
- package/.agent/agents/product-owner.md +1 -0
- package/.agent/agents/product-reviewer.md +12 -7
- package/.agent/agents/project-planner.md +3 -0
- package/.agent/agents/qa-automation-engineer.md +50 -43
- package/.agent/agents/resilience-reviewer.md +1 -0
- package/.agent/agents/schema-reviewer.md +1 -0
- package/.agent/agents/security-auditor.md +24 -24
- package/.agent/agents/seo-specialist.md +33 -23
- package/.agent/agents/sql-reviewer.md +5 -4
- package/.agent/agents/supervisor-agent.md +12 -2
- package/.agent/agents/swarm-worker-contracts.md +13 -13
- package/.agent/agents/swarm-worker-registry.md +51 -51
- package/.agent/agents/system-architect.md +1 -0
- package/.agent/agents/test-coverage-reviewer.md +25 -22
- package/.agent/agents/test-engineer.md +12 -11
- package/.agent/agents/throughput-optimizer.md +45 -40
- package/.agent/agents/type-safety-reviewer.md +5 -4
- package/.agent/agents/ui-ux-auditor.md +6 -4
- package/.agent/agents/ui-visual-auditor.md +3 -0
- package/.agent/agents/ux-reviewer.md +11 -6
- package/.agent/agents/visual-reviewer.md +11 -6
- package/.agent/agents/vitals-reviewer.md +5 -4
- package/.agent/history/memory/.memory.idx +3716 -1
- package/.agent/history/memory/MEMORY.md +246 -1
- package/.agent/mcp_config.json +1 -6
- package/.agent/routing_index.json +2034 -263
- package/.agent/rules/GEMINI.md +12 -10
- package/.agent/rules/GEMINI_PLANNER.md +19 -21
- package/.agent/scripts/_colors.js +52 -54
- package/.agent/scripts/_utils.js +52 -53
- package/.agent/scripts/auto_preview.js +39 -43
- package/.agent/scripts/bundle_analyzer.js +47 -60
- package/.agent/scripts/case_law_manager.js +200 -294
- package/.agent/scripts/checklist.js +73 -94
- package/.agent/scripts/cicd_validator.js +305 -0
- package/.agent/scripts/compile_router.py +4 -111
- package/.agent/scripts/context_broker.js +317 -412
- package/.agent/scripts/contract_engine.js +402 -0
- package/.agent/scripts/dependency_analyzer.js +112 -124
- package/.agent/scripts/graph_builder.js +75 -103
- package/.agent/scripts/graph_visualizer.js +10 -12
- package/.agent/scripts/graph_zoom.js +38 -55
- package/.agent/scripts/guardrail_engine.js +195 -145
- package/.agent/scripts/impact_classifier.js +55 -30
- package/.agent/scripts/inner_loop_validator.js +108 -159
- package/.agent/scripts/integrity_manifest.js +59 -67
- package/.agent/scripts/lint_runner.js +65 -75
- package/.agent/scripts/marathon_harness.js +131 -208
- package/.agent/scripts/migrate_skills_frontmatter.py +4 -63
- package/.agent/scripts/minify_context.js +29 -33
- package/.agent/scripts/minimal_change_engine.js +95 -87
- package/.agent/scripts/mutation_runner.js +46 -62
- package/.agent/scripts/pipeline_engine.js +320 -209
- package/.agent/scripts/prompt_compiler.js +118 -93
- package/.agent/scripts/schema_validator.js +73 -121
- package/.agent/scripts/security_scan.js +88 -117
- package/.agent/scripts/session_manager.js +52 -69
- package/.agent/scripts/signal_detector.js +24 -22
- package/.agent/scripts/skill_evolution.js +184 -245
- package/.agent/scripts/skill_integrator.js +35 -48
- package/.agent/scripts/socratic_gate_policy.js +15 -12
- package/.agent/scripts/strengthen_skills.js +29 -33
- package/.agent/scripts/swarm_dispatcher.js +120 -151
- package/.agent/scripts/test_runner.js +54 -56
- package/.agent/scripts/token_budget_broker.js +9 -7
- package/.agent/scripts/trace_engine.js +126 -0
- package/.agent/scripts/verify_all.js +76 -93
- package/.agent/scripts/visual_audit.js +16 -21
- package/.agent/skill_topic_map.json +237 -0
- package/.agent/skills/12-principles-of-animation/SKILL.md +7 -0
- package/.agent/skills/60fps-animation/SKILL.md +7 -0
- package/.agent/skills/accessible-animation/SKILL.md +5 -1
- package/.agent/skills/adapt/SKILL.md +7 -1
- package/.agent/skills/advanced-rag-pipelines/SKILL.md +1 -0
- package/.agent/skills/agent-organizer/SKILL.md +1 -0
- package/.agent/skills/agentic-patterns/SKILL.md +33 -25
- package/.agent/skills/agentic-workflows-2026/SKILL.md +80 -0
- package/.agent/skills/ai-app-hardening/SKILL.md +59 -0
- package/.agent/skills/ai-prompt-injection-defense/SKILL.md +7 -6
- package/.agent/skills/animation-on-scroll/SKILL.md +24 -15
- package/.agent/skills/animation-systems/SKILL.md +11 -10
- package/.agent/skills/antfu-conventions/SKILL.md +7 -2
- package/.agent/skills/api-patterns/SKILL.md +14 -10
- package/.agent/skills/api-security-auditor/SKILL.md +15 -14
- package/.agent/skills/app-builder/SKILL.md +1 -0
- package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +2 -2
- package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +12 -12
- package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +3 -3
- package/.agent/skills/apple-design/SKILL.md +8 -7
- package/.agent/skills/architecture/SKILL.md +3 -2
- package/.agent/skills/audit-and-fix/SKILL.md +8 -5
- package/.agent/skills/authentication-best-practices/SKILL.md +9 -8
- package/.agent/skills/backend-security-expert/SKILL.md +1 -0
- package/.agent/skills/baseline-ui/SKILL.md +8 -7
- package/.agent/skills/bash-linux/SKILL.md +1 -0
- package/.agent/skills/behavioral-modes/SKILL.md +1 -0
- package/.agent/skills/better-colors/SKILL.md +11 -7
- package/.agent/skills/better-typography/SKILL.md +30 -16
- package/.agent/skills/better-ui/SKILL.md +17 -10
- package/.agent/skills/bolder/SKILL.md +6 -0
- package/.agent/skills/brainstorming/SKILL.md +6 -4
- package/.agent/skills/browser-native-ai/SKILL.md +5 -4
- package/.agent/skills/build-primitive/SKILL.md +5 -0
- package/.agent/skills/building-native-ui/SKILL.md +1 -0
- package/.agent/skills/cicd-pro/SKILL.md +2 -1
- package/.agent/skills/clarify/SKILL.md +19 -14
- package/.agent/skills/clean-code/SKILL.md +16 -15
- package/.agent/skills/cloud-architect/SKILL.md +1 -0
- package/.agent/skills/cobejs/SKILL.md +7 -9
- package/.agent/skills/code-review-checklist/SKILL.md +1 -0
- package/.agent/skills/codebase-design/SKILL.md +7 -2
- package/.agent/skills/colorize/SKILL.md +8 -3
- package/.agent/skills/compact-landing/SKILL.md +8 -3
- package/.agent/skills/company-logos/SKILL.md +6 -0
- package/.agent/skills/config-validator/SKILL.md +10 -9
- package/.agent/skills/containerization-pro/SKILL.md +6 -5
- package/.agent/skills/context-engineering-pro/SKILL.md +70 -0
- package/.agent/skills/create-design-md/SKILL.md +13 -5
- package/.agent/skills/critique/SKILL.md +10 -8
- package/.agent/skills/csharp-developer/SKILL.md +1 -0
- package/.agent/skills/data-validation-schemas/SKILL.md +28 -23
- package/.agent/skills/database-design/SKILL.md +2 -1
- package/.agent/skills/delight/SKILL.md +6 -0
- package/.agent/skills/deployment-procedures/SKILL.md +2 -1
- package/.agent/skills/design-lab/SKILL.md +5 -0
- package/.agent/skills/devops-engineer/SKILL.md +3 -2
- package/.agent/skills/devops-incident-responder/SKILL.md +2 -1
- package/.agent/skills/diagnosing-bugs/SKILL.md +12 -2
- package/.agent/skills/distill/SKILL.md +7 -2
- package/.agent/skills/documentation-templates/SKILL.md +3 -2
- package/.agent/skills/domain-modeling/SKILL.md +12 -4
- package/.agent/skills/duckdb-analytical-sql/SKILL.md +59 -0
- package/.agent/skills/edge-ai-mobile/SKILL.md +50 -0
- package/.agent/skills/edge-computing/SKILL.md +9 -8
- package/.agent/skills/emil-design-eng/SKILL.md +43 -27
- package/.agent/skills/error-resilience/SKILL.md +34 -16
- package/.agent/skills/expo-router-v4/SKILL.md +81 -0
- package/.agent/skills/extract-design-system/SKILL.md +12 -11
- package/.agent/skills/fabel-protocol/SKILL.md +24 -17
- package/.agent/skills/fixing-accessibility/SKILL.md +23 -16
- package/.agent/skills/fixing-metadata/SKILL.md +24 -13
- package/.agent/skills/fixing-motion-performance/SKILL.md +7 -5
- package/.agent/skills/framer-motion-expert/SKILL.md +29 -15
- package/.agent/skills/frontend-design/SKILL.md +21 -13
- package/.agent/skills/frontend-security-expert/SKILL.md +1 -0
- package/.agent/skills/game-design-expert/SKILL.md +1 -0
- package/.agent/skills/game-engineering-expert/SKILL.md +1 -0
- package/.agent/skills/generative-ui-expert/SKILL.md +3 -2
- package/.agent/skills/geo-fundamentals/SKILL.md +2 -1
- package/.agent/skills/git-pro/SKILL.md +10 -9
- package/.agent/skills/github-operations/SKILL.md +2 -1
- package/.agent/skills/gpt-taste/SKILL.md +7 -0
- package/.agent/skills/gsap-core/SKILL.md +26 -22
- package/.agent/skills/gsap-frameworks/SKILL.md +6 -5
- package/.agent/skills/gsap-performance/SKILL.md +4 -3
- package/.agent/skills/gsap-plugins/SKILL.md +34 -33
- package/.agent/skills/gsap-react/SKILL.md +9 -8
- package/.agent/skills/gsap-scrolltrigger/SKILL.md +34 -33
- package/.agent/skills/gsap-timeline/SKILL.md +18 -15
- package/.agent/skills/gsap-utils/SKILL.md +25 -24
- package/.agent/skills/harden/SKILL.md +9 -3
- package/.agent/skills/harness-protocol/SKILL.md +1 -0
- package/.agent/skills/i18n-localization/SKILL.md +10 -9
- package/.agent/skills/impeccable/SKILL.md +5 -0
- package/.agent/skills/improve-codebase-architecture/SKILL.md +10 -5
- package/.agent/skills/improve-ui/SKILL.md +12 -5
- package/.agent/skills/intelligent-routing/SKILL.md +7 -6
- package/.agent/skills/knowledge-graph/SKILL.md +1 -0
- package/.agent/skills/landing-page/SKILL.md +1 -0
- package/.agent/skills/lint-and-validate/SKILL.md +9 -4
- package/.agent/skills/llm-engineering/SKILL.md +55 -54
- package/.agent/skills/local-first/SKILL.md +20 -19
- package/.agent/skills/local-first-architecture/SKILL.md +6 -1
- package/.agent/skills/lottie-animation/SKILL.md +7 -3
- package/.agent/skills/marquee-loop/SKILL.md +1 -0
- package/.agent/skills/masked-reveal/SKILL.md +17 -4
- package/.agent/skills/mcp-builder/SKILL.md +13 -10
- package/.agent/skills/micro-interaction/SKILL.md +20 -5
- package/.agent/skills/mobile-design/SKILL.md +26 -15
- package/.agent/skills/monorepo-management/SKILL.md +3 -2
- package/.agent/skills/morphing-icons/SKILL.md +16 -6
- package/.agent/skills/motion-engineering/SKILL.md +19 -15
- package/.agent/skills/nextjs-react-expert/SKILL.md +26 -21
- package/.agent/skills/nodejs-best-practices/SKILL.md +89 -76
- package/.agent/skills/observability/SKILL.md +45 -44
- package/.agent/skills/opentelemetry-observability/SKILL.md +59 -0
- package/.agent/skills/page-transition-animation/SKILL.md +6 -3
- package/.agent/skills/parallel-agents/SKILL.md +7 -2
- package/.agent/skills/performance-profiling/SKILL.md +24 -13
- package/.agent/skills/plan-writing/SKILL.md +1 -0
- package/.agent/skills/platform-engineer/SKILL.md +3 -2
- package/.agent/skills/platform-engineering-opentofu/SKILL.md +68 -0
- package/.agent/skills/playwright-ai-e2e/SKILL.md +60 -0
- package/.agent/skills/playwright-best-practices/SKILL.md +29 -28
- package/.agent/skills/polish/SKILL.md +13 -12
- package/.agent/skills/powershell-windows/SKILL.md +1 -0
- package/.agent/skills/pricing-page/SKILL.md +8 -3
- package/.agent/skills/product-aware-heuristics/SKILL.md +122 -72
- package/.agent/skills/progressive-blur/SKILL.md +9 -4
- package/.agent/skills/project-idioms/SKILL.md +1 -0
- package/.agent/skills/property-based-testing/SKILL.md +58 -0
- package/.agent/skills/python-patterns/SKILL.md +1 -0
- package/.agent/skills/python-pro/SKILL.md +1 -0
- package/.agent/skills/quieter/SKILL.md +6 -0
- package/.agent/skills/react-doctor/SKILL.md +6 -0
- package/.agent/skills/react-specialist/SKILL.md +32 -28
- package/.agent/skills/readme-builder/SKILL.md +1 -0
- package/.agent/skills/realtime-patterns/SKILL.md +34 -33
- package/.agent/skills/red-team-tactics/SKILL.md +1 -0
- package/.agent/skills/redesign-skill/SKILL.md +6 -0
- package/.agent/skills/review-animations/SKILL.md +5 -2
- package/.agent/skills/review-animations/STANDARDS.md +37 -23
- package/.agent/skills/rust-pro/SKILL.md +1 -0
- package/.agent/skills/seo-fundamentals/SKILL.md +4 -3
- package/.agent/skills/server-management/SKILL.md +1 -0
- package/.agent/skills/shadcn-ui-expert/SKILL.md +28 -22
- package/.agent/skills/shape/SKILL.md +9 -2
- package/.agent/skills/skill-creator/SKILL.md +1 -0
- package/.agent/skills/soft-skill/SKILL.md +6 -0
- package/.agent/skills/sounds-on-the-web/SKILL.md +1 -0
- package/.agent/skills/sql-pro/SKILL.md +1 -0
- package/.agent/skills/supabase-postgres-best-practices/SKILL.md +1 -0
- package/.agent/skills/svg-animation/SKILL.md +16 -7
- package/.agent/skills/swiftui-expert/SKILL.md +1 -0
- package/.agent/skills/swiss-design/SKILL.md +5 -0
- package/.agent/skills/system-design-pro/SKILL.md +1 -0
- package/.agent/skills/systematic-debugging/SKILL.md +1 -0
- package/.agent/skills/tailwind-patterns/SKILL.md +25 -11
- package/.agent/skills/taste-skill/SKILL.md +6 -0
- package/.agent/skills/tdd-workflow/SKILL.md +5 -0
- package/.agent/skills/test-result-analyzer/SKILL.md +1 -0
- package/.agent/skills/testing-patterns/SKILL.md +123 -115
- package/.agent/skills/thermo-nuclear-code-quality-review/SKILL.md +5 -0
- package/.agent/skills/thinking-protocol/SKILL.md +3 -0
- package/.agent/skills/to-spring-or-not-to-spring/SKILL.md +9 -8
- package/.agent/skills/transitions-dev/SKILL.md +19 -6
- package/.agent/skills/trend-researcher/SKILL.md +1 -0
- package/.agent/skills/typescript-advanced/SKILL.md +23 -18
- package/.agent/skills/typeset/SKILL.md +10 -1
- package/.agent/skills/ui-reasoning-engine/SKILL.md +67 -48
- package/.agent/skills/ui-skill-packs/SKILL.md +6 -1
- package/.agent/skills/ui-skills-root/SKILL.md +39 -38
- package/.agent/skills/ui-ux-pro-max/SKILL.md +34 -26
- package/.agent/skills/ui-ux-researcher/SKILL.md +1 -0
- package/.agent/skills/vector-search-pgvector/SKILL.md +78 -0
- package/.agent/skills/vue-expert/SKILL.md +22 -19
- package/.agent/skills/vulnerability-scanner/SKILL.md +22 -21
- package/.agent/skills/web-accessibility-auditor/SKILL.md +2 -1
- package/.agent/skills/web-design-guidelines/SKILL.md +16 -10
- package/.agent/skills/web-quality-audit/SKILL.md +5 -0
- package/.agent/skills/webapp-testing/SKILL.md +14 -13
- package/.agent/skills/webgpu-performance/SKILL.md +1 -0
- package/.agent/skills/whimsy-injector/SKILL.md +9 -5
- package/.agent/skills/workflow-optimizer/SKILL.md +1 -0
- package/.agent/skills/zero-trust-passkeys/SKILL.md +90 -0
- package/.agent/templates/DESIGN.md +119 -110
- package/.agent/templates/design-tokens.json +9 -6
- package/.agent/workflows/acf.md +1 -0
- package/.agent/workflows/api-tester.md +1 -0
- package/.agent/workflows/audit.md +1 -0
- package/.agent/workflows/brainstorm.md +1 -0
- package/.agent/workflows/changelog.md +1 -0
- package/.agent/workflows/contract.md +60 -0
- package/.agent/workflows/create.md +1 -0
- package/.agent/workflows/debug.md +1 -0
- package/.agent/workflows/deploy.md +1 -0
- package/.agent/workflows/enhance.md +1 -0
- package/.agent/workflows/fix-ci.md +89 -0
- package/.agent/workflows/fix.md +1 -0
- package/.agent/workflows/generate.md +1 -0
- package/.agent/workflows/marathon.md +1 -0
- package/.agent/workflows/migrate.md +1 -0
- package/.agent/workflows/minimal.md +9 -7
- package/.agent/workflows/orchestrate.md +1 -0
- package/.agent/workflows/performance-benchmarker.md +1 -0
- package/.agent/workflows/pipeline.md +26 -21
- package/.agent/workflows/plan.md +1 -0
- package/.agent/workflows/preview.md +1 -0
- package/.agent/workflows/refactor.md +3 -2
- package/.agent/workflows/review-ai.md +4 -3
- package/.agent/workflows/review.md +1 -0
- package/.agent/workflows/session.md +1 -0
- package/.agent/workflows/status.md +1 -0
- package/.agent/workflows/strengthen-skills.md +1 -0
- package/.agent/workflows/super-prompt.md +1 -0
- package/.agent/workflows/swarm.md +15 -3
- package/.agent/workflows/test.md +8 -7
- package/.agent/workflows/tribunal-backend.md +3 -2
- package/.agent/workflows/tribunal-cicd.md +104 -0
- package/.agent/workflows/tribunal-database.md +1 -0
- package/.agent/workflows/tribunal-frontend.md +8 -6
- package/.agent/workflows/tribunal-full.md +15 -14
- package/.agent/workflows/tribunal-mobile.md +6 -5
- package/.agent/workflows/tribunal-performance.md +1 -0
- package/.agent/workflows/tribunal-speed.md +1 -0
- package/.agent/workflows/tribunal-ui.md +29 -21
- package/.agent/workflows/ui-ux-pro-max.md +19 -15
- package/CONTRIBUTING.md +3 -3
- package/README.md +160 -88
- package/SECURITY.md +11 -11
- package/bin/mcp-server.js +512 -233
- package/bin/tribunal-kit.js +29 -30
- package/bin/wrapper.js +45 -48
- package/dist/cli.js +26 -0
- package/dist/commands/case.js +2 -0
- package/dist/commands/contract.js +440 -0
- package/dist/commands/memory.js +3 -2
- package/dist/commands/native.js +36 -0
- package/dist/commands/status.js +6 -0
- package/dist/esm/index.mjs +32 -0
- package/dist/index.d.ts +58 -3
- package/package.json +20 -16
- package/scripts/benchmark.js +62 -86
- package/scripts/changelog.js +67 -73
- package/scripts/fix-vbc.js +13 -15
- package/scripts/fix-vbc.ps1 +2 -118
- package/scripts/stress_benchmark.js +358 -0
- package/scripts/sync-version.js +71 -41
- package/scripts/validate-payload.js +23 -30
- package/scripts/visual_audit.js +23 -13
|
@@ -20,6 +20,7 @@ scripts-binding:
|
|
|
20
20
|
## Mandatory Pre-Flight Context Inspection
|
|
21
21
|
|
|
22
22
|
Before building Node.js services or middleware, you MUST inspect:
|
|
23
|
+
|
|
23
24
|
1. Node Built-in Import Protocol (Section 34) → Use explicit `node:` prefix (`import fs from "node:fs/promises"`); ban legacy CommonJS `require()`
|
|
24
25
|
2. Mandatory Process Exit on Uncaught Exception (Section 170) → Ensure process exits (`process.exit(1)`) after `uncaughtException` to prevent running in corrupted state
|
|
25
26
|
3. Startup Environment Validation (Section 373) → Validate environment variables at app startup with Zod; crash immediately if required secrets are missing
|
|
@@ -40,10 +41,10 @@ Before building Node.js services or middleware, you MUST inspect:
|
|
|
40
41
|
|
|
41
42
|
```typescript
|
|
42
43
|
// ✅ ESM imports (modern Node.js)
|
|
43
|
-
import { readFile, writeFile } from
|
|
44
|
-
import { join, resolve } from
|
|
45
|
-
import { createServer } from
|
|
46
|
-
import { EventEmitter } from
|
|
44
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
45
|
+
import { join, resolve } from 'node:path';
|
|
46
|
+
import { createServer } from 'node:http';
|
|
47
|
+
import { EventEmitter } from 'node:events';
|
|
47
48
|
|
|
48
49
|
// ❌ HALLUCINATION TRAP: Use node: protocol prefix for built-in modules
|
|
49
50
|
// ❌ import fs from "fs"; ← ambiguous (could be npm package)
|
|
@@ -54,7 +55,7 @@ import { EventEmitter } from "node:events";
|
|
|
54
55
|
// ✅ import fs from "node:fs/promises"; ← ESM
|
|
55
56
|
|
|
56
57
|
// Dynamic imports (for conditional loading)
|
|
57
|
-
const module = await import(
|
|
58
|
+
const module = await import('./heavy-module.js');
|
|
58
59
|
```
|
|
59
60
|
|
|
60
61
|
---
|
|
@@ -76,13 +77,13 @@ const module = await import("./heavy-module.js");
|
|
|
76
77
|
### Fastify (Recommended)
|
|
77
78
|
|
|
78
79
|
```typescript
|
|
79
|
-
import Fastify from
|
|
80
|
-
import { z } from
|
|
80
|
+
import Fastify from 'fastify';
|
|
81
|
+
import { z } from 'zod';
|
|
81
82
|
|
|
82
83
|
const app = Fastify({
|
|
83
84
|
logger: {
|
|
84
|
-
level: process.env.LOG_LEVEL ??
|
|
85
|
-
transport: process.env.NODE_ENV ===
|
|
85
|
+
level: process.env.LOG_LEVEL ?? 'info',
|
|
86
|
+
transport: process.env.NODE_ENV === 'development' ? { target: 'pino-pretty' } : undefined,
|
|
86
87
|
},
|
|
87
88
|
});
|
|
88
89
|
|
|
@@ -90,22 +91,22 @@ const app = Fastify({
|
|
|
90
91
|
const CreateUserSchema = z.object({
|
|
91
92
|
name: z.string().min(2).max(100),
|
|
92
93
|
email: z.string().email(),
|
|
93
|
-
role: z.enum([
|
|
94
|
+
role: z.enum(['admin', 'user']).default('user'),
|
|
94
95
|
});
|
|
95
96
|
|
|
96
97
|
type CreateUserBody = z.infer<typeof CreateUserSchema>;
|
|
97
98
|
|
|
98
99
|
app.post<{ Body: CreateUserBody }>(
|
|
99
|
-
|
|
100
|
+
'/users',
|
|
100
101
|
{
|
|
101
102
|
schema: {
|
|
102
103
|
body: {
|
|
103
|
-
type:
|
|
104
|
-
required: [
|
|
104
|
+
type: 'object',
|
|
105
|
+
required: ['name', 'email'],
|
|
105
106
|
properties: {
|
|
106
|
-
name: { type:
|
|
107
|
-
email: { type:
|
|
108
|
-
role: { type:
|
|
107
|
+
name: { type: 'string', minLength: 2 },
|
|
108
|
+
email: { type: 'string', format: 'email' },
|
|
109
|
+
role: { type: 'string', enum: ['admin', 'user'] },
|
|
109
110
|
},
|
|
110
111
|
},
|
|
111
112
|
},
|
|
@@ -120,7 +121,7 @@ app.post<{ Body: CreateUserBody }>(
|
|
|
120
121
|
// Graceful shutdown
|
|
121
122
|
const start = async () => {
|
|
122
123
|
try {
|
|
123
|
-
await app.listen({ port: 3000, host:
|
|
124
|
+
await app.listen({ port: 3000, host: '0.0.0.0' });
|
|
124
125
|
} catch (err) {
|
|
125
126
|
app.log.error(err);
|
|
126
127
|
process.exit(1);
|
|
@@ -133,29 +134,29 @@ start();
|
|
|
133
134
|
### Hono (Edge-First)
|
|
134
135
|
|
|
135
136
|
```typescript
|
|
136
|
-
import { Hono } from
|
|
137
|
-
import { cors } from
|
|
138
|
-
import { logger } from
|
|
139
|
-
import { zValidator } from
|
|
140
|
-
import { z } from
|
|
137
|
+
import { Hono } from 'hono';
|
|
138
|
+
import { cors } from 'hono/cors';
|
|
139
|
+
import { logger } from 'hono/logger';
|
|
140
|
+
import { zValidator } from '@hono/zod-validator';
|
|
141
|
+
import { z } from 'zod';
|
|
141
142
|
|
|
142
143
|
const app = new Hono();
|
|
143
144
|
|
|
144
|
-
app.use(
|
|
145
|
-
app.use(
|
|
145
|
+
app.use('*', logger());
|
|
146
|
+
app.use('*', cors({ origin: 'https://myapp.com' }));
|
|
146
147
|
|
|
147
148
|
const createUserSchema = z.object({
|
|
148
149
|
name: z.string().min(2),
|
|
149
150
|
email: z.string().email(),
|
|
150
151
|
});
|
|
151
152
|
|
|
152
|
-
app.post(
|
|
153
|
-
const body = c.req.valid(
|
|
153
|
+
app.post('/users', zValidator('json', createUserSchema), async c => {
|
|
154
|
+
const body = c.req.valid('json');
|
|
154
155
|
const user = await createUser(body);
|
|
155
156
|
return c.json(user, 201);
|
|
156
157
|
});
|
|
157
158
|
|
|
158
|
-
app.get(
|
|
159
|
+
app.get('/health', c => c.json({ status: 'ok' }));
|
|
159
160
|
|
|
160
161
|
export default app; // works in Node, Deno, Bun, Cloudflare Workers
|
|
161
162
|
```
|
|
@@ -168,15 +169,15 @@ export default app; // works in Node, Deno, Bun, Cloudflare Workers
|
|
|
168
169
|
|
|
169
170
|
```typescript
|
|
170
171
|
// ✅ MANDATORY: Handle unhandled rejections and exceptions
|
|
171
|
-
process.on(
|
|
172
|
-
console.error(
|
|
172
|
+
process.on('unhandledRejection', (reason, promise) => {
|
|
173
|
+
console.error('Unhandled Rejection at:', promise, 'reason:', reason);
|
|
173
174
|
// Log to error tracking service (Sentry, etc.)
|
|
174
175
|
// Gracefully shutdown
|
|
175
176
|
process.exit(1);
|
|
176
177
|
});
|
|
177
178
|
|
|
178
|
-
process.on(
|
|
179
|
-
console.error(
|
|
179
|
+
process.on('uncaughtException', error => {
|
|
180
|
+
console.error('Uncaught Exception:', error);
|
|
180
181
|
// Log to error tracking service
|
|
181
182
|
process.exit(1); // MUST exit — state is corrupted
|
|
182
183
|
});
|
|
@@ -194,18 +195,18 @@ export class AppError extends Error {
|
|
|
194
195
|
constructor(
|
|
195
196
|
message: string,
|
|
196
197
|
public statusCode: number = 500,
|
|
197
|
-
public code: string =
|
|
198
|
+
public code: string = 'INTERNAL_ERROR',
|
|
198
199
|
public isOperational: boolean = true,
|
|
199
200
|
) {
|
|
200
201
|
super(message);
|
|
201
|
-
this.name =
|
|
202
|
+
this.name = 'AppError';
|
|
202
203
|
Error.captureStackTrace(this, this.constructor);
|
|
203
204
|
}
|
|
204
205
|
}
|
|
205
206
|
|
|
206
207
|
export class NotFoundError extends AppError {
|
|
207
208
|
constructor(resource: string, id: string) {
|
|
208
|
-
super(`${resource} '${id}' not found`, 404,
|
|
209
|
+
super(`${resource} '${id}' not found`, 404, 'NOT_FOUND');
|
|
209
210
|
}
|
|
210
211
|
}
|
|
211
212
|
|
|
@@ -214,13 +215,13 @@ export class ValidationError extends AppError {
|
|
|
214
215
|
message: string,
|
|
215
216
|
public errors: Record<string, string[]> = {},
|
|
216
217
|
) {
|
|
217
|
-
super(message, 400,
|
|
218
|
+
super(message, 400, 'VALIDATION_ERROR');
|
|
218
219
|
}
|
|
219
220
|
}
|
|
220
221
|
|
|
221
222
|
export class UnauthorizedError extends AppError {
|
|
222
|
-
constructor(message =
|
|
223
|
-
super(message, 401,
|
|
223
|
+
constructor(message = 'Authentication required') {
|
|
224
|
+
super(message, 401, 'UNAUTHORIZED');
|
|
224
225
|
}
|
|
225
226
|
}
|
|
226
227
|
|
|
@@ -232,9 +233,9 @@ app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
|
|
|
232
233
|
});
|
|
233
234
|
} else {
|
|
234
235
|
// Programmer error — log and return generic message
|
|
235
|
-
console.error(
|
|
236
|
+
console.error('Unexpected error:', err);
|
|
236
237
|
res.status(500).json({
|
|
237
|
-
error: { code:
|
|
238
|
+
error: { code: 'INTERNAL_ERROR', message: 'Something went wrong' },
|
|
238
239
|
});
|
|
239
240
|
}
|
|
240
241
|
});
|
|
@@ -262,13 +263,17 @@ const [users, posts, stats] = await Promise.all([
|
|
|
262
263
|
// Total: ~200ms
|
|
263
264
|
|
|
264
265
|
// Promise.allSettled — when some can fail
|
|
265
|
-
const results = await Promise.allSettled([
|
|
266
|
+
const results = await Promise.allSettled([
|
|
267
|
+
fetchCriticalData(),
|
|
268
|
+
fetchOptionalData(),
|
|
269
|
+
fetchAnalytics(),
|
|
270
|
+
]);
|
|
266
271
|
|
|
267
272
|
for (const result of results) {
|
|
268
|
-
if (result.status ===
|
|
273
|
+
if (result.status === 'fulfilled') {
|
|
269
274
|
process(result.value);
|
|
270
275
|
} else {
|
|
271
|
-
console.error(
|
|
276
|
+
console.error('Failed:', result.reason);
|
|
272
277
|
}
|
|
273
278
|
}
|
|
274
279
|
```
|
|
@@ -276,7 +281,10 @@ for (const result of results) {
|
|
|
276
281
|
### Retry Pattern
|
|
277
282
|
|
|
278
283
|
```typescript
|
|
279
|
-
async function withRetry<T>(
|
|
284
|
+
async function withRetry<T>(
|
|
285
|
+
fn: () => Promise<T>,
|
|
286
|
+
options: { maxRetries?: number; baseDelay?: number; maxDelay?: number } = {},
|
|
287
|
+
): Promise<T> {
|
|
280
288
|
const { maxRetries = 3, baseDelay = 1000, maxDelay = 10000 } = options;
|
|
281
289
|
|
|
282
290
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
@@ -288,14 +296,14 @@ async function withRetry<T>(fn: () => Promise<T>, options: { maxRetries?: number
|
|
|
288
296
|
const delay = Math.min(baseDelay * 2 ** attempt, maxDelay);
|
|
289
297
|
const jitter = delay * (0.5 + Math.random() * 0.5);
|
|
290
298
|
console.warn(`Attempt ${attempt + 1} failed, retrying in ${jitter}ms`);
|
|
291
|
-
await new Promise(
|
|
299
|
+
await new Promise(resolve => setTimeout(resolve, jitter));
|
|
292
300
|
}
|
|
293
301
|
}
|
|
294
|
-
throw new Error(
|
|
302
|
+
throw new Error('Unreachable');
|
|
295
303
|
}
|
|
296
304
|
|
|
297
305
|
// Usage:
|
|
298
|
-
const data = await withRetry(() => fetch(
|
|
306
|
+
const data = await withRetry(() => fetch('https://api.flaky.com/data'), {
|
|
299
307
|
maxRetries: 3,
|
|
300
308
|
baseDelay: 500,
|
|
301
309
|
});
|
|
@@ -312,7 +320,7 @@ async function fetchWithTimeout(url: string, timeoutMs = 5000): Promise<Response
|
|
|
312
320
|
const response = await fetch(url, { signal: controller.signal });
|
|
313
321
|
return response;
|
|
314
322
|
} catch (error) {
|
|
315
|
-
if (error instanceof DOMException && error.name ===
|
|
323
|
+
if (error instanceof DOMException && error.name === 'AbortError') {
|
|
316
324
|
throw new Error(`Request to ${url} timed out after ${timeoutMs}ms`);
|
|
317
325
|
}
|
|
318
326
|
throw error;
|
|
@@ -327,9 +335,9 @@ async function fetchWithTimeout(url: string, timeoutMs = 5000): Promise<Response
|
|
|
327
335
|
## Streaming
|
|
328
336
|
|
|
329
337
|
```typescript
|
|
330
|
-
import { Readable, Transform, pipeline } from
|
|
331
|
-
import { createReadStream, createWriteStream } from
|
|
332
|
-
import { createGzip } from
|
|
338
|
+
import { Readable, Transform, pipeline } from 'node:stream/promises';
|
|
339
|
+
import { createReadStream, createWriteStream } from 'node:fs';
|
|
340
|
+
import { createGzip } from 'node:zlib';
|
|
333
341
|
|
|
334
342
|
// Stream large file processing (no memory issues)
|
|
335
343
|
async function processLargeCSV(inputPath: string, outputPath: string) {
|
|
@@ -340,20 +348,25 @@ async function processLargeCSV(inputPath: string, outputPath: string) {
|
|
|
340
348
|
},
|
|
341
349
|
});
|
|
342
350
|
|
|
343
|
-
await pipeline(
|
|
351
|
+
await pipeline(
|
|
352
|
+
createReadStream(inputPath),
|
|
353
|
+
transform,
|
|
354
|
+
createGzip(),
|
|
355
|
+
createWriteStream(outputPath),
|
|
356
|
+
);
|
|
344
357
|
}
|
|
345
358
|
|
|
346
359
|
// Streaming HTTP response
|
|
347
|
-
app.get(
|
|
348
|
-
res.setHeader(
|
|
349
|
-
res.setHeader(
|
|
360
|
+
app.get('/export', async (req, res) => {
|
|
361
|
+
res.setHeader('Content-Type', 'text/csv');
|
|
362
|
+
res.setHeader('Content-Disposition', 'attachment; filename=export.csv');
|
|
350
363
|
|
|
351
|
-
const cursor = db.collection(
|
|
352
|
-
cursor.on(
|
|
364
|
+
const cursor = db.collection('users').find().stream();
|
|
365
|
+
cursor.on('data', user => {
|
|
353
366
|
res.write(`${user.id},${user.name},${user.email}\n`);
|
|
354
367
|
});
|
|
355
|
-
cursor.on(
|
|
356
|
-
cursor.on(
|
|
368
|
+
cursor.on('end', () => res.end());
|
|
369
|
+
cursor.on('error', err => {
|
|
357
370
|
console.error(err);
|
|
358
371
|
res.status(500).end();
|
|
359
372
|
});
|
|
@@ -370,16 +383,16 @@ app.get("/export", async (req, res) => {
|
|
|
370
383
|
|
|
371
384
|
```typescript
|
|
372
385
|
// config.ts — centralized, validated configuration
|
|
373
|
-
import { z } from
|
|
386
|
+
import { z } from 'zod';
|
|
374
387
|
|
|
375
388
|
const envSchema = z.object({
|
|
376
|
-
NODE_ENV: z.enum([
|
|
389
|
+
NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
|
|
377
390
|
PORT: z.coerce.number().default(3000),
|
|
378
391
|
DATABASE_URL: z.string().url(),
|
|
379
392
|
REDIS_URL: z.string().url().optional(),
|
|
380
393
|
JWT_SECRET: z.string().min(32),
|
|
381
|
-
CORS_ORIGIN: z.string().default(
|
|
382
|
-
LOG_LEVEL: z.enum([
|
|
394
|
+
CORS_ORIGIN: z.string().default('http://localhost:5173'),
|
|
395
|
+
LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
|
|
383
396
|
});
|
|
384
397
|
|
|
385
398
|
export const config = envSchema.parse(process.env);
|
|
@@ -398,27 +411,27 @@ export const config = envSchema.parse(process.env);
|
|
|
398
411
|
## Security Hardening
|
|
399
412
|
|
|
400
413
|
```typescript
|
|
401
|
-
import helmet from
|
|
402
|
-
import rateLimit from
|
|
414
|
+
import helmet from 'helmet';
|
|
415
|
+
import rateLimit from 'express-rate-limit';
|
|
403
416
|
|
|
404
417
|
// Security headers
|
|
405
418
|
app.use(helmet());
|
|
406
419
|
|
|
407
420
|
// Rate limiting
|
|
408
421
|
app.use(
|
|
409
|
-
|
|
422
|
+
'/api/',
|
|
410
423
|
rateLimit({
|
|
411
424
|
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
412
425
|
max: 100, // 100 requests per window
|
|
413
426
|
standardHeaders: true,
|
|
414
427
|
legacyHeaders: false,
|
|
415
|
-
message: { error:
|
|
428
|
+
message: { error: 'Too many requests, try again later' },
|
|
416
429
|
}),
|
|
417
430
|
);
|
|
418
431
|
|
|
419
432
|
// Auth rate limiting (stricter)
|
|
420
433
|
app.use(
|
|
421
|
-
|
|
434
|
+
'/api/auth/',
|
|
422
435
|
rateLimit({
|
|
423
436
|
windowMs: 15 * 60 * 1000,
|
|
424
437
|
max: 5, // only 5 login attempts per 15 min
|
|
@@ -426,7 +439,7 @@ app.use(
|
|
|
426
439
|
);
|
|
427
440
|
|
|
428
441
|
// Input validation (ALWAYS validate)
|
|
429
|
-
app.post(
|
|
442
|
+
app.post('/api/users', async (req, res, next) => {
|
|
430
443
|
try {
|
|
431
444
|
const data = CreateUserSchema.parse(req.body); // Zod validates
|
|
432
445
|
const user = await createUser(data);
|
|
@@ -441,12 +454,12 @@ app.post("/api/users", async (req, res, next) => {
|
|
|
441
454
|
// ✅ db.query("SELECT * FROM users WHERE id = $1", [req.params.id]);
|
|
442
455
|
|
|
443
456
|
// Path traversal prevention
|
|
444
|
-
import { resolve, normalize } from
|
|
457
|
+
import { resolve, normalize } from 'node:path';
|
|
445
458
|
|
|
446
459
|
function safePath(userInput: string, baseDir: string): string {
|
|
447
460
|
const resolved = resolve(baseDir, normalize(userInput));
|
|
448
461
|
if (!resolved.startsWith(baseDir)) {
|
|
449
|
-
throw new Error(
|
|
462
|
+
throw new Error('Path traversal detected');
|
|
450
463
|
}
|
|
451
464
|
return resolved;
|
|
452
465
|
}
|
|
@@ -473,29 +486,29 @@ async function gracefulShutdown(signal: string) {
|
|
|
473
486
|
|
|
474
487
|
// Allow in-flight requests 10s to complete
|
|
475
488
|
setTimeout(() => {
|
|
476
|
-
console.error(
|
|
489
|
+
console.error('Forceful shutdown after timeout');
|
|
477
490
|
process.exit(1);
|
|
478
491
|
}, 10000);
|
|
479
492
|
|
|
480
493
|
process.exit(0);
|
|
481
494
|
}
|
|
482
495
|
|
|
483
|
-
process.on(
|
|
484
|
-
process.on(
|
|
496
|
+
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
|
|
497
|
+
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
|
|
485
498
|
```
|
|
486
499
|
|
|
487
500
|
### Worker Threads (CPU-Bound)
|
|
488
501
|
|
|
489
502
|
```typescript
|
|
490
|
-
import { Worker, isMainThread, parentPort, workerData } from
|
|
503
|
+
import { Worker, isMainThread, parentPort, workerData } from 'node:worker_threads';
|
|
491
504
|
|
|
492
505
|
if (isMainThread) {
|
|
493
506
|
// Main thread — offload CPU work
|
|
494
507
|
function runWorker(data: unknown): Promise<unknown> {
|
|
495
508
|
return new Promise((resolve, reject) => {
|
|
496
509
|
const worker = new Worker(new URL(import.meta.url), { workerData: data });
|
|
497
|
-
worker.on(
|
|
498
|
-
worker.on(
|
|
510
|
+
worker.on('message', resolve);
|
|
511
|
+
worker.on('error', reject);
|
|
499
512
|
});
|
|
500
513
|
}
|
|
501
514
|
|
|
@@ -20,6 +20,7 @@ scripts-binding:
|
|
|
20
20
|
## Mandatory Pre-Flight Context Inspection
|
|
21
21
|
|
|
22
22
|
Before instrumenting applications for observability, you MUST inspect:
|
|
23
|
+
|
|
23
24
|
1. Structured JSON Logging Rule (Section 34) → Use Pino/structlog for structured JSON logging with ISO timestamps; ban plain `console.log` in production
|
|
24
25
|
2. Separation of Liveness & Readiness Checks (Section 253) → Isolate `/health/live` (process active) from `/health/ready` (DB connected); ban DB calls in liveness checks to prevent restart loops
|
|
25
26
|
3. Correlation Tracking Context (Section 80) → Inject `x-request-id` via AsyncLocalStorage or middleware so every log line is correlated to a specific request
|
|
@@ -43,25 +44,25 @@ All three are needed. Logs alone are not observability.
|
|
|
43
44
|
## Structured Logging
|
|
44
45
|
|
|
45
46
|
```typescript
|
|
46
|
-
import pino from
|
|
47
|
+
import pino from 'pino';
|
|
47
48
|
|
|
48
49
|
// ✅ Structured JSON logging
|
|
49
50
|
const logger = pino({
|
|
50
|
-
level: process.env.LOG_LEVEL ??
|
|
51
|
+
level: process.env.LOG_LEVEL ?? 'info',
|
|
51
52
|
timestamp: pino.stdTimeFunctions.isoTime,
|
|
52
|
-
...(process.env.NODE_ENV ===
|
|
53
|
-
transport: { target:
|
|
53
|
+
...(process.env.NODE_ENV === 'development' && {
|
|
54
|
+
transport: { target: 'pino-pretty' },
|
|
54
55
|
}),
|
|
55
56
|
});
|
|
56
57
|
|
|
57
58
|
// ✅ GOOD: Structured with context
|
|
58
|
-
logger.info({ userId: user.id, action:
|
|
59
|
-
logger.error({ err, orderId: order.id, paymentGateway:
|
|
60
|
-
logger.warn({ queueDepth: 1500, threshold: 1000 },
|
|
59
|
+
logger.info({ userId: user.id, action: 'login', ip: req.ip }, 'User logged in');
|
|
60
|
+
logger.error({ err, orderId: order.id, paymentGateway: 'stripe' }, 'Payment failed');
|
|
61
|
+
logger.warn({ queueDepth: 1500, threshold: 1000 }, 'Queue depth exceeding threshold');
|
|
61
62
|
|
|
62
63
|
// ❌ BAD: Unstructured string logging
|
|
63
|
-
console.log(
|
|
64
|
-
console.log(
|
|
64
|
+
console.log('User ' + user.id + ' logged in from ' + req.ip);
|
|
65
|
+
console.log('Error: ' + error.message);
|
|
65
66
|
|
|
66
67
|
// ❌ HALLUCINATION TRAP: console.log is NOT production logging
|
|
67
68
|
// - No severity levels (info/warn/error)
|
|
@@ -92,14 +93,14 @@ Rules:
|
|
|
92
93
|
### Request Context / Correlation
|
|
93
94
|
|
|
94
95
|
```typescript
|
|
95
|
-
import { AsyncLocalStorage } from
|
|
96
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
96
97
|
|
|
97
98
|
const requestContext = new AsyncLocalStorage<{ requestId: string; userId?: string }>();
|
|
98
99
|
|
|
99
100
|
// Middleware: set context per request
|
|
100
101
|
app.use((req, res, next) => {
|
|
101
|
-
const requestId = req.headers[
|
|
102
|
-
res.setHeader(
|
|
102
|
+
const requestId = req.headers['x-request-id']?.toString() ?? crypto.randomUUID();
|
|
103
|
+
res.setHeader('x-request-id', requestId);
|
|
103
104
|
requestContext.run({ requestId, userId: req.user?.id }, next);
|
|
104
105
|
});
|
|
105
106
|
|
|
@@ -114,7 +115,7 @@ function getLogger() {
|
|
|
114
115
|
|
|
115
116
|
// Every log from this request includes requestId and userId
|
|
116
117
|
const log = getLogger();
|
|
117
|
-
log.info(
|
|
118
|
+
log.info('Processing order'); // { requestId: "abc-123", userId: "42", msg: "Processing order" }
|
|
118
119
|
```
|
|
119
120
|
|
|
120
121
|
---
|
|
@@ -122,21 +123,21 @@ log.info("Processing order"); // { requestId: "abc-123", userId: "42", msg: "Pro
|
|
|
122
123
|
## Distributed Tracing (OpenTelemetry)
|
|
123
124
|
|
|
124
125
|
```typescript
|
|
125
|
-
import { NodeSDK } from
|
|
126
|
-
import { getNodeAutoInstrumentations } from
|
|
127
|
-
import { OTLPTraceExporter } from
|
|
126
|
+
import { NodeSDK } from '@opentelemetry/sdk-node';
|
|
127
|
+
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
|
|
128
|
+
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
|
|
128
129
|
|
|
129
130
|
// Initialize OpenTelemetry
|
|
130
131
|
const sdk = new NodeSDK({
|
|
131
132
|
traceExporter: new OTLPTraceExporter({
|
|
132
|
-
url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT ??
|
|
133
|
+
url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT ?? 'http://localhost:4318/v1/traces',
|
|
133
134
|
}),
|
|
134
135
|
instrumentations: [
|
|
135
136
|
getNodeAutoInstrumentations({
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
137
|
+
'@opentelemetry/instrumentation-http': { enabled: true },
|
|
138
|
+
'@opentelemetry/instrumentation-express': { enabled: true },
|
|
139
|
+
'@opentelemetry/instrumentation-pg': { enabled: true },
|
|
140
|
+
'@opentelemetry/instrumentation-redis': { enabled: true },
|
|
140
141
|
}),
|
|
141
142
|
],
|
|
142
143
|
});
|
|
@@ -144,16 +145,16 @@ const sdk = new NodeSDK({
|
|
|
144
145
|
sdk.start();
|
|
145
146
|
|
|
146
147
|
// Manual span for custom business logic
|
|
147
|
-
import { trace } from
|
|
148
|
+
import { trace } from '@opentelemetry/api';
|
|
148
149
|
|
|
149
|
-
const tracer = trace.getTracer(
|
|
150
|
+
const tracer = trace.getTracer('order-service');
|
|
150
151
|
|
|
151
152
|
async function processOrder(order: Order) {
|
|
152
|
-
return tracer.startActiveSpan(
|
|
153
|
+
return tracer.startActiveSpan('processOrder', async span => {
|
|
153
154
|
try {
|
|
154
|
-
span.setAttribute(
|
|
155
|
-
span.setAttribute(
|
|
156
|
-
span.setAttribute(
|
|
155
|
+
span.setAttribute('order.id', order.id);
|
|
156
|
+
span.setAttribute('order.total', order.total);
|
|
157
|
+
span.setAttribute('order.items.count', order.items.length);
|
|
157
158
|
|
|
158
159
|
const result = await executeOrder(order);
|
|
159
160
|
span.setStatus({ code: SpanStatusCode.OK });
|
|
@@ -174,30 +175,30 @@ async function processOrder(order: Order) {
|
|
|
174
175
|
## Metrics
|
|
175
176
|
|
|
176
177
|
```typescript
|
|
177
|
-
import { metrics } from
|
|
178
|
+
import { metrics } from '@opentelemetry/api';
|
|
178
179
|
|
|
179
|
-
const meter = metrics.getMeter(
|
|
180
|
+
const meter = metrics.getMeter('api-server');
|
|
180
181
|
|
|
181
182
|
// Counter — things that only go up
|
|
182
|
-
const requestCounter = meter.createCounter(
|
|
183
|
-
description:
|
|
183
|
+
const requestCounter = meter.createCounter('http.requests.total', {
|
|
184
|
+
description: 'Total HTTP requests',
|
|
184
185
|
});
|
|
185
186
|
|
|
186
187
|
// Histogram — request durations
|
|
187
|
-
const requestDuration = meter.createHistogram(
|
|
188
|
-
description:
|
|
189
|
-
unit:
|
|
188
|
+
const requestDuration = meter.createHistogram('http.request.duration_ms', {
|
|
189
|
+
description: 'HTTP request duration in milliseconds',
|
|
190
|
+
unit: 'ms',
|
|
190
191
|
});
|
|
191
192
|
|
|
192
193
|
// Gauge — current values
|
|
193
|
-
const activeConnections = meter.createUpDownCounter(
|
|
194
|
-
description:
|
|
194
|
+
const activeConnections = meter.createUpDownCounter('db.connections.active', {
|
|
195
|
+
description: 'Active database connections',
|
|
195
196
|
});
|
|
196
197
|
|
|
197
198
|
// Middleware to record metrics
|
|
198
199
|
app.use((req, res, next) => {
|
|
199
200
|
const start = performance.now();
|
|
200
|
-
res.on(
|
|
201
|
+
res.on('finish', () => {
|
|
201
202
|
const duration = performance.now() - start;
|
|
202
203
|
requestCounter.add(1, {
|
|
203
204
|
method: req.method,
|
|
@@ -264,22 +265,22 @@ Rules:
|
|
|
264
265
|
|
|
265
266
|
```typescript
|
|
266
267
|
// Liveness: Is the process running?
|
|
267
|
-
app.get(
|
|
268
|
-
res.status(200).json({ status:
|
|
268
|
+
app.get('/health/live', (req, res) => {
|
|
269
|
+
res.status(200).json({ status: 'ok' });
|
|
269
270
|
});
|
|
270
271
|
|
|
271
272
|
// Readiness: Can it accept traffic?
|
|
272
|
-
app.get(
|
|
273
|
+
app.get('/health/ready', async (req, res) => {
|
|
273
274
|
try {
|
|
274
|
-
await db.raw(
|
|
275
|
+
await db.raw('SELECT 1'); // database check
|
|
275
276
|
await redis.ping(); // cache check
|
|
276
277
|
res.status(200).json({
|
|
277
|
-
status:
|
|
278
|
-
checks: { database:
|
|
278
|
+
status: 'ready',
|
|
279
|
+
checks: { database: 'ok', cache: 'ok' },
|
|
279
280
|
});
|
|
280
281
|
} catch (error) {
|
|
281
282
|
res.status(503).json({
|
|
282
|
-
status:
|
|
283
|
+
status: 'not ready',
|
|
283
284
|
checks: { database: error.message },
|
|
284
285
|
});
|
|
285
286
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: opentelemetry-observability
|
|
3
|
+
description: Full-stack distributed tracing, metrics, OpenTelemetry (OTel), Prometheus, Grafana Tempo, and zero-overhead observability instrumentation.
|
|
4
|
+
tools: Read, Grep, Glob, Edit, Write
|
|
5
|
+
version: 3.0.0
|
|
6
|
+
last-updated: 2026-08-05
|
|
7
|
+
script: .agent/scripts/test_runner.js
|
|
8
|
+
scripts-binding:
|
|
9
|
+
- .agent/scripts/test_runner.js
|
|
10
|
+
skills:
|
|
11
|
+
- devops-engineer
|
|
12
|
+
- observability
|
|
13
|
+
- performance-profiling
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# OpenTelemetry Observability — 2026 Telemetry Standards
|
|
17
|
+
|
|
18
|
+
## Mandatory Pre-Flight Context Inspection
|
|
19
|
+
|
|
20
|
+
Before instrumenting applications:
|
|
21
|
+
|
|
22
|
+
1. Vendor-Neutral Telemetry → Use standard OpenTelemetry SDKs (OTLP over gRPC/HTTP)
|
|
23
|
+
2. Trace Propagation → Propagate `traceparent` W3C headers across HTTP and message queues
|
|
24
|
+
3. Sampling Policy → Implement head/tail sampling to reduce telemetry storage costs by 80%
|
|
25
|
+
|
|
26
|
+
## Custom Trace & Meter Instrumentation (TypeScript)
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import { trace, metrics } from '@opentelemetry/api';
|
|
30
|
+
|
|
31
|
+
const tracer = trace.getTracer('user-service', '1.0.0');
|
|
32
|
+
const meter = metrics.getMeter('user-service', '1.0.0');
|
|
33
|
+
|
|
34
|
+
const loginCounter = meter.createCounter('user_logins_total', {
|
|
35
|
+
description: 'Counts total user login attempts',
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
export async function handleLogin(userId: string) {
|
|
39
|
+
return tracer.startActiveSpan('handleLogin', async span => {
|
|
40
|
+
try {
|
|
41
|
+
span.setAttribute('user.id', userId);
|
|
42
|
+
loginCounter.add(1, { status: 'success' });
|
|
43
|
+
// Business logic...
|
|
44
|
+
span.setStatus({ code: 1 }); // OK
|
|
45
|
+
} catch (err: any) {
|
|
46
|
+
span.recordException(err);
|
|
47
|
+
span.setStatus({ code: 2, message: err.message }); // Error
|
|
48
|
+
throw err;
|
|
49
|
+
} finally {
|
|
50
|
+
span.end();
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## 🛑 Verification-Before-Completion (VBC) Protocol
|
|
57
|
+
|
|
58
|
+
- Verify traces connect seamlessly from frontend click to DB query.
|
|
59
|
+
- Confirm telemetry exporter overhead adds < 1ms latency to HTTP handlers.
|