vibes-plug 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 (141) hide show
  1. package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  2. package/BLUEPRINT.md +125 -0
  3. package/CHANGELOG.md +195 -0
  4. package/CONTRIBUTING.md +199 -0
  5. package/LICENSE +21 -0
  6. package/README.md +263 -0
  7. package/SECURITY.md +21 -0
  8. package/banner.png +0 -0
  9. package/package.json +25 -0
  10. package/plugin.json +8 -0
  11. package/scripts/update_skills.js +75 -0
  12. package/skills/ai-llm-integration-expert/SKILL.md +162 -0
  13. package/skills/api-design-expert/SKILL.md +310 -0
  14. package/skills/app-analyzer-optimizer/SKILL.md +189 -0
  15. package/skills/asisten_ramah/SKILL.md +41 -0
  16. package/skills/authentication-identity-expert/SKILL.md +45 -0
  17. package/skills/auto-doc-updater/SKILL.md +204 -0
  18. package/skills/bootstrap-to-modern/SKILL.md +87 -0
  19. package/skills/brainstorming/SKILL.md +353 -0
  20. package/skills/bun-runtime-expert/SKILL.md +211 -0
  21. package/skills/ci-cd-devops-architect/SKILL.md +45 -0
  22. package/skills/cloud-hosting-expert/SKILL.md +244 -0
  23. package/skills/coderabbit/SKILL.md +192 -0
  24. package/skills/data-telemetry-expert/SKILL.md +213 -0
  25. package/skills/database-orm-expert/SKILL.md +294 -0
  26. package/skills/design-system-architect/SKILL.md +243 -0
  27. package/skills/e2e-testing-expert/SKILL.md +315 -0
  28. package/skills/event-driven-architect/SKILL.md +81 -0
  29. package/skills/firebase-security-expert/SKILL.md +195 -0
  30. package/skills/fullstack-expert/SKILL.md +202 -0
  31. package/skills/fullstack-expert/references/api_design_guide.md +466 -0
  32. package/skills/fullstack-expert/references/devops_infrastructure.md +477 -0
  33. package/skills/fullstack-expert/references/multi_language_backend.md +528 -0
  34. package/skills/fullstack-expert/references/system_design_patterns.md +358 -0
  35. package/skills/fullstack-expert/scripts/api_contract_validator.py +253 -0
  36. package/skills/fullstack-expert/scripts/architecture_analyzer.py +326 -0
  37. package/skills/gemini-agent-booster/SKILL.md +135 -0
  38. package/skills/global-a11y-i18n-expert/SKILL.md +81 -0
  39. package/skills/go-programming-expert/SKILL.md +295 -0
  40. package/skills/hig/SKILL.md +188 -0
  41. package/skills/js-backend-expert/SKILL.md +192 -0
  42. package/skills/mcp-server-architect/SKILL.md +194 -0
  43. package/skills/mobile-expo-expert/SKILL.md +186 -0
  44. package/skills/monday-design-aesthetic/SKILL.md +67 -0
  45. package/skills/monorepo-architect/SKILL.md +227 -0
  46. package/skills/mpa-orchestrator/SKILL.md +101 -0
  47. package/skills/multi-agent-orchestration/SKILL.md +234 -0
  48. package/skills/multiple-entry-points/SKILL.md +55 -0
  49. package/skills/mvc-expert/SKILL.md +231 -0
  50. package/skills/payment-gateway-expert/SKILL.md +45 -0
  51. package/skills/performance-web-vitals/SKILL.md +332 -0
  52. package/skills/prd-architect/SKILL.md +191 -0
  53. package/skills/production-ready-hardener/SKILL.md +469 -0
  54. package/skills/production-ready-hardener/references/performance_optimization.md +441 -0
  55. package/skills/production-ready-hardener/references/production_checklist.md +161 -0
  56. package/skills/production-ready-hardener/references/security_hardening_guide.md +379 -0
  57. package/skills/production-ready-hardener/scripts/production_readiness_scanner.py +875 -0
  58. package/skills/python-programming-expert/SKILL.md +271 -0
  59. package/skills/realtime-collaboration-expert/SKILL.md +45 -0
  60. package/skills/rust-programming-expert/SKILL.md +235 -0
  61. package/skills/saas-billing/SKILL.md +377 -0
  62. package/skills/saas-multi-tenant/SKILL.md +237 -0
  63. package/skills/saas-mvp-launcher/SKILL.md +231 -0
  64. package/skills/saas-transformer/SKILL.md +446 -0
  65. package/skills/saas-transformer/references/billing_integration_guide.md +401 -0
  66. package/skills/saas-transformer/references/feature_gating_patterns.md +137 -0
  67. package/skills/saas-transformer/references/saas_transformation_checklist.md +121 -0
  68. package/skills/saas-transformer/scripts/saas_transformation_scanner.py +254 -0
  69. package/skills/scalability-clean-code/SKILL.md +229 -0
  70. package/skills/secure-fuzz-testing/SKILL.md +201 -0
  71. package/skills/senior-frontend/SKILL.md +161 -0
  72. package/skills/senior-frontend/references/frontend_best_practices.md +806 -0
  73. package/skills/senior-frontend/references/nextjs_optimization_guide.md +724 -0
  74. package/skills/senior-frontend/references/react_patterns.md +746 -0
  75. package/skills/senior-frontend/scripts/bundle_analyzer.py +407 -0
  76. package/skills/senior-frontend/scripts/component_generator.py +329 -0
  77. package/skills/senior-frontend/scripts/frontend_scaffolder.py +1005 -0
  78. package/skills/senior-fullstack/SKILL.md +167 -0
  79. package/skills/senior-fullstack/references/architecture_patterns.md +160 -0
  80. package/skills/senior-fullstack/references/development_workflows.md +222 -0
  81. package/skills/senior-fullstack/references/tech_stack_guide.md +190 -0
  82. package/skills/senior-fullstack/scripts/code_quality_analyzer.py +114 -0
  83. package/skills/senior-fullstack/scripts/fullstack_scaffolder.py +114 -0
  84. package/skills/senior-fullstack/scripts/project_scaffolder.py +114 -0
  85. package/skills/seo/SKILL.md +225 -0
  86. package/skills/seo/references/cwv-thresholds.md +108 -0
  87. package/skills/seo/references/eeat-framework.md +214 -0
  88. package/skills/seo/references/quality-gates.md +155 -0
  89. package/skills/seo/references/schema-types.md +118 -0
  90. package/skills/seo-aeo-landing-page-writer/SKILL.md +97 -0
  91. package/skills/seo-geo/SKILL.md +188 -0
  92. package/skills/session-handoff-resume/SKILL.md +158 -0
  93. package/skills/skill_baru/SKILL.md +147 -0
  94. package/skills/spa-orchestrator/SKILL.md +288 -0
  95. package/skills/state-management-expert/SKILL.md +272 -0
  96. package/skills/supabase-migration/SKILL.md +45 -0
  97. package/skills/supabase-security-expert/SKILL.md +243 -0
  98. package/skills/tailwind-expert/SKILL.md +188 -0
  99. package/skills/tanstack-query-expert/SKILL.md +199 -0
  100. package/skills/tauri-expert/SKILL.md +97 -0
  101. package/skills/token-saver/SKILL.md +111 -0
  102. package/skills/typescript-expert/SKILL.md +279 -0
  103. package/skills/ui-components-expert/SKILL.md +63 -0
  104. package/skills/ui-ux-pro-max/SKILL.md +201 -0
  105. package/skills/ui-ux-pro-max/data/charts.csv +26 -0
  106. package/skills/ui-ux-pro-max/data/colors.csv +97 -0
  107. package/skills/ui-ux-pro-max/data/icons.csv +101 -0
  108. package/skills/ui-ux-pro-max/data/landing.csv +31 -0
  109. package/skills/ui-ux-pro-max/data/products.csv +97 -0
  110. package/skills/ui-ux-pro-max/data/prompts.csv +24 -0
  111. package/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
  112. package/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  113. package/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  114. package/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  115. package/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  116. package/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  117. package/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  118. package/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
  119. package/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  120. package/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  121. package/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  122. package/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  123. package/skills/ui-ux-pro-max/data/styles.csv +59 -0
  124. package/skills/ui-ux-pro-max/data/typography.csv +58 -0
  125. package/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  126. package/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  127. package/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
  128. package/skills/ui-ux-pro-max/scripts/__pycache__/core.cpython-310.pyc +0 -0
  129. package/skills/ui-ux-pro-max/scripts/__pycache__/core.cpython-312.pyc +0 -0
  130. package/skills/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-310.pyc +0 -0
  131. package/skills/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-312.pyc +0 -0
  132. package/skills/ui-ux-pro-max/scripts/core.py +257 -0
  133. package/skills/ui-ux-pro-max/scripts/design_system.py +493 -0
  134. package/skills/ui-ux-pro-max/scripts/search.py +81 -0
  135. package/skills/ui_ux_expert/SKILL.md +114 -0
  136. package/skills/vibe-code-gardener/SKILL.md +173 -0
  137. package/skills/web-scraper/SKILL.md +205 -0
  138. package/skills/web-scraper/references/data-transforms.md +397 -0
  139. package/skills/web-scraper/references/extraction-patterns.md +475 -0
  140. package/skills/web-scraper/references/output-templates.md +481 -0
  141. package/skills/zero-to-prod-orchestrator/SKILL.md +180 -0
