@rune-kit/rune 2.1.1 → 2.2.1

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 (157) hide show
  1. package/README.md +40 -34
  2. package/compiler/__tests__/pack-split.test.js +145 -0
  3. package/compiler/adapters/antigravity.js +1 -1
  4. package/compiler/adapters/codex.js +77 -0
  5. package/compiler/adapters/cursor.js +1 -1
  6. package/compiler/adapters/generic.js +1 -1
  7. package/compiler/adapters/index.js +4 -0
  8. package/compiler/adapters/opencode.js +86 -0
  9. package/compiler/adapters/windsurf.js +1 -1
  10. package/compiler/bin/rune.js +10 -7
  11. package/compiler/doctor.js +42 -0
  12. package/compiler/emitter.js +64 -10
  13. package/compiler/parser.js +42 -3
  14. package/compiler/transformer.js +10 -6
  15. package/compiler/transforms/branding.js +1 -1
  16. package/compiler/transforms/compliance.js +40 -0
  17. package/extensions/ai-ml/PACK.md +38 -474
  18. package/extensions/ai-ml/skills/ai-agents.md +172 -0
  19. package/extensions/ai-ml/skills/code-sandbox.md +187 -0
  20. package/extensions/ai-ml/skills/deep-research.md +146 -0
  21. package/extensions/ai-ml/skills/embedding-search.md +66 -0
  22. package/extensions/ai-ml/skills/fine-tuning-guide.md +74 -0
  23. package/extensions/ai-ml/skills/llm-architect.md +125 -0
  24. package/extensions/ai-ml/skills/llm-integration.md +64 -0
  25. package/extensions/ai-ml/skills/prompt-patterns.md +72 -0
  26. package/extensions/ai-ml/skills/rag-patterns.md +66 -0
  27. package/extensions/ai-ml/skills/web-extraction.md +114 -0
  28. package/extensions/analytics/PACK.md +19 -484
  29. package/extensions/analytics/skills/ab-testing.md +72 -0
  30. package/extensions/analytics/skills/dashboard-patterns.md +83 -0
  31. package/extensions/analytics/skills/data-validation.md +68 -0
  32. package/extensions/analytics/skills/funnel-analysis.md +81 -0
  33. package/extensions/analytics/skills/sql-patterns.md +57 -0
  34. package/extensions/analytics/skills/statistical-analysis.md +79 -0
  35. package/extensions/analytics/skills/tracking-setup.md +71 -0
  36. package/extensions/backend/PACK.md +44 -618
  37. package/extensions/backend/skills/api-patterns.md +84 -0
  38. package/extensions/backend/skills/async-pipeline.md +193 -0
  39. package/extensions/backend/skills/auth-patterns.md +97 -0
  40. package/extensions/backend/skills/background-jobs.md +133 -0
  41. package/extensions/backend/skills/caching-patterns.md +108 -0
  42. package/extensions/backend/skills/cli-generation.md +133 -0
  43. package/extensions/backend/skills/database-patterns.md +87 -0
  44. package/extensions/backend/skills/middleware-patterns.md +104 -0
  45. package/extensions/chrome-ext/PACK.md +19 -921
  46. package/extensions/chrome-ext/skills/cws-preflight.md +143 -0
  47. package/extensions/chrome-ext/skills/cws-publish.md +104 -0
  48. package/extensions/chrome-ext/skills/ext-ai-integration.md +251 -0
  49. package/extensions/chrome-ext/skills/ext-messaging.md +139 -0
  50. package/extensions/chrome-ext/skills/ext-storage.md +133 -0
  51. package/extensions/chrome-ext/skills/mv3-scaffold.md +164 -0
  52. package/extensions/content/PACK.md +43 -335
  53. package/extensions/content/skills/blog-patterns.md +88 -0
  54. package/extensions/content/skills/cms-integration.md +131 -0
  55. package/extensions/content/skills/content-scoring.md +107 -0
  56. package/extensions/content/skills/i18n.md +83 -0
  57. package/extensions/content/skills/mdx-authoring.md +137 -0
  58. package/extensions/content/skills/reference.md +1014 -0
  59. package/extensions/content/skills/seo-patterns.md +67 -0
  60. package/extensions/content/skills/video-repurpose.md +153 -0
  61. package/extensions/devops/PACK.md +38 -457
  62. package/extensions/devops/skills/chaos-testing.md +67 -0
  63. package/extensions/devops/skills/ci-cd.md +75 -0
  64. package/extensions/devops/skills/docker.md +58 -0
  65. package/extensions/devops/skills/edge-serverless.md +163 -0
  66. package/extensions/devops/skills/infra-as-code.md +158 -0
  67. package/extensions/devops/skills/kubernetes.md +110 -0
  68. package/extensions/devops/skills/monitoring.md +57 -0
  69. package/extensions/devops/skills/server-setup.md +64 -0
  70. package/extensions/devops/skills/ssl-domain.md +42 -0
  71. package/extensions/ecommerce/PACK.md +62 -226
  72. package/extensions/ecommerce/skills/cart-system.md +79 -0
  73. package/extensions/ecommerce/skills/inventory-mgmt.md +102 -0
  74. package/extensions/ecommerce/skills/order-management.md +126 -0
  75. package/extensions/ecommerce/skills/payment-integration.md +472 -0
  76. package/extensions/ecommerce/skills/shopify-dev.md +69 -0
  77. package/extensions/ecommerce/skills/subscription-billing.md +93 -0
  78. package/extensions/ecommerce/skills/tax-compliance.md +117 -0
  79. package/extensions/gamedev/PACK.md +66 -317
  80. package/extensions/gamedev/skills/asset-pipeline.md +74 -0
  81. package/extensions/gamedev/skills/audio-system.md +129 -0
  82. package/extensions/gamedev/skills/camera-system.md +87 -0
  83. package/extensions/gamedev/skills/ecs.md +98 -0
  84. package/extensions/gamedev/skills/game-loops.md +72 -0
  85. package/extensions/gamedev/skills/input-system.md +199 -0
  86. package/extensions/gamedev/skills/multiplayer.md +180 -0
  87. package/extensions/gamedev/skills/particles.md +105 -0
  88. package/extensions/gamedev/skills/physics-engine.md +89 -0
  89. package/extensions/gamedev/skills/scene-management.md +146 -0
  90. package/extensions/gamedev/skills/threejs-patterns.md +90 -0
  91. package/extensions/gamedev/skills/webgl.md +71 -0
  92. package/extensions/mobile/PACK.md +56 -223
  93. package/extensions/mobile/skills/app-store-connect.md +152 -0
  94. package/extensions/mobile/skills/app-store-prep.md +66 -0
  95. package/extensions/mobile/skills/deep-linking.md +109 -0
  96. package/extensions/mobile/skills/flutter.md +60 -0
  97. package/extensions/mobile/skills/ios-build-pipeline.md +142 -0
  98. package/extensions/mobile/skills/native-bridge.md +66 -0
  99. package/extensions/mobile/skills/ota-updates.md +97 -0
  100. package/extensions/mobile/skills/push-notifications.md +111 -0
  101. package/extensions/mobile/skills/react-native.md +82 -0
  102. package/extensions/saas/PACK.md +26 -720
  103. package/extensions/saas/skills/billing-integration.md +121 -0
  104. package/extensions/saas/skills/feature-flags.md +130 -0
  105. package/extensions/saas/skills/multi-tenant.md +103 -0
  106. package/extensions/saas/skills/onboarding-flow.md +139 -0
  107. package/extensions/saas/skills/subscription-flow.md +95 -0
  108. package/extensions/saas/skills/team-management.md +144 -0
  109. package/extensions/security/PACK.md +10 -448
  110. package/extensions/security/skills/api-security.md +140 -0
  111. package/extensions/security/skills/compliance.md +68 -0
  112. package/extensions/security/skills/owasp-audit.md +64 -0
  113. package/extensions/security/skills/pentest-patterns.md +77 -0
  114. package/extensions/security/skills/secret-mgmt.md +65 -0
  115. package/extensions/security/skills/supply-chain.md +65 -0
  116. package/extensions/trading/PACK.md +18 -535
  117. package/extensions/trading/skills/chart-components.md +55 -0
  118. package/extensions/trading/skills/experiment-loop.md +125 -0
  119. package/extensions/trading/skills/fintech-patterns.md +47 -0
  120. package/extensions/trading/skills/indicator-library.md +58 -0
  121. package/extensions/trading/skills/quant-analysis.md +111 -0
  122. package/extensions/trading/skills/realtime-data.md +58 -0
  123. package/extensions/trading/skills/trade-logic.md +104 -0
  124. package/extensions/ui/PACK.md +34 -853
  125. package/extensions/ui/skills/a11y-audit.md +91 -0
  126. package/extensions/ui/skills/animation-patterns.md +106 -0
  127. package/extensions/ui/skills/component-patterns.md +75 -0
  128. package/extensions/ui/skills/design-decision.md +98 -0
  129. package/extensions/ui/skills/design-system.md +68 -0
  130. package/extensions/ui/skills/landing-patterns.md +155 -0
  131. package/extensions/ui/skills/palette-picker.md +162 -0
  132. package/extensions/ui/skills/react-health.md +90 -0
  133. package/extensions/ui/skills/type-system.md +125 -0
  134. package/extensions/ui/skills/web-vitals.md +153 -0
  135. package/extensions/zalo/PACK.md +117 -0
  136. package/extensions/zalo/skills/zalo-oa-mcp.md +317 -0
  137. package/extensions/zalo/skills/zalo-oa-messaging.md +429 -0
  138. package/extensions/zalo/skills/zalo-oa-setup.md +236 -0
  139. package/extensions/zalo/skills/zalo-oa-webhook.md +189 -0
  140. package/extensions/zalo/skills/zalo-personal-messaging.md +194 -0
  141. package/extensions/zalo/skills/zalo-personal-setup.md +153 -0
  142. package/extensions/zalo/skills/zalo-rate-guard.md +219 -0
  143. package/package.json +5 -2
  144. package/skills/brainstorm/SKILL.md +63 -1
  145. package/skills/cook/SKILL.md +89 -6
  146. package/skills/debug/SKILL.md +5 -0
  147. package/skills/fix/SKILL.md +5 -0
  148. package/skills/mcp-builder/SKILL.md +48 -1
  149. package/skills/neural-memory/SKILL.md +362 -0
  150. package/skills/plan/SKILL.md +3 -0
  151. package/skills/rescue/SKILL.md +5 -0
  152. package/skills/review/SKILL.md +44 -5
  153. package/skills/review-intake/SKILL.md +17 -1
  154. package/skills/skill-router/SKILL.md +106 -8
  155. package/skills/team/SKILL.md +24 -1
  156. package/skills/test/SKILL.md +18 -0
  157. package/skills/verification/SKILL.md +40 -1
