webspresso 0.0.104 → 0.0.106

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 (233) hide show
  1. package/.agents/AGENTS.md +21 -2
  2. package/.agents/ARCHITECTURE.md +23 -0
  3. package/.agents/CACHE.md +147 -0
  4. package/.agents/CLI.md +220 -8
  5. package/.agents/EARLY_HINTS.md +120 -0
  6. package/.agents/FLAGS.md +118 -0
  7. package/.agents/HEALTH.md +118 -0
  8. package/.agents/LIMITS.md +109 -0
  9. package/.agents/LOGGING.md +93 -0
  10. package/.agents/METRICS.md +127 -0
  11. package/.agents/MIGRATION_JOBS.md +95 -0
  12. package/.agents/ORM.md +155 -1
  13. package/.agents/PLUGINS.md +38 -3
  14. package/.agents/QUEUE.md +42 -0
  15. package/.agents/RATE_LIMIT.md +147 -0
  16. package/.agents/RESILIENCE.md +235 -0
  17. package/.agents/SCALE_OUT.md +109 -0
  18. package/.agents/SECRETS.md +117 -0
  19. package/AGENTS.md +16 -0
  20. package/README.md +2 -2
  21. package/bin/commands/add-aws.js +396 -0
  22. package/bin/commands/add-ci.js +523 -0
  23. package/bin/commands/add-cloudflare.js +240 -0
  24. package/bin/commands/add-cloudrun.js +381 -0
  25. package/bin/commands/add-docker.js +6 -6
  26. package/bin/commands/add-migration-job.js +396 -0
  27. package/bin/commands/assets-sync.js +209 -0
  28. package/bin/commands/client-generate.js +52 -0
  29. package/bin/commands/console.js +53 -0
  30. package/bin/commands/db-migrate.js +47 -2
  31. package/bin/commands/db-studio.js +84 -0
  32. package/bin/commands/deploy-check.js +242 -13
  33. package/bin/commands/dev.js +1 -1
  34. package/bin/commands/export.js +87 -0
  35. package/bin/commands/new.js +5 -5
  36. package/bin/commands/openapi.js +1 -1
  37. package/bin/commands/secrets-pull.js +208 -0
  38. package/bin/commands/start.js +1 -1
  39. package/bin/utils/db.js +7 -1
  40. package/bin/utils/project.js +2 -2
  41. package/bin/webspresso.js +22 -0
  42. package/core/app.js +421 -0
  43. package/core/auth/authenticate.js +93 -0
  44. package/core/auth/hash.js +5 -4
  45. package/core/auth/index.js +34 -4
  46. package/core/auth/jwt.js +5 -54
  47. package/core/auth/magic-link.js +4 -5
  48. package/core/auth/manager.js +53 -10
  49. package/core/auth/middleware.js +16 -68
  50. package/core/auth/oauth.js +8 -17
  51. package/core/auth/redis-session.js +1008 -0
  52. package/core/auth/sessions.js +156 -0
  53. package/core/auth/totp.js +2 -1
  54. package/core/cache/byte-size.js +123 -0
  55. package/core/cache/cdn.js +296 -0
  56. package/core/cache/index.js +33 -0
  57. package/core/cache/lru.js +477 -0
  58. package/core/cache/tagged-lru.js +354 -0
  59. package/core/commands/registry.js +6 -20
  60. package/core/console/commands.js +148 -0
  61. package/core/console/context.js +260 -0
  62. package/core/console/eval.js +70 -0
  63. package/core/console/index.js +22 -0
  64. package/core/console/repl.js +102 -0
  65. package/core/early-hints/index.js +267 -0
  66. package/core/errors/domain.js +49 -0
  67. package/core/errors/http.js +31 -0
  68. package/core/errors/index.js +10 -0
  69. package/core/errors/normalize.js +88 -2
  70. package/core/events/discovery.js +6 -24
  71. package/core/events/dispatcher.js +9 -7
  72. package/core/events/signal.js +7 -0
  73. package/core/export/discovery.js +191 -0
  74. package/core/export/exporter.js +277 -0
  75. package/core/export/index.js +24 -0
  76. package/core/flags/evaluator.js +252 -0
  77. package/core/flags/hasher.js +37 -0
  78. package/core/flags/index.js +21 -0
  79. package/core/flags/manager.js +263 -0
  80. package/core/flags/store.js +126 -0
  81. package/core/health/index.js +41 -0
  82. package/core/health/middleware.js +213 -0
  83. package/core/health/normalize.js +140 -0
  84. package/core/health/probes.js +203 -0
  85. package/core/http/adapter.js +74 -0
  86. package/core/http/express-adapter.js +46 -0
  87. package/core/http/hono-adapter.js +531 -0
  88. package/core/http/index.js +41 -0
  89. package/core/http/pipeline.js +485 -0
  90. package/core/index.js +336 -0
  91. package/core/limits/index.js +34 -0
  92. package/core/limits/middleware.js +325 -0
  93. package/core/limits/normalize.js +222 -0
  94. package/core/logger/formatters.js +264 -0
  95. package/core/logger/index.js +260 -0
  96. package/core/logger/trace.js +137 -0
  97. package/core/metrics/collectors.js +125 -0
  98. package/core/metrics/index.js +45 -0
  99. package/core/metrics/middleware.js +230 -0
  100. package/core/metrics/registry.js +366 -0
  101. package/core/orm/batch.js +70 -0
  102. package/core/orm/cache/fingerprint.js +2 -2
  103. package/core/orm/cache/memory-provider.js +27 -110
  104. package/core/orm/d1.js +265 -0
  105. package/core/orm/index.js +176 -13
  106. package/core/orm/json-fields.js +22 -8
  107. package/core/orm/migrate-cloud.js +194 -0
  108. package/core/orm/model.js +10 -0
  109. package/core/orm/pool.js +97 -0
  110. package/core/orm/query-builder.js +72 -9
  111. package/core/orm/repository.js +318 -19
  112. package/core/orm/schema-helpers.js +8 -10
  113. package/core/orm/scopes.js +321 -1
  114. package/core/orm/transaction.js +10 -2
  115. package/core/orm/utils.js +4 -86
  116. package/core/queue/adapters/cloudflare.js +131 -0
  117. package/core/queue/adapters/database.js +4 -8
  118. package/core/queue/adapters/pubsub.js +400 -0
  119. package/core/queue/adapters/sqs.js +419 -0
  120. package/core/queue/adapters/wait-until.js +77 -0
  121. package/core/queue/index.js +8 -0
  122. package/core/queue/manager.js +66 -41
  123. package/core/rate-limit/index.js +22 -0
  124. package/core/rate-limit/limiter.js +219 -0
  125. package/core/rate-limit/stores/memory.js +129 -0
  126. package/core/rate-limit/stores/redis.js +151 -0
  127. package/core/rate-limit/utils.js +112 -0
  128. package/core/resilience/circuit-breaker.js +422 -0
  129. package/core/resilience/errors.js +63 -0
  130. package/core/resilience/index.js +53 -0
  131. package/core/resilience/registry.js +97 -0
  132. package/core/resilience/retry.js +203 -0
  133. package/core/schema-cache.js +9 -2
  134. package/core/secrets/index.js +113 -0
  135. package/core/secrets/manager.js +308 -0
  136. package/core/secrets/providers/aws.js +288 -0
  137. package/core/secrets/providers/env.js +44 -0
  138. package/core/secrets/providers/gcp.js +307 -0
  139. package/core/secrets/providers/memory.js +76 -0
  140. package/core/shutdown/http-adapter.js +4 -1
  141. package/core/shutdown/shutdown-manager.js +129 -19
  142. package/core/stream/index.js +19 -0
  143. package/core/stream/text-stream.js +326 -0
  144. package/core/studio/index.js +43 -0
  145. package/core/studio/inspector.js +258 -0
  146. package/core/studio/server.js +325 -0
  147. package/core/studio/ui.js +681 -0
  148. package/core/utils/array.js +12 -0
  149. package/core/utils/base64url.js +8 -0
  150. package/core/utils/crypto.js +118 -0
  151. package/core/utils/ensure-leading-slash.js +6 -0
  152. package/core/utils/escape-regexp.js +7 -0
  153. package/core/utils/fetch.js +6 -5
  154. package/core/utils/fs.js +144 -0
  155. package/core/utils/hmac.js +6 -0
  156. package/core/utils/json.js +98 -0
  157. package/core/utils/object.js +106 -0
  158. package/core/utils/random.js +9 -0
  159. package/core/utils/regex.js +77 -0
  160. package/core/utils/sha256.js +6 -0
  161. package/core/utils/string.js +87 -0
  162. package/core/utils/strip-trailing-slash.js +6 -0
  163. package/core/utils/time.js +96 -0
  164. package/core/utils/timeout.js +348 -0
  165. package/core/utils/url.js +106 -0
  166. package/core/utils/walk.js +7 -0
  167. package/index.d.ts +1549 -2
  168. package/index.js +272 -2
  169. package/package.json +3 -2
  170. package/plugins/admin-panel/core/api-extensions.js +2 -5
  171. package/plugins/admin-panel/index.js +13 -6
  172. package/plugins/admin-panel/modules/menu.js +1 -1
  173. package/plugins/api-key/crypto.js +3 -3
  174. package/plugins/api-key/index.js +3 -2
  175. package/plugins/api-key/scopes.js +5 -7
  176. package/plugins/audit-log/api-handlers.js +6 -15
  177. package/plugins/audit-log/index.js +3 -1
  178. package/plugins/audit-log/parse.js +3 -3
  179. package/plugins/basic-auth/index.js +3 -2
  180. package/plugins/cors.js +3 -2
  181. package/plugins/csrf/index.js +9 -12
  182. package/plugins/csv/index.js +8 -5
  183. package/plugins/dashboard/app.js +2 -2
  184. package/plugins/dashboard/index.js +5 -5
  185. package/plugins/data-exchange/record-selection.js +2 -5
  186. package/plugins/email/api-handlers.js +5 -18
  187. package/plugins/email/auth-bridge.js +3 -2
  188. package/plugins/email/index.js +11 -9
  189. package/plugins/health-check.js +2 -1
  190. package/plugins/index.js +5 -0
  191. package/plugins/lazy.js +5 -6
  192. package/plugins/mcp/discovery.js +18 -17
  193. package/plugins/polar/src/api.js +2 -1
  194. package/plugins/polar/src/webhooks.js +5 -6
  195. package/plugins/queue/index.js +18 -2
  196. package/plugins/rate-limit/index.js +3 -1
  197. package/plugins/redirect/index.js +16 -9
  198. package/plugins/rls/index.js +170 -0
  199. package/plugins/seo-checker/index.js +2 -2
  200. package/plugins/site-analytics/index.js +3 -1
  201. package/plugins/site-analytics/tracking.js +2 -2
  202. package/plugins/sitemap.js +3 -2
  203. package/plugins/swagger.js +12 -5
  204. package/plugins/upload/gcs-provider.js +148 -0
  205. package/plugins/upload/index.js +136 -77
  206. package/plugins/upload/orphan-pruner.js +4 -3
  207. package/plugins/upload/s3-provider.js +257 -0
  208. package/plugins/webhooks/crypto.js +6 -11
  209. package/plugins/webhooks/dispatcher.js +8 -8
  210. package/plugins/webhooks/index.js +33 -23
  211. package/plugins/webhooks/matcher.js +7 -11
  212. package/plugins/webhooks/sender.js +8 -11
  213. package/plugins/xlsx/index.js +7 -5
  214. package/src/api/api-loader.js +12 -95
  215. package/src/api/define-api.js +1 -0
  216. package/src/app-context.js +41 -5
  217. package/src/client-runtime/constants.js +10 -0
  218. package/src/client-runtime/mount.js +2 -3
  219. package/src/dev/banner.js +6 -2
  220. package/src/dev/client-gen.js +458 -0
  221. package/src/discovery/scan-routes.js +5 -2
  222. package/src/file-router.js +3 -3
  223. package/src/helpers.js +212 -24
  224. package/src/modules/module-discovery.js +1 -9
  225. package/src/pages/page-loader.js +13 -154
  226. package/src/plugin-manager.js +99 -18
  227. package/src/server.js +335 -133
  228. package/src/services/discovery.js +19 -40
  229. package/src/services/executor.js +95 -25
  230. package/src/services/memoize.js +3 -25
  231. package/src/services/registry.js +15 -1
  232. package/src/services/validator.js +38 -20
  233. package/src/template/precompile.js +8 -19