@@ -0,0 +1,358 @@
1
+ # System Design Patterns
2
+
3
+ ## Overview
4
+ This reference documents production-grade system design patterns for fullstack expert architects. Covers distributed systems, event-driven architectures, and scalable microservice topologies.
5
+
6
+ ---
7
+
8
+ ## 1. Microservices Communication Patterns
9
+
10
+ ### Synchronous: API Gateway + Service Mesh
11
+
12
+ Use an API Gateway (Kong, AWS API Gateway, Envoy) as the single entry point. Behind it, services communicate via gRPC for internal calls (binary protocol, code-gen, strict contracts).
13
+
14
+ ```
15
+ ┌──────────────┐
16
+ │ Client │
17
+ └──────┬───────┘
18
+ │ HTTPS
19
+ ┌──────▼───────┐
20
+ │ API Gateway │ (Rate limiting, Auth, Routing)
21
+ └──────┬───────┘
22
+ │ gRPC / HTTP
23
+ ┌────┼────┐
24
+ ▼ ▼ ▼
25
+ ┌───┐┌───┐┌───┐
26
+ │Svc││Svc││Svc│
27
+ │ A ││ B ││ C │
28
+ └─┬─┘└─┬─┘└─┬─┘
29
+ │ │ │
30
+ ▼ ▼ ▼
31
+ ┌───────────────┐
32
+ │ Database(s) │
33
+ └───────────────┘
34
+ ```
35
+
36
+ ### Asynchronous: Event-Driven Architecture (EDA)
37
+
38
+ For decoupled, resilient communication:
39
+
40
+ ```typescript
41
+ // Producer: Order Service (TypeScript + BullMQ)
42
+ import { Queue } from 'bullmq';
43
+ import IORedis from 'ioredis';
44
+
45
+ const connection = new IORedis(process.env.REDIS_URL!);
46
+ const orderEventsQueue = new Queue('OrderEvents', { connection });
47
+
48
+ export async function publishOrderCreated(order: Order) {
49
+ await orderEventsQueue.add('order.created', {
50
+ orderId: order.id,
51
+ userId: order.userId,
52
+ total: order.total,
53
+ items: order.items,
54
+ timestamp: new Date().toISOString(),
55
+ }, {
56
+ attempts: 5,
57
+ backoff: { type: 'exponential', delay: 3000 },
58
+ removeOnComplete: { age: 86400 }, // Keep completed jobs for 24h
59
+ });
60
+ }
61
+ ```
62
+
63
+ ```typescript
64
+ // Consumer: Notification Service (TypeScript + BullMQ Worker)
65
+ import { Worker, Job } from 'bullmq';
66
+ import IORedis from 'ioredis';
67
+
68
+ const connection = new IORedis(process.env.REDIS_URL!);
69
+
70
+ const notificationWorker = new Worker(
71
+ 'OrderEvents',
72
+ async (job: Job) => {
73
+ switch (job.name) {
74
+ case 'order.created':
75
+ await sendOrderConfirmationEmail(job.data);
76
+ await sendPushNotification(job.data.userId, 'Order confirmed!');
77
+ break;
78
+ case 'order.shipped':
79
+ await sendShippingNotification(job.data);
80
+ break;
81
+ }
82
+ },
83
+ { connection, concurrency: 5 }
84
+ );
85
+ ```
86
+
87
+ ---
88
+
89
+ ## 2. Saga Pattern for Distributed Transactions
90
+
91
+ When a business operation spans multiple services, use the Saga pattern (choreography or orchestration) instead of distributed 2PC.
92
+
93
+ ### Orchestrator-Based Saga
94
+
95
+ ```typescript
96
+ // Saga Orchestrator (TypeScript)
97
+ interface SagaStep<T> {
98
+ name: string;
99
+ execute: (context: T) => Promise<void>;
100
+ compensate: (context: T) => Promise<void>;
101
+ }
102
+
103
+ class SagaOrchestrator<T> {
104
+ private steps: SagaStep<T>[] = [];
105
+ private completedSteps: SagaStep<T>[] = [];
106
+
107
+ addStep(step: SagaStep<T>): this {
108
+ this.steps.push(step);
109
+ return this;
110
+ }
111
+
112
+ async execute(context: T): Promise<void> {
113
+ for (const step of this.steps) {
114
+ try {
115
+ console.log(`▶ Executing: ${step.name}`);
116
+ await step.execute(context);
117
+ this.completedSteps.push(step);
118
+ } catch (error) {
119
+ console.error(`✗ Failed at: ${step.name}`, error);
120
+ await this.rollback(context);
121
+ throw new SagaFailedError(step.name, error);
122
+ }
123
+ }
124
+ }
125
+
126
+ private async rollback(context: T): Promise<void> {
127
+ // Compensate in reverse order
128
+ for (const step of [...this.completedSteps].reverse()) {
129
+ try {
130
+ console.log(`↩ Compensating: ${step.name}`);
131
+ await step.compensate(context);
132
+ } catch (error) {
133
+ console.error(`⚠ Compensation failed: ${step.name}`, error);
134
+ // Log to dead letter queue for manual intervention
135
+ }
136
+ }
137
+ }
138
+ }
139
+
140
+ // Usage: Order Creation Saga
141
+ const orderSaga = new SagaOrchestrator<OrderContext>()
142
+ .addStep({
143
+ name: 'Reserve Inventory',
144
+ execute: async (ctx) => await inventoryService.reserve(ctx.items),
145
+ compensate: async (ctx) => await inventoryService.release(ctx.items),
146
+ })
147
+ .addStep({
148
+ name: 'Process Payment',
149
+ execute: async (ctx) => await paymentService.charge(ctx.paymentMethod, ctx.total),
150
+ compensate: async (ctx) => await paymentService.refund(ctx.paymentId),
151
+ })
152
+ .addStep({
153
+ name: 'Create Order Record',
154
+ execute: async (ctx) => await orderService.create(ctx),
155
+ compensate: async (ctx) => await orderService.cancel(ctx.orderId),
156
+ });
157
+ ```
158
+
159
+ ---
160
+
161
+ ## 3. CQRS (Command Query Responsibility Segregation)
162
+
163
+ Separate write models (commands) from read models (queries) when read/write patterns differ significantly.
164
+
165
+ ```
166
+ ┌─────────────┐ ┌─────────────┐
167
+ │ Write API │ │ Read API │
168
+ │ (Commands) │ │ (Queries) │
169
+ └──────┬──────┘ └──────┬──────┘
170
+ │ │
171
+ ▼ ▼
172
+ ┌─────────────┐ ┌─────────────┐
173
+ │ Write DB │──▶│ Read DB │
174
+ │ (PostgreSQL) │ │ (Redis / │
175
+ │ Normalized │ │ Elasticsearch)
176
+ └─────────────┘ └─────────────┘
177
+
178
+ ▼ (Domain Events)
179
+ ┌─────────────┐
180
+ │ Event Bus │
181
+ │ (Kafka) │
182
+ └─────────────┘
183
+ ```
184
+
185
+ ```typescript
186
+ // Write side: Command Handler
187
+ async function handleCreateProduct(cmd: CreateProductCommand): Promise<string> {
188
+ // Validate business rules
189
+ const product = Product.create(cmd);
190
+
191
+ // Persist to write store
192
+ await db.insert(products).values(product.toRow());
193
+
194
+ // Publish domain event for read model projection
195
+ await eventBus.publish('product.created', {
196
+ id: product.id,
197
+ name: product.name,
198
+ price: product.price,
199
+ category: product.category,
200
+ });
201
+
202
+ return product.id;
203
+ }
204
+
205
+ // Read side: Event Projector
206
+ eventBus.subscribe('product.created', async (event) => {
207
+ // Project into denormalized read model optimized for queries
208
+ await redis.hset(`product:${event.id}`, {
209
+ ...event,
210
+ searchText: `${event.name} ${event.category}`.toLowerCase(),
211
+ });
212
+
213
+ // Also index in Elasticsearch for full-text search
214
+ await esClient.index({
215
+ index: 'products',
216
+ id: event.id,
217
+ body: event,
218
+ });
219
+ });
220
+ ```
221
+
222
+ ---
223
+
224
+ ## 4. Circuit Breaker Pattern
225
+
226
+ Prevent cascading failures in distributed systems by wrapping external service calls with circuit breakers.
227
+
228
+ ```typescript
229
+ // Circuit Breaker Implementation (TypeScript)
230
+ enum CircuitState {
231
+ CLOSED = 'CLOSED', // Normal operation
232
+ OPEN = 'OPEN', // Failing, reject calls
233
+ HALF_OPEN = 'HALF_OPEN' // Testing recovery
234
+ }
235
+
236
+ class CircuitBreaker {
237
+ private state = CircuitState.CLOSED;
238
+ private failureCount = 0;
239
+ private lastFailureTime = 0;
240
+
241
+ constructor(
242
+ private readonly name: string,
243
+ private readonly threshold: number = 5,
244
+ private readonly resetTimeoutMs: number = 30000,
245
+ ) {}
246
+
247
+ async call<T>(fn: () => Promise<T>): Promise<T> {
248
+ if (this.state === CircuitState.OPEN) {
249
+ if (Date.now() - this.lastFailureTime > this.resetTimeoutMs) {
250
+ this.state = CircuitState.HALF_OPEN;
251
+ } else {
252
+ throw new CircuitOpenError(`Circuit ${this.name} is OPEN`);
253
+ }
254
+ }
255
+
256
+ try {
257
+ const result = await fn();
258
+ this.onSuccess();
259
+ return result;
260
+ } catch (error) {
261
+ this.onFailure();
262
+ throw error;
263
+ }
264
+ }
265
+
266
+ private onSuccess(): void {
267
+ this.failureCount = 0;
268
+ this.state = CircuitState.CLOSED;
269
+ }
270
+
271
+ private onFailure(): void {
272
+ this.failureCount++;
273
+ this.lastFailureTime = Date.now();
274
+ if (this.failureCount >= this.threshold) {
275
+ this.state = CircuitState.OPEN;
276
+ console.warn(`⚡ Circuit ${this.name} opened after ${this.failureCount} failures`);
277
+ }
278
+ }
279
+ }
280
+
281
+ // Usage
282
+ const paymentCircuit = new CircuitBreaker('payment-service', 5, 30000);
283
+
284
+ async function processPayment(order: Order) {
285
+ return paymentCircuit.call(() =>
286
+ fetch('https://payment-api.example.com/charge', {
287
+ method: 'POST',
288
+ body: JSON.stringify({ amount: order.total }),
289
+ })
290
+ );
291
+ }
292
+ ```
293
+
294
+ ---
295
+
296
+ ## 5. Service Discovery & Load Balancing
297
+
298
+ ### DNS-Based (Kubernetes)
299
+
300
+ ```yaml
301
+ # Kubernetes Service (ClusterIP) for internal discovery
302
+ apiVersion: v1
303
+ kind: Service
304
+ metadata:
305
+ name: user-service
306
+ namespace: production
307
+ spec:
308
+ selector:
309
+ app: user-service
310
+ ports:
311
+ - port: 80
312
+ targetPort: 3000
313
+ type: ClusterIP
314
+ ---
315
+ # HorizontalPodAutoscaler for dynamic scaling
316
+ apiVersion: autoscaling/v2
317
+ kind: HorizontalPodAutoscaler
318
+ metadata:
319
+ name: user-service-hpa
320
+ spec:
321
+ scaleTargetRef:
322
+ apiVersion: apps/v1
323
+ kind: Deployment
324
+ name: user-service
325
+ minReplicas: 2
326
+ maxReplicas: 10
327
+ metrics:
328
+ - type: Resource
329
+ resource:
330
+ name: cpu
331
+ target:
332
+ type: Utilization
333
+ averageUtilization: 70
334
+ - type: Resource
335
+ resource:
336
+ name: memory
337
+ target:
338
+ type: Utilization
339
+ averageUtilization: 80
340
+ ```
341
+
342
+ ---
343
+
344
+ ## Anti-Patterns to Avoid
345
+
346
+ ### 🚫 Distributed Monolith
347
+ Don't create microservices that are tightly coupled and must be deployed together. If services can't be deployed independently, they're a distributed monolith — worse than a proper monolith.
348
+
349
+ ### 🚫 Shared Database Between Services
350
+ Each service should own its data store. Cross-service data access should happen via APIs or events, never direct database queries.
351
+
352
+ ### 🚫 Synchronous Call Chains
353
+ Avoid long chains of synchronous HTTP calls (`A → B → C → D`). Each hop adds latency and a failure point. Use async messaging for non-critical paths.
354
+
355
+ ---
356
+
357
+ ## Conclusion
358
+ Choosing the right system design patterns depends on your scale, team size, and consistency requirements. Start with a modular monolith and extract services only when you have clear domain boundaries and operational maturity.
@@ -0,0 +1,253 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ API Contract Validator
4
+ Validates API contracts (OpenAPI specs) and checks for best practices.
5
+ """
6
+
7
+ import os
8
+ import sys
9
+ import json
10
+ import argparse
11
+ from pathlib import Path
12
+ from typing import Dict, List, Optional
13
+
14
+
15
+ class ApiContractValidator:
16
+ """Validates OpenAPI specs and API route files for best practices."""
17
+
18
+ def __init__(self, target_path: str, verbose: bool = False):
19
+ self.target_path = Path(target_path)
20
+ self.verbose = verbose
21
+ self.results: Dict = {
22
+ 'status': 'pending',
23
+ 'target': str(self.target_path),
24
+ 'findings': [],
25
+ 'api_routes': [],
26
+ 'score': 100,
27
+ }
28
+
29
+ def run(self) -> Dict:
30
+ """Execute the API contract validation."""
31
+ print(f"📋 Running API Contract Validator...")
32
+ print(f"📁 Target: {self.target_path}")
33
+
34
+ try:
35
+ self.validate_target()
36
+ self.scan_api_routes()
37
+ self.check_openapi_spec()
38
+ self.check_validation_schemas()
39
+ self.check_error_handling()
40
+ self.check_authentication()
41
+ self.check_rate_limiting()
42
+ self.generate_report()
43
+
44
+ self.results['status'] = 'success'
45
+ print("✅ Validation completed!")
46
+ return self.results
47
+
48
+ except Exception as e:
49
+ print(f"❌ Error: {e}")
50
+ sys.exit(1)
51
+
52
+ def validate_target(self):
53
+ """Validate the target path exists."""
54
+ if not self.target_path.exists():
55
+ raise ValueError(f"Target path does not exist: {self.target_path}")
56
+
57
+ def scan_api_routes(self):
58
+ """Scan for API route definitions."""
59
+ api_dirs = [
60
+ 'app/api', 'src/routes', 'src/api', 'routes',
61
+ 'internal/handler', 'src/handlers',
62
+ ]
63
+ route_files = []
64
+
65
+ for api_dir in api_dirs:
66
+ dir_path = self.target_path / api_dir
67
+ if dir_path.is_dir():
68
+ for f in dir_path.rglob('*'):
69
+ if f.is_file() and f.suffix in {'.ts', '.tsx', '.js', '.py', '.go', '.rs'}:
70
+ route_files.append(str(f.relative_to(self.target_path)))
71
+
72
+ self.results['api_routes'] = route_files
73
+ if self.verbose:
74
+ print(f"✓ Found {len(route_files)} API route files")
75
+
76
+ if not route_files:
77
+ self._add_finding('info', 'No API routes found in standard directories')
78
+
79
+ def check_openapi_spec(self):
80
+ """Check for OpenAPI specification file."""
81
+ spec_files = ['openapi.yaml', 'openapi.yml', 'openapi.json', 'swagger.yaml', 'swagger.json']
82
+ has_spec = any((self.target_path / f).exists() for f in spec_files)
83
+
84
+ # Also check in docs/ or api/ directories
85
+ for subdir in ['docs', 'api', 'spec']:
86
+ if (self.target_path / subdir).is_dir():
87
+ has_spec = has_spec or any(
88
+ (self.target_path / subdir / f).exists() for f in spec_files
89
+ )
90
+
91
+ if not has_spec and self.results['api_routes']:
92
+ self._add_finding('warning', 'No OpenAPI spec found — consider spec-first API design')
93
+ self.results['score'] -= 10
94
+
95
+ def check_validation_schemas(self):
96
+ """Check for input validation schemas (Zod, Pydantic, etc.)."""
97
+ validation_patterns = ['zod', 'pydantic', 'joi', 'yup', 'class-validator']
98
+ has_validation = False
99
+
100
+ pkg_json = self.target_path / 'package.json'
101
+ if pkg_json.exists():
102
+ try:
103
+ with open(pkg_json) as f:
104
+ pkg = json.load(f)
105
+ deps = {**pkg.get('dependencies', {}), **pkg.get('devDependencies', {})}
106
+ has_validation = any(v in deps for v in validation_patterns)
107
+ except (json.JSONDecodeError, IOError):
108
+ pass
109
+
110
+ # Check Python
111
+ pyproject = self.target_path / 'pyproject.toml'
112
+ if pyproject.exists():
113
+ try:
114
+ content = pyproject.read_text()
115
+ has_validation = has_validation or 'pydantic' in content
116
+ except IOError:
117
+ pass
118
+
119
+ if not has_validation and self.results['api_routes']:
120
+ self._add_finding('warning', 'No input validation library detected (Zod, Pydantic, etc.)')
121
+ self.results['score'] -= 15
122
+
123
+ def check_error_handling(self):
124
+ """Check for structured error handling patterns."""
125
+ error_files = []
126
+ for pattern in ['**/error*.ts', '**/error*.py', '**/error*.go', '**/error*.rs']:
127
+ error_files.extend(self.target_path.glob(pattern))
128
+
129
+ if not error_files and self.results['api_routes']:
130
+ self._add_finding('info', 'No dedicated error handling module found — consider structured error responses (RFC 7807)')
131
+
132
+ def check_authentication(self):
133
+ """Check for authentication middleware setup."""
134
+ auth_indicators = ['auth', 'jwt', 'clerk', 'nextauth', 'lucia', 'passport']
135
+ has_auth = False
136
+
137
+ pkg_json = self.target_path / 'package.json'
138
+ if pkg_json.exists():
139
+ try:
140
+ with open(pkg_json) as f:
141
+ pkg = json.load(f)
142
+ deps = {**pkg.get('dependencies', {}), **pkg.get('devDependencies', {})}
143
+ has_auth = any(
144
+ any(indicator in dep for indicator in auth_indicators)
145
+ for dep in deps
146
+ )
147
+ except (json.JSONDecodeError, IOError):
148
+ pass
149
+
150
+ if not has_auth and self.results['api_routes']:
151
+ self._add_finding('info', 'No authentication library detected — ensure API endpoints are protected')
152
+
153
+ def check_rate_limiting(self):
154
+ """Check for rate limiting setup."""
155
+ rate_limit_deps = ['rate-limit', 'ratelimit', 'limiter', 'throttle']
156
+ has_rate_limit = False
157
+
158
+ pkg_json = self.target_path / 'package.json'
159
+ if pkg_json.exists():
160
+ try:
161
+ with open(pkg_json) as f:
162
+ pkg = json.load(f)
163
+ deps = {**pkg.get('dependencies', {}), **pkg.get('devDependencies', {})}
164
+ has_rate_limit = any(
165
+ any(rl in dep for rl in rate_limit_deps)
166
+ for dep in deps
167
+ )
168
+ except (json.JSONDecodeError, IOError):
169
+ pass
170
+
171
+ if not has_rate_limit and self.results['api_routes']:
172
+ self._add_finding('warning', 'No rate limiting detected — protect API endpoints from abuse')
173
+ self.results['score'] -= 5
174
+
175
+ def _add_finding(self, severity: str, message: str):
176
+ """Add a finding to the results."""
177
+ self.results['findings'].append({
178
+ 'severity': severity,
179
+ 'message': message,
180
+ })
181
+ if self.verbose:
182
+ icon = {'critical': '🔴', 'warning': '🟡', 'info': '🔵'}.get(severity, '⚪')
183
+ print(f" {icon} [{severity.upper()}] {message}")
184
+
185
+ def generate_report(self):
186
+ """Generate and display the validation report."""
187
+ findings = self.results['findings']
188
+ critical = len([f for f in findings if f['severity'] == 'critical'])
189
+ warnings = len([f for f in findings if f['severity'] == 'warning'])
190
+ info = len([f for f in findings if f['severity'] == 'info'])
191
+
192
+ score = max(0, self.results['score'])
193
+ self.results['score'] = score
194
+
195
+ print(f"\n{'='*60}")
196
+ print("📋 API CONTRACT VALIDATION REPORT")
197
+ print(f"{'='*60}")
198
+ print(f"Target: {self.results['target']}")
199
+ print(f"Score: {score}/100")
200
+ print(f"API Routes: {len(self.results['api_routes'])} files found")
201
+ print(f"Findings: {critical} critical, {warnings} warnings, {info} info")
202
+ print(f"\nFindings:")
203
+ for f in findings:
204
+ icon = {'critical': '🔴', 'warning': '🟡', 'info': '🔵'}.get(f['severity'], '⚪')
205
+ print(f" {icon} [{f['severity'].upper()}] {f['message']}")
206
+ print(f"{'='*60}\n")
207
+
208
+
209
+ def main():
210
+ """Main entry point."""
211
+ parser = argparse.ArgumentParser(
212
+ description="API Contract Validator — validates API design best practices"
213
+ )
214
+ parser.add_argument(
215
+ 'target',
216
+ help='Target project path to validate'
217
+ )
218
+ parser.add_argument(
219
+ '--verbose', '-v',
220
+ action='store_true',
221
+ help='Enable verbose output'
222
+ )
223
+ parser.add_argument(
224
+ '--json',
225
+ action='store_true',
226
+ help='Output results as JSON'
227
+ )
228
+ parser.add_argument(
229
+ '--output', '-o',
230
+ help='Output file path'
231
+ )
232
+
233
+ args = parser.parse_args()
234
+
235
+ validator = ApiContractValidator(
236
+ args.target,
237
+ verbose=args.verbose
238
+ )
239
+
240
+ results = validator.run()
241
+
242
+ if args.json:
243
+ output = json.dumps(results, indent=2)
244
+ if args.output:
245
+ with open(args.output, 'w') as f:
246
+ f.write(output)
247
+ print(f"Results written to {args.output}")
248
+ else:
249
+ print(output)
250
+
251
+
252
+ if __name__ == '__main__':
253
+ main()