@@ -0,0 +1,133 @@
1
+ ---
2
+ name: "cli-generation"
3
+ pack: "@rune/backend"
4
+ description: "Generate production-grade CLI wrappers for backend services — command groups, dual output mode (human + JSON), stateful REPL, session management with undo/redo, and pip/npm-installable packaging."
5
+ model: sonnet
6
+ tools: [Read, Edit, Write, Grep, Glob, Bash]
7
+ ---
8
+
9
+ # cli-generation
10
+
11
+ Generate production-grade CLI wrappers for backend services — command groups, dual output mode (human + JSON), stateful REPL, session management with undo/redo, and pip/npm-installable packaging.
12
+
13
+ #### Workflow
14
+
15
+ **Step 1 — Analyze backend service surface**
16
+ Map existing API endpoints, service methods, or data models to CLI command groups:
17
+ ```typescript
18
+ interface CLICommandGroup {
19
+ name: string; // e.g., 'users', 'orders', 'config'
20
+ source: string; // API route file or service class
21
+ commands: CLICommand[];
22
+ }
23
+
24
+ interface CLICommand {
25
+ name: string; // e.g., 'list', 'create', 'delete'
26
+ sourceMethod: string; // e.g., 'UserService.findAll'
27
+ params: CLIParam[];
28
+ mutating: boolean; // true = needs confirmation/undo support
29
+ }
30
+ ```
31
+
32
+ **Step 2 — Design dual output mode**
33
+ Every command MUST support both human-readable and machine-readable output:
34
+ ```typescript
35
+ // Human mode (default): tables, colors, formatted text
36
+ function formatHuman(data: any, format: 'table' | 'list' | 'detail'): string {
37
+ if (format === 'table') return formatTable(data, { borders: true, colors: true });
38
+ if (format === 'list') return data.map((d: any) => ` • ${d.name}`).join('\n');
39
+ return JSON.stringify(data, null, 2);
40
+ }
41
+
42
+ // JSON mode (--json flag): structured output for piping/scripting
43
+ function formatJSON(data: any): string {
44
+ return JSON.stringify(data, null, 2);
45
+ }
46
+
47
+ // Error output follows same dual pattern
48
+ function formatError(error: Error, jsonMode: boolean): string {
49
+ if (jsonMode) return JSON.stringify({ error: error.message, type: error.constructor.name });
50
+ return chalk.red(`Error: ${error.message}`);
51
+ }
52
+ ```
53
+
54
+ **Step 3 — Implement session with undo/redo**
55
+ For mutating operations, maintain session state:
56
+ ```typescript
57
+ interface CLISession {
58
+ id: string;
59
+ history: SessionSnapshot[];
60
+ undoStack: SessionSnapshot[]; // max 50
61
+ redoStack: SessionSnapshot[];
62
+ modified: boolean;
63
+ }
64
+
65
+ function snapshot(session: CLISession, action: string): CLISession {
66
+ return {
67
+ ...session,
68
+ undoStack: [...session.undoStack.slice(-49), { action, state: deepCopy(session) }],
69
+ redoStack: [], // new action clears redo
70
+ modified: true,
71
+ };
72
+ }
73
+ ```
74
+
75
+ **Step 4 — Build REPL mode**
76
+ CLI enters REPL when invoked without subcommand:
77
+ ```typescript
78
+ // Click (Python) — invoke_without_command=True enters REPL
79
+ @click.group(invoke_without_command=True)
80
+ @click.pass_context
81
+ def cli(ctx):
82
+ if ctx.invoked_subcommand is None:
83
+ start_repl(ctx)
84
+
85
+ // Commander (Node.js) — detect no args
86
+ if (process.argv.length <= 2) {
87
+ startREPL({ history: '~/.myapp_history', prompt: 'myapp> ' });
88
+ }
89
+ ```
90
+
91
+ REPL features: command history (file-persisted), auto-suggest from history, tab completion, colored prompt, help command, status bar showing connection state.
92
+
93
+ **Step 5 — Package for distribution**
94
+ ```bash
95
+ # Python: PEP 420 namespace packages for independent installability
96
+ # pyproject.toml or setup.py
97
+ entry_points = {
98
+ 'console_scripts': ['myapp = myapp.cli:main'],
99
+ }
100
+
101
+ # Node.js: bin field in package.json
102
+ {
103
+ "bin": { "myapp": "./bin/cli.js" },
104
+ "files": ["bin/", "lib/"]
105
+ }
106
+ ```
107
+
108
+ **Step 6 — Verify installation**
109
+ After packaging: install locally (`pip install -e .` or `npm link`), verify binary on PATH (`which myapp`), run `myapp --version`, test `myapp --json` mode, and verify REPL launch.
110
+
111
+ #### Example
112
+
113
+ ```python
114
+ # Generated CLI structure for a backend service
115
+ # myapp/
116
+ # ├── cli.py ← Click entry point + REPL
117
+ # ├── commands/
118
+ # │ ├── users.py ← User CRUD commands
119
+ # │ ├── orders.py ← Order management
120
+ # │ └── config.py ← Config operations
121
+ # ├── core/
122
+ # │ ├── session.py ← Session + undo/redo
123
+ # │ └── client.py ← API client wrapper
124
+ # └── utils/
125
+ # ├── output.py ← Dual output (human + JSON)
126
+ # └── repl.py ← REPL with prompt-toolkit
127
+
128
+ # Usage:
129
+ # myapp users list → human-readable table
130
+ # myapp users list --json → JSON output for piping
131
+ # myapp users create --name "Alice" → creates user, snapshots for undo
132
+ # myapp → enters REPL mode
133
+ ```
@@ -0,0 +1,87 @@
1
+ ---
2
+ name: "database-patterns"
3
+ pack: "@rune/backend"
4
+ description: "Database design and query patterns — schema design, migrations, indexing strategies, N+1 prevention, soft deletes, read replicas, connection pooling, seeding."
5
+ model: sonnet
6
+ tools: [Read, Edit, Write, Grep, Glob, Bash]
7
+ ---
8
+
9
+ # database-patterns
10
+
11
+ Database design and query patterns — schema design, migrations, indexing strategies, N+1 prevention, soft deletes, read replicas, connection pooling, seeding.
12
+
13
+ #### Workflow
14
+
15
+ **Step 1 — Detect ORM and query patterns**
16
+ Use Grep to find ORM usage (`prisma.`, `knex(`, `sequelize.`, `typeorm`, `drizzle`, `mongoose.`, `db.query`) and raw SQL strings. Read schema files (`schema.prisma`, `migrations/`, `models/`) to understand the data model.
17
+
18
+ **Step 2 — Detect N+1 and missing indexes**
19
+ Scan for loops containing database calls (a query inside `for`, `map`, `forEach` → N+1). Check foreign key columns for missing indexes. Identify queries with `WHERE` clauses on unindexed columns. Flag each with the specific query and fix.
20
+
21
+ **Step 3 — Emit optimized queries**
22
+ For N+1: emit eager loading (`include`, `populate`, `JOIN`). For missing indexes: emit migration files. For unsafe raw SQL: emit parameterized version. For connection pooling: check pool config and recommend sizing based on max connections.
23
+
24
+ **Step 4 — Soft delete and query scoping**
25
+ Emit soft delete pattern: add `deleted_at TIMESTAMPTZ` column, update all `findMany`/`findUnique` calls to include `WHERE deleted_at IS NULL`. Cascade consideration: soft-delete parent should soft-delete children (emit trigger or application-level cascade). For Prisma: emit a custom extension that injects the filter automatically. Warn about index bloat from soft-deleted rows — add partial index `WHERE deleted_at IS NULL` to keep index lean.
26
+
27
+ **Step 5 — Read replicas, connection pooling, and seeding**
28
+ Read replicas: emit query routing — writes to primary, reads to replica. Handle replication lag: do not read from replica immediately after write in the same request (use primary for the read-after-write). For Prisma: emit `$extends` with read/write client split. Connection pooling deep dive: PgBouncer in transaction mode for serverless (each query gets a connection); Prisma's built-in pool for long-running servers. Pool sizing formula: `connections = (core_count * 2) + effective_spindle_count`. Seeding: emit factory functions using `@faker-js/faker` — deterministic seeds via `faker.seed(42)` for reproducible test data.
29
+
30
+ #### Example
31
+
32
+ ```typescript
33
+ // BEFORE: N+1 — one query per post to get author
34
+ const posts = await prisma.post.findMany();
35
+ for (const post of posts) {
36
+ post.author = await prisma.user.findUnique({ where: { id: post.authorId } });
37
+ }
38
+
39
+ // AFTER: eager loading, single query with JOIN
40
+ const posts = await prisma.post.findMany({
41
+ include: { author: { select: { id: true, name: true, avatar: true } } },
42
+ });
43
+
44
+ // Migration: missing indexes + soft delete column
45
+ -- Migration: add_indexes_and_soft_delete_to_posts
46
+ ALTER TABLE posts ADD COLUMN deleted_at TIMESTAMPTZ;
47
+ CREATE INDEX idx_posts_author_id ON posts(author_id);
48
+ CREATE INDEX idx_posts_created_at ON posts(created_at DESC);
49
+ CREATE INDEX idx_posts_active ON posts(author_id, created_at DESC) WHERE deleted_at IS NULL;
50
+
51
+ // Prisma soft delete extension (auto-scopes all queries)
52
+ const softDelete = Prisma.defineExtension({
53
+ name: 'softDelete',
54
+ query: {
55
+ $allModels: {
56
+ async findMany({ model, operation, args, query }) {
57
+ args.where = { ...args.where, deletedAt: null };
58
+ return query(args);
59
+ },
60
+ async delete({ model, args, query }) {
61
+ return (query as any)({ ...args, data: { deletedAt: new Date() } } as any);
62
+ },
63
+ },
64
+ },
65
+ });
66
+ const prisma = new PrismaClient().$extends(softDelete);
67
+
68
+ // Read replica routing with Prisma
69
+ const primaryClient = new PrismaClient({ datasources: { db: { url: PRIMARY_URL } } });
70
+ const replicaClient = new PrismaClient({ datasources: { db: { url: REPLICA_URL } } });
71
+ const db = { write: primaryClient, read: replicaClient };
72
+ // Usage: db.write.user.create(...) vs db.read.user.findMany(...)
73
+
74
+ // Factory seeding
75
+ import { faker } from '@faker-js/faker';
76
+ faker.seed(42); // reproducible
77
+
78
+ const createUserFactory = (overrides = {}) => ({
79
+ id: faker.string.uuid(),
80
+ email: faker.internet.email(),
81
+ name: faker.person.fullName(),
82
+ createdAt: faker.date.past(),
83
+ ...overrides,
84
+ });
85
+
86
+ await prisma.user.createMany({ data: Array.from({ length: 50 }, () => createUserFactory()) });
87
+ ```
@@ -0,0 +1,104 @@
1
+ ---
2
+ name: "middleware-patterns"
3
+ pack: "@rune/backend"
4
+ description: "Middleware architecture — request validation, error handling, logging, CORS, compression, graceful shutdown, health checks, request ID tracking."
5
+ model: sonnet
6
+ tools: [Read, Edit, Write, Grep, Glob, Bash]
7
+ ---
8
+
9
+ # middleware-patterns
10
+
11
+ Middleware architecture — request validation, error handling, logging, CORS, compression, graceful shutdown, health checks, request ID tracking.
12
+
13
+ #### Workflow
14
+
15
+ **Step 1 — Audit middleware stack**
16
+ Read the main server file (app.ts, server.ts, index.ts) to inventory all middleware in registration order. Check for: missing request ID generation, missing structured logging, inconsistent error responses, missing input validation, CORS misconfiguration (`*` in production).
17
+
18
+ **Step 2 — Detect error handling gaps**
19
+ Use Grep to find `catch` blocks, error middleware signatures (`err, req, res, next`), and unhandled promise rejections. Check if errors return consistent format (same envelope for 400, 401, 403, 404, 500). Flag any that leak stack traces or internal details in production.
20
+
21
+ **Step 3 — Emit middleware improvements**
22
+ For each gap, emit the middleware function: request ID (`X-Request-Id` header, UUID per request), structured JSON logger (request method, path, status, duration, request ID), global error handler with consistent envelope, Zod-based request validation middleware.
23
+
24
+ **Step 4 — Compression strategy**
25
+ Emit response compression middleware. Use `brotli` for static assets and pre-compressible responses (better ratio than gzip, supported by all modern clients). Use `gzip` as fallback for older clients. Conditional compression: skip for already-compressed content types (`image/*`, `video/*`, `application/zip`) — compressing these wastes CPU. In Express: use `compression` package with a `filter` function. In Fastify: `@fastify/compress` with `encodings: ['br', 'gzip']`. Minimum size threshold: do not compress responses < 1KB (overhead exceeds benefit).
26
+
27
+ **Step 5 — Graceful shutdown and health checks**
28
+ Graceful shutdown: on `SIGTERM`/`SIGINT`, stop accepting new connections, wait for in-flight requests to complete (timeout 30s), then close DB pools and exit. Emit the shutdown handler for Express (`server.close()`), Fastify (`fastify.close()`), and worker processes. Health check endpoints: `/health/live` (liveness — is the process alive? return 200 always unless process is broken), `/health/ready` (readiness — can it serve traffic? check DB connection, Redis connection, return 503 if dependencies are down). In Kubernetes: map liveness to `livenessProbe`, readiness to `readinessProbe`. Do NOT check external third-party APIs in readiness — only your own dependencies.
29
+
30
+ #### Example
31
+
32
+ ```typescript
33
+ // Request ID middleware
34
+ const requestId = (req, res, next) => {
35
+ req.id = req.headers['x-request-id'] || crypto.randomUUID();
36
+ res.setHeader('X-Request-Id', req.id);
37
+ next();
38
+ };
39
+
40
+ // Structured error handler — consistent envelope, no stack leak
41
+ const errorHandler = (err, req, res, _next) => {
42
+ const status = err.status || 500;
43
+ const message = status < 500 ? err.message : 'Internal server error';
44
+ logger.error({ err, requestId: req.id, path: req.path });
45
+ res.status(status).json({
46
+ error: { code: err.code || 'INTERNAL_ERROR', message },
47
+ request_id: req.id,
48
+ });
49
+ };
50
+
51
+ // Zod validation middleware
52
+ const validate = (schema: z.ZodSchema) => (req, res, next) => {
53
+ const result = schema.safeParse({ body: req.body, query: req.query, params: req.params });
54
+ if (!result.success) {
55
+ return res.status(400).json({ error: { code: 'VALIDATION_ERROR', message: 'Invalid request', details: result.error.flatten() } });
56
+ }
57
+ Object.assign(req, result.data);
58
+ next();
59
+ };
60
+
61
+ // Compression with conditional skip (Express)
62
+ import compression from 'compression';
63
+ app.use(compression({
64
+ filter: (req, res) => {
65
+ const contentType = res.getHeader('Content-Type') as string || '';
66
+ if (/image|video|audio|zip|gz|br/.test(contentType)) return false;
67
+ return compression.filter(req, res);
68
+ },
69
+ threshold: 1024, // skip responses < 1KB
70
+ }));
71
+
72
+ // Graceful shutdown
73
+ const gracefulShutdown = async (signal: string) => {
74
+ console.log(`Received ${signal}, shutting down gracefully...`);
75
+ server.close(async () => {
76
+ try {
77
+ await prisma.$disconnect();
78
+ await redis.quit();
79
+ console.log('All connections closed. Exiting.');
80
+ process.exit(0);
81
+ } catch (err) {
82
+ console.error('Error during shutdown:', err);
83
+ process.exit(1);
84
+ }
85
+ });
86
+ // Force exit after 30s if still not done
87
+ setTimeout(() => { console.error('Forced shutdown after timeout'); process.exit(1); }, 30_000);
88
+ };
89
+ process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
90
+ process.on('SIGINT', () => gracefulShutdown('SIGINT'));
91
+
92
+ // Health check endpoints
93
+ app.get('/health/live', (req, res) => res.json({ status: 'ok' }));
94
+
95
+ app.get('/health/ready', async (req, res) => {
96
+ const checks = await Promise.allSettled([
97
+ prisma.$queryRaw`SELECT 1`, // DB check
98
+ redis.ping(), // Redis check
99
+ ]);
100
+ const results = { db: checks[0].status, redis: checks[1].status };
101
+ const allHealthy = checks.every(c => c.status === 'fulfilled');
102
+ res.status(allHealthy ? 200 : 503).json({ status: allHealthy ? 'ready' : 'degraded', checks: results });
103
+ });
104
+ ```