@@ -0,0 +1,118 @@
1
+ # Feature Flags & Canary Traffic Splitter (`core/flags`)
2
+
3
+ Webspresso features an enterprise-grade, zero-dependency **Feature Flag & Canary Traffic Splitting Engine** in `core/flags/`. It enables gradual rollouts, multivariate A/B testing, user/role/domain targeting, and runtime overrides across Nunjucks SSR templates, API endpoints (`defineApi`), service layers, and Edge/Hono adapters.
4
+
5
+ ---
6
+
7
+ ## 🎯 Key Capabilities
8
+
9
+ 1. **Sub-Microsecond Deterministic Bucketing**:
10
+ - FNV-1a 32-bit hashing algorithm (`getBucket`) maps user identifiers to deterministic integer buckets `0 .. 99` across distributed nodes without network calls.
11
+ 2. **Flexible Targeting Rules**:
12
+ - **Boolean Toggles**: `enabled: true | false`.
13
+ - **Canary Percentage Rollout**: `rollout: 10` (10% of traffic, consistent per user).
14
+ - **Targeted Whitelists**: `users: ['user_123', 'admin@corp.com']`.
15
+ - **Role-Based Targeting**: `roles: ['admin', 'beta_tester']`.
16
+ - **Email Domain Targeting**: `emailDomains: ['acme.com']`.
17
+ - **Multivariate A/B Variants**: `variants: [{ name: 'blue_button', weight: 50 }, { name: 'green_button', weight: 50 }]`.
18
+ - **Custom Predicates**: `condition: (ctx) => ctx.plan === 'enterprise'`.
19
+ 3. **Multi-Layer Integration**:
20
+ - **Express / Hono Middleware**: Automatically injects `req.flags`, `req.hasFeature()`, and `req.getVariant()`.
21
+ - **Nunjucks SSR Templates**: Access via `{{ fsy.hasFeature('new_ui') }}` and `{{ fsy.flag('theme') }}`.
22
+ - **Declarative API Route Guard**: `defineApi({ flag: 'beta_feature' })` returns HTTP 404 (or configured status) if disabled.
23
+ - **Environment Variable Overrides**: Instant runtime overrides via `FEATURE_<FLAG_NAME>=true|false`.
24
+
25
+ ---
26
+
27
+ ## 🚀 Quick Start
28
+
29
+ ### 1. Application Configuration
30
+
31
+ ```javascript
32
+ const { createApp } = require('webspresso');
33
+
34
+ const app = createApp({
35
+ flags: {
36
+ // 1. Simple toggle
37
+ dark_mode: true,
38
+
39
+ // 2. 20% Canary rollout
40
+ new_checkout: {
41
+ rollout: 20,
42
+ },
43
+
44
+ // 3. User & Role targeting
45
+ ai_assistant: {
46
+ roles: ['pro', 'admin'],
47
+ users: ['vip_client_1'],
48
+ },
49
+
50
+ // 4. Multivariate A/B Test
51
+ pricing_page_test: {
52
+ variants: [
53
+ { name: 'control', weight: 50 },
54
+ { name: 'discount_banner', weight: 50 },
55
+ ],
56
+ },
57
+ },
58
+ });
59
+ ```
60
+
61
+ ### 2. Nunjucks SSR Templates (`pages/*.njk`)
62
+
63
+ ```nunjucks
64
+ {% if fsy.hasFeature('new_checkout') %}
65
+ {% include "components/new-checkout.njk" %}
66
+ {% else %}
67
+ {% include "components/legacy-checkout.njk" %}
68
+ {% endif %}
69
+
70
+ {% if fsy.flag('pricing_page_test') == 'discount_banner' %}
71
+ <div class="banner">Special 20% Discount Applied!</div>
72
+ {% endif %}
73
+ ```
74
+
75
+ ### 3. File-Based API Endpoints (`pages/api/...`)
76
+
77
+ ```javascript
78
+ const { defineApi } = require('webspresso');
79
+
80
+ module.exports = defineApi({
81
+ // Automatically blocks request with HTTP 404 if flag is disabled
82
+ flag: 'ai_assistant',
83
+ handler: async (req, res, ctx) => {
84
+ // Also accessible inside ctx or req
85
+ const isVip = ctx.hasFeature('vip_access');
86
+ return res.json({ success: true, isVip });
87
+ },
88
+ });
89
+ ```
90
+
91
+ ### 4. Route Guard Middleware
92
+
93
+ ```javascript
94
+ const { createFeatureFlagManager } = require('webspresso');
95
+
96
+ const flags = createFeatureFlagManager({
97
+ flags: { secret_admin: { roles: ['admin'] } },
98
+ });
99
+
100
+ // Use as standalone route middleware
101
+ app.get('/admin/secret', flags.guard('secret_admin', { statusCode: 403 }), (req, res) => {
102
+ res.send('Welcome, Admin!');
103
+ });
104
+ ```
105
+
106
+ ---
107
+
108
+ ## ⚙️ Environment Overrides
109
+
110
+ Flags can be overridden at runtime without code deployment or restart:
111
+
112
+ ```bash
113
+ # Enable flag
114
+ FEATURE_NEW_CHECKOUT=true npm start
115
+
116
+ # Disable flag
117
+ FEATURE_NEW_CHECKOUT=false npm start
118
+ ```
@@ -0,0 +1,118 @@
1
+ # Cloud & Kubernetes Health & Readiness Probes (`core/health`)
2
+
3
+ Webspresso includes a zero-dependency, Docker & Kubernetes-native health inspection system. It provides standard liveness (`/healthz`), readiness (`/readyz`), and combined diagnostics endpoints with automatic database pings, background worker queue checks, event loop delay metrics, and instant graceful shutdown draining integration.
4
+
5
+ ---
6
+
7
+ ## 🎯 Key Capabilities
8
+
9
+ 1. **Kubernetes Liveness Probe (`/healthz`)**:
10
+ - Confirms process vitality and responsiveness.
11
+ - Gathers memory footprint (`rss`, `heapUsed`, `heapTotal` formatted and raw bytes), process uptime, PID, platform, and event loop lag statistics (`meanMs`, `maxMs`, `p99Ms`).
12
+ - If event loop delay exceeds threshold (`eventLoopThresholdMs`), flags status as `degraded`.
13
+
14
+ 2. **Kubernetes Readiness Probe (`/readyz`)**:
15
+ - Confirms the container is fully prepared to handle live client traffic.
16
+ - **Database Connectivity**: Pings active Knex instance (`SELECT 1`) with timeout protection.
17
+ - **Queue Readiness**: Probes worker queue instance status.
18
+ - **Custom Probes**: Executes user-registered async checks concurrently (`checks: { redis, stripe }`).
19
+ - Returns `HTTP 200` (`{ ready: true, status: 'ready' }`) when all components are healthy.
20
+ - Returns `HTTP 503` (`{ ready: false, status: 'unhealthy', checks: ... }`) if any component fails.
21
+
22
+ 3. **Graceful Draining Integration (`ShutdownManager`)**:
23
+ - As soon as the server enters shutdown draining (`app.close()` or `SIGTERM`/`SIGINT`), `/readyz` immediately returns `HTTP 503` (`{ ready: false, status: 'draining' }`).
24
+ - Cloud load balancers (AWS ALB, K8s Ingress, Google Cloud, Cloudflare) immediately stop routing new traffic to this instance, while existing active requests drain cleanly without dropping a single connection.
25
+
26
+ ---
27
+
28
+ ## 🚀 Configuration Examples
29
+
30
+ ### 1. Simple Enablement
31
+
32
+ ```javascript
33
+ const { createApp } = require('webspresso');
34
+
35
+ const app = createApp({
36
+ pagesDir: 'pages',
37
+ // Enables /healthz (liveness), /readyz (readiness), and /health (combined)
38
+ healthCheck: true,
39
+ });
40
+ ```
41
+
42
+ Shorthand custom path:
43
+ ```javascript
44
+ const app = createApp({
45
+ pagesDir: 'pages',
46
+ healthCheck: '/api/status', // Mounts combined status on /api/status
47
+ });
48
+ ```
49
+
50
+ ### 2. Full Production Configuration
51
+
52
+ ```javascript
53
+ const app = createApp({
54
+ pagesDir: 'pages',
55
+ db: myDatabaseInstance,
56
+ queue: myQueueInstance,
57
+ healthCheck: {
58
+ enabled: true,
59
+ path: '/healthz', // Liveness probe URL
60
+ readyPath: '/readyz', // Readiness probe URL
61
+ combinedPath: '/health', // Diagnostic summary URL
62
+ db: true, // Automatically probe database (SELECT 1)
63
+ queue: true, // Automatically probe worker queue
64
+ eventLoopLag: true, // Monitor event loop delay
65
+ eventLoopThresholdMs: 300, // Lag threshold in ms
66
+ timeoutMs: 2500, // Probe timeout before marking down
67
+ checks: { // Custom dependency probes
68
+ redis: async () => redisClient.ping(),
69
+ stripe: async () => checkStripeHealth(),
70
+ },
71
+ headers: {
72
+ 'Cache-Control': 'no-store, no-cache, must-revalidate',
73
+ 'X-Content-Type-Options': 'nosniff',
74
+ },
75
+ },
76
+ });
77
+ ```
78
+
79
+ ---
80
+
81
+ ## ☸️ Kubernetes Pod Spec Example
82
+
83
+ ```yaml
84
+ livenessProbe:
85
+ httpGet:
86
+ path: /healthz
87
+ port: 3000
88
+ initialDelaySeconds: 5
89
+ periodSeconds: 10
90
+ timeoutSeconds: 3
91
+ failureThreshold: 3
92
+
93
+ readinessProbe:
94
+ httpGet:
95
+ path: /readyz
96
+ port: 3000
97
+ initialDelaySeconds: 2
98
+ periodSeconds: 5
99
+ timeoutSeconds: 2
100
+ failureThreshold: 2
101
+ ```
102
+
103
+ ---
104
+
105
+ ## 🔍 Programmatic Inspection
106
+
107
+ Access health state directly in code or CLI scripts:
108
+
109
+ ```javascript
110
+ // Get complete diagnostic payload
111
+ const status = await app.getHealthStatus();
112
+ console.log('Liveness:', status.liveness);
113
+ console.log('Readiness:', status.readiness);
114
+
115
+ // Or via healthManager
116
+ const liveness = await app.healthManager.getLiveness();
117
+ const readiness = await app.healthManager.getReadiness();
118
+ ```
@@ -0,0 +1,109 @@
1
+ # Configurable Payload Size Limits & DoS Protection (`core/limits`)
2
+
3
+ Webspresso provides a zero-dependency, configurable request body size limiter and Denial of Service (DoS) protection layer. It safeguards Node.js memory against payload exhaustion attacks while supporting per-route overrides, streaming bypass, and native raw body capture for HMAC webhook verification.
4
+
5
+ ---
6
+
7
+ ## 🎯 Key Capabilities
8
+
9
+ 1. **Multi-Parser Configuration**:
10
+ - `json`: Size limit for `application/json` (default: `'1mb'`).
11
+ - `urlencoded`: Size limit for `application/x-www-form-urlencoded` (default: `'1mb'`).
12
+ - `parameterLimit`: Maximum number of URL-encoded form parameters (default: `1000`).
13
+ - `raw`: Size limit for `application/octet-stream` (default: `false` / disabled).
14
+ - `text`: Size limit for `text/plain` (default: `false` / disabled).
15
+ 2. **Standard Exception Mapping**:
16
+ - Limit exceeded -> Throws `PayloadTooLargeError` (HTTP 413) with `{ limit, length, expected }` details and `code: 'PAYLOAD_TOO_LARGE'`.
17
+ - Parameter exhaustion -> Throws `PayloadTooLargeError` (HTTP 413) with `code: 'PARAMETERS_TOO_MANY'`.
18
+ - Malformed JSON -> Throws `BadRequestError` (HTTP 400) with `code: 'INVALID_JSON_PAYLOAD'`.
19
+ 3. **Webhook & HMAC Signature Verification**:
20
+ - `captureRawBody: true` stores incoming unparsed `Buffer` on `req.rawBody` for zero-overhead cryptographic signatures (Polar, Stripe, LemonSqueezy, GitHub).
21
+ 4. **Route Overrides & Streaming Bypass**:
22
+ - `limits.routes`: Generous limits for specific paths (e.g. `/api/upload` -> 25MB) without loosening server-wide protection.
23
+ - `limits.exclude`: Completely skips global body parsers for streaming and custom multipart endpoints.
24
+
25
+ ---
26
+
27
+ ## 🚀 Configuration Examples
28
+
29
+ ### 1. Global Configuration
30
+
31
+ ```javascript
32
+ const { createApp } = require('webspresso');
33
+
34
+ const app = createApp({
35
+ pagesDir: 'pages',
36
+ limits: {
37
+ json: '2mb', // 2 Megabytes for JSON
38
+ urlencoded: '1mb', // 1 Megabyte for Forms
39
+ parameterLimit: 2000, // Up to 2000 parameters
40
+ raw: '10mb', // Enable raw buffer parsing for binary data
41
+ captureRawBody: true, // Automatically populate req.rawBody
42
+ },
43
+ });
44
+ ```
45
+
46
+ Shorthand (applies to both JSON and URL-encoded):
47
+ ```javascript
48
+ const app = createApp({
49
+ pagesDir: 'pages',
50
+ limits: '5mb', // Both json and urlencoded set to 5 MB
51
+ });
52
+ ```
53
+
54
+ ### 2. Route Overrides & Exclusions
55
+
56
+ ```javascript
57
+ const app = createApp({
58
+ pagesDir: 'pages',
59
+ limits: {
60
+ json: '500kb', // Tight global limit for standard APIs
61
+ routes: {
62
+ '/api/import/json': { json: '25mb' }, // Relaxed limit for batch import
63
+ '/api/webhooks/*': { raw: '5mb', captureRawBody: true },
64
+ },
65
+ exclude: [
66
+ '/api/stream/upload', // Skip global body parser entirely for socket streaming
67
+ ],
68
+ },
69
+ });
70
+ ```
71
+
72
+ ### 3. Webhook Signature Verification with `req.rawBody`
73
+
74
+ ```javascript
75
+ // pages/api/webhooks/polar.post.js
76
+ const crypto = require('crypto');
77
+ const { defineApi, UnauthorizedError } = require('webspresso');
78
+
79
+ module.exports = defineApi({
80
+ handler: async (req, res) => {
81
+ const signature = req.headers['webhook-signature'];
82
+ const expected = crypto
83
+ .createHmac('sha256', process.env.POLAR_WEBHOOK_SECRET)
84
+ .update(req.rawBody) // Native Buffer captured via captureRawBody
85
+ .digest('hex');
86
+
87
+ if (signature !== expected) {
88
+ throw new UnauthorizedError('Invalid signature');
89
+ }
90
+
91
+ return res.json({ received: true });
92
+ },
93
+ });
94
+ ```
95
+
96
+ ---
97
+
98
+ ## 🛡️ Standalone Middleware Usage
99
+
100
+ For manual route mounting or custom Express routers:
101
+
102
+ ```javascript
103
+ const { createLimitsMiddleware } = require('webspresso');
104
+
105
+ // Mount on custom router or endpoint
106
+ app.post('/custom-endpoint', createLimitsMiddleware({ json: '50mb' }), (req, res) => {
107
+ res.json({ size: req.body.length });
108
+ });
109
+ ```
@@ -0,0 +1,93 @@
1
+ # Structured Cloud Logging & Distributed Tracing Guide
2
+
3
+ Webspresso features an enterprise, zero-dependency Structured Cloud Logger (`core/logger`) designed specifically for serverless and containerized cloud platforms (Google Cloud Run, AWS App Runner, ECS Fargate, Lambda, Kubernetes).
4
+
5
+ ---
6
+
7
+ ## 🎯 Key Capabilities
8
+
9
+ 1. **Native Cloud Platform Detection & Formatting**:
10
+ - **Google Cloud Platform (`format: 'gcp'`)**: Automatically emits JSON payloads with Google Cloud Logging `severity` levels (`DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`), `logging.googleapis.com/trace`, `logging.googleapis.com/spanId`, and RFC `httpRequest` metadata.
11
+ - **Amazon Web Services (`format: 'aws'`)**: Formats logs with `level`, `requestId`, `xrayTraceId`, and `http` metrics compatible with AWS CloudWatch and AWS X-Ray.
12
+ - **Standard JSON (`format: 'json'`)**: Compact, structured single-line JSON stream for Docker, Kubernetes, and Datadog.
13
+ - **Development Pretty (`format: 'pretty'`)**: Fast, ANSI color-coded console logs for local developer happiness.
14
+ 2. **Distributed Tracing Context Propagation**:
15
+ - Parses incoming request trace headers automatically:
16
+ - `x-cloud-trace-context` (Google Cloud Trace)
17
+ - `x-amzn-trace-id` (AWS X-Ray)
18
+ - `traceparent` (W3C standard)
19
+ - `x-request-id` / `x-correlation-id`
20
+ - Injects trace ID and span ID into every log statement emitted during the request lifecycle.
21
+ 3. **Automatic Child Logger on Requests (`req.logger`)**:
22
+ - In API route handlers and SSR page loaders, `req.logger` is pre-bound to the request's trace ID and contextual metadata.
23
+ - Automatically logs HTTP access on request finish (`res.on('finish')`) with latency, status code, remote IP, and user-agent.
24
+ 4. **Deep Sensitive Key Redaction**:
25
+ - Recursively masks sensitive fields (`password`, `token`, `secret`, `authorization`, `cookie`, `apiKey`) to prevent accidental credential leakage in cloud log aggregation systems.
26
+
27
+ ---
28
+
29
+ ## 🚀 Usage in Application Code
30
+
31
+ ### In API Route Handlers
32
+
33
+ ```javascript
34
+ // pages/api/orders.post.js
35
+ const { defineApi } = require('webspresso');
36
+
37
+ module.exports = defineApi({
38
+ schema: ({ z }) => ({
39
+ body: z.object({ amount: z.number().positive(), customerId: z.string() }),
40
+ }),
41
+ handler: async (req, res) => {
42
+ // req.logger is automatically bound to the request's trace ID
43
+ req.logger.info('Processing order checkout', {
44
+ customerId: req.input.body.customerId,
45
+ amount: req.input.body.amount,
46
+ });
47
+
48
+ try {
49
+ const order = await req.service('order.create', req.input.body);
50
+ req.logger.info('Order processed successfully', { orderId: order.id });
51
+ return res.status(201).json(order);
52
+ } catch (err) {
53
+ req.logger.error('Failed to process order', { error: err.message });
54
+ throw err;
55
+ }
56
+ },
57
+ });
58
+ ```
59
+
60
+ ### Standalone Logger & Child Context
61
+
62
+ ```javascript
63
+ const { createLogger } = require('webspresso');
64
+
65
+ const logger = createLogger({
66
+ format: 'auto', // 'gcp' | 'aws' | 'json' | 'pretty'
67
+ level: 'info',
68
+ defaultMeta: { service: 'payment-worker' },
69
+ project: 'my-gcp-project', // optional GCP project ID
70
+ });
71
+
72
+ logger.info('Worker started');
73
+
74
+ // Create contextual child logger
75
+ const jobLogger = logger.child({ jobId: 'job_42' });
76
+ jobLogger.info('Task execution started');
77
+ ```
78
+
79
+ ### Configuration in `createApp`
80
+
81
+ ```javascript
82
+ const { createApp } = require('webspresso');
83
+
84
+ const app = createApp({
85
+ pagesDir: './pages',
86
+ logger: {
87
+ format: 'auto', // Auto-detected from K_SERVICE, AWS_EXECUTION_ENV, or NODE_ENV
88
+ level: 'info',
89
+ exclude: ['/healthz', '/readyz', '/favicon.ico'],
90
+ redact: ['password', 'secret', 'token'],
91
+ },
92
+ });
93
+ ```
@@ -0,0 +1,127 @@
1
+ # Cloud Metrics & Distributed Tracing Guide
2
+
3
+ Webspresso provides an enterprise-grade, zero-dependency Cloud Metrics & Distributed Tracing engine (`core/metrics`) delivering Prometheus exposition format (`/metrics`), JSON telemetry (`/metrics.json`), HTTP latency histograms, and W3C/GCP/AWS distributed tracing header propagation.
4
+
5
+ ---
6
+
7
+ ## 🎯 Key Capabilities
8
+
9
+ 1. **Prometheus-Compatible Exposition Format**:
10
+ - Zero external dependencies (no `prom-client` or OpenTelemetry npm packages required).
11
+ - Generates compliant `text/plain; version=0.0.4; charset=utf-8` output directly consumable by Prometheus, Grafana Agent, Google Cloud Managed Service for Prometheus, AWS CloudWatch Container Insights, and Datadog.
12
+ - Dual-format exposition: `/metrics` for Prometheus scraping and `/metrics.json` (or `Accept: application/json`) for programmatic inspection or lightweight dashboards.
13
+ 2. **Distributed Tracing & W3C Propagation**:
14
+ - Parses incoming tracing headers automatically (`traceparent`, `x-cloud-trace-context`, `x-amzn-trace-id`, `x-request-id`).
15
+ - Automatically injects `x-trace-id` and W3C `traceparent` (`00-${traceId}-${spanId}-01`) onto outgoing HTTP response headers.
16
+ - Attaches `req.traceId` and `req.spanId` to the incoming request object for seamless correlation with `req.logger`.
17
+ 3. **Core HTTP Request Telemetry**:
18
+ - `webspresso_http_requests_total{method, route, status}`: Counter for all processed HTTP requests.
19
+ - `webspresso_http_request_duration_seconds{method, route}`: Latency histogram with cumulative buckets, `_sum`, and `_count`.
20
+ - `webspresso_http_active_requests`: Gauge tracking in-flight concurrent requests.
21
+ - **Noise-free scraping**: Internal scrape calls to `/metrics`, `/metrics.json`, and `/healthz` are excluded from HTTP latency counters to prevent self-polluting metrics graphs.
22
+ 4. **Automated Node.js & Framework Collectors**:
23
+ - **Process & Memory**: `process_uptime_seconds`, `nodejs_heap_size_used_bytes`, `nodejs_heap_size_total_bytes`, `process_resident_memory_bytes`, `nodejs_external_memory_bytes`.
24
+ - **CPU**: `process_cpu_user_seconds_total`, `process_cpu_system_seconds_total`.
25
+ - **Event Loop Lag**: `nodejs_eventloop_lag_seconds{quantile="0.50|0.99|max"}` via native `perf_hooks.monitorEventLoopDelay`.
26
+ - **Database Connection Pool**: `webspresso_db_pool_size`, `webspresso_db_pool_used`, `webspresso_db_pool_available` (Knex pool).
27
+ - **In-Memory Cache**: `webspresso_cache_entries`, `webspresso_cache_bytes` (LRU cache).
28
+ - **Circuit Breakers**: `webspresso_circuit_breaker_state{name}` (0=closed, 1=half-open, 2=open), `webspresso_circuit_breaker_failures_total{name}`.
29
+ 5. **Security & Gating**:
30
+ - Protect metrics endpoints with bearer token authentication (`auth: 'secret-token'`).
31
+
32
+ ---
33
+
34
+ ## 🚀 Configuration & Enabling Metrics
35
+
36
+ ### 1. Enabling via `createApp`
37
+
38
+ ```javascript
39
+ const { createApp } = require('webspresso');
40
+
41
+ const { app } = createApp({
42
+ pagesDir: './pages',
43
+ metrics: {
44
+ enabled: true, // default: true if metrics option is passed
45
+ path: '/metrics', // default: '/metrics'
46
+ collectDefault: true, // default: true (system, memory, pool, cache, lag)
47
+ traceHeader: true, // default: true (x-trace-id, traceparent)
48
+ auth: process.env.METRICS_TOKEN || null, // Optional Bearer token protection
49
+ buckets: [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10],
50
+ },
51
+ });
52
+ ```
53
+
54
+ Or enable with shorthand:
55
+
56
+ ```javascript
57
+ createApp({
58
+ metrics: true, // mounts /metrics and /metrics.json with defaults
59
+ });
60
+ ```
61
+
62
+ ---
63
+
64
+ ## 📊 Custom Application Metrics
65
+
66
+ Application routes, services, and plugins can register and record custom domain metrics via `app.metrics` or `req.metrics`:
67
+
68
+ ```javascript
69
+ // Register a custom counter
70
+ const orderCounter = app.metrics.counter(
71
+ 'shop_orders_placed_total',
72
+ 'Total number of completed customer orders'
73
+ );
74
+
75
+ // Register a custom gauge
76
+ const activeUsersGauge = app.metrics.gauge(
77
+ 'shop_active_cart_sessions',
78
+ 'Number of carts currently active'
79
+ );
80
+
81
+ // In an API handler
82
+ // pages/api/checkout.post.js
83
+ module.exports = defineApi({
84
+ handler: async (req, res) => {
85
+ const order = await req.service('order.create', req.body);
86
+
87
+ // Increment domain metric
88
+ orderCounter.inc({ plan: order.plan, currency: order.currency }, 1);
89
+
90
+ return res.status(201).json(order);
91
+ },
92
+ });
93
+ ```
94
+
95
+ ---
96
+
97
+ ## 🛡️ Standalone Registry Usage
98
+
99
+ ```javascript
100
+ const { createMetricsRegistry } = require('webspresso');
101
+
102
+ const registry = createMetricsRegistry();
103
+
104
+ const counter = registry.counter('jobs_processed_total', 'Jobs processed by worker');
105
+ counter.inc({ queue: 'email', status: 'success' }, 1);
106
+
107
+ const histogram = registry.histogram('job_execution_duration_seconds', 'Job execution duration', [0.1, 0.5, 1, 5]);
108
+ histogram.observe({ queue: 'email' }, 0.24);
109
+
110
+ // Format output
111
+ console.log(registry.formatPrometheus());
112
+ console.log(JSON.stringify(registry.formatJson(), null, 2));
113
+ ```
114
+
115
+ ---
116
+
117
+ ## 📈 Prometheus Scrape Configuration (`prometheus.yml`)
118
+
119
+ ```yaml
120
+ scrape_configs:
121
+ - job_name: 'webspresso-app'
122
+ scrape_interval: 15s
123
+ metrics_path: '/metrics'
124
+ bearer_token: 'YOUR_METRICS_TOKEN' # if auth is enabled
125
+ static_configs:
126
+ - targets: ['localhost:3000']
127
+ ```
@@ -0,0 +1,95 @@
1
+ # Cloud Migration Jobs & Zero-Downtime Database Deploy Guide
2
+
3
+ Webspresso provides an enterprise, zero-downtime database migration architecture designed specifically for Google Cloud Run, AWS ECS Fargate, AWS App Runner, and Kubernetes.
4
+
5
+ ---
6
+
7
+ ## 🎯 The Cloud Migration Challenge
8
+
9
+ In containerized, autoscaling cloud platforms (such as Google Cloud Run or AWS ECS), running migrations inside the web application container startup command (`CMD ["node", "server.js"]`) causes severe production risks:
10
+
11
+ 1. **Concurrent Migration Race Conditions**: If a new revision autoscales to multiple container instances, multiple containers attempt to run migrations simultaneously, causing deadlock or corrupt schema states.
12
+ 2. **Crash Loops & Downtime**: If a migration script fails, web containers fail health checks and crash-loop, but HTTP traffic might already hit partially-migrated schemas.
13
+ 3. **Stale Lock Hangs**: If a container is forcefully terminated by Cloud Run or ECS during migration, Knex's `knex_migrations_lock` table is left locked (`Migration table is already locked`), breaking all subsequent CI/CD deployments.
14
+
15
+ ### The Webspresso Solution: Dedicated Pre-Deploy Cloud Migration Jobs
16
+
17
+ Webspresso solves this by separating database schema migrations into a single, isolated pre-deploy job that runs to completion before new web service revisions receive traffic:
18
+
19
+ ```
20
+ [ Git Push / CI/CD ]
21
+ │
22
+ ▼
23
+ [ Build Container Image ]
24
+ │
25
+ ▼
26
+ [ Run Cloud Migration Job ] ──── (Fails? Stop deployment, keep old web version running)
27
+ │ (Success)
28
+ ▼
29
+ [ Deploy Web Service Revision ] ─── (Safely route 100% traffic to new code)
30
+ ```
31
+
32
+ ---
33
+
34
+ ## 🚀 CLI Commands
35
+
36
+ ### 1. Scaffold Migration Jobs (`add:migration-job`)
37
+
38
+ ```bash
39
+ # For Google Cloud Run (cloudrun-job.yaml + deploy-cloudrun-migration.sh)
40
+ npx webspresso add:migration-job --platform cloudrun --app my-app --cloudsql "project:region:instance"
41
+
42
+ # For AWS ECS Fargate & App Runner (ecs-migration-task.json + deploy-aws-migration.sh)
43
+ npx webspresso add:migration-job --platform aws --app my-app --region us-east-1
44
+
45
+ # For Kubernetes / Helm (k8s/migration-job.yaml with pre-upgrade hooks)
46
+ npx webspresso add:migration-job --platform k8s --app my-app
47
+
48
+ # For all platforms
49
+ npx webspresso add:migration-job --platform all
50
+ ```
51
+
52
+ ---
53
+
54
+ ## ⚡ Cloud-Safe Migration Options (`db:migrate`)
55
+
56
+ Webspresso's `db:migrate` command features cloud resilience flags powered by `core/orm/migrate-cloud.js`:
57
+
58
+ ```bash
59
+ # Cloud-Safe mode: exponential backoff connection retries + automatic stale lock auto-healing
60
+ npx webspresso db:migrate --safe --env production
61
+
62
+ # Dry-run: preview pending migrations without altering the database
63
+ npx webspresso db:migrate --dry-run --env production
64
+
65
+ # Auto-heal hanging locks left by aborted serverless jobs
66
+ npx webspresso db:migrate --unlock-if-stale
67
+
68
+ # Force unlock migration table immediately
69
+ npx webspresso db:migrate --force-unlock
70
+ ```
71
+
72
+ ---
73
+
74
+ ## 🛡️ Zero-Downtime Migration Rules for Schema Evolution
75
+
76
+ When modifying production schemas under zero-downtime requirements, follow the **Expand and Contract (Parallel Run)** pattern:
77
+
78
+ | Goal | ❌ Risky (Breaks running old version) | ✅ Zero-Downtime Pattern |
79
+ | :--- | :--- | :--- |
80
+ | **Rename Column** | `table.renameColumn('old', 'new')` | 1. Add `new` column<br>2. Dual-write in application<br>3. Backfill data<br>4. Drop `old` column in subsequent deploy |
81
+ | **Drop Column** | `table.dropColumn('field')` | Remove column references in application code first, deploy code, then drop column in the next deployment. |
82
+ | **Add NOT NULL** | `table.string('col').notNullable()` | 1. Add nullable column or column with default value<br>2. Backfill existing rows<br>3. Alter to `notNullable` |
83
+ | **Add Index** | Raw `CREATE INDEX` (locks table) | In Postgres: use `CREATE INDEX CONCURRENTLY` |
84
+
85
+ ---
86
+
87
+ ## 🔍 Preflight Verification (`deploy:check`)
88
+
89
+ Webspresso's preflight scanner automatically audits migration strategies:
90
+
91
+ ```bash
92
+ npx webspresso deploy:check --platform cloudrun --strict
93
+ ```
94
+
95
+ If migrations exist and no cloud migration job is detected, it emits an actionable warning to prevent production container race conditions.