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.
- package/.agents/AGENTS.md +21 -2
- package/.agents/ARCHITECTURE.md +23 -0
- package/.agents/CACHE.md +147 -0
- package/.agents/CLI.md +220 -8
- package/.agents/EARLY_HINTS.md +120 -0
- package/.agents/FLAGS.md +118 -0
- package/.agents/HEALTH.md +118 -0
- package/.agents/LIMITS.md +109 -0
- package/.agents/LOGGING.md +93 -0
- package/.agents/METRICS.md +127 -0
- package/.agents/MIGRATION_JOBS.md +95 -0
- package/.agents/ORM.md +155 -1
- package/.agents/PLUGINS.md +38 -3
- package/.agents/QUEUE.md +42 -0
- package/.agents/RATE_LIMIT.md +147 -0
- package/.agents/RESILIENCE.md +235 -0
- package/.agents/SCALE_OUT.md +109 -0
- package/.agents/SECRETS.md +117 -0
- package/AGENTS.md +16 -0
- package/README.md +2 -2
- package/bin/commands/add-aws.js +396 -0
- package/bin/commands/add-ci.js +523 -0
- package/bin/commands/add-cloudflare.js +240 -0
- package/bin/commands/add-cloudrun.js +381 -0
- package/bin/commands/add-docker.js +6 -6
- package/bin/commands/add-migration-job.js +396 -0
- package/bin/commands/assets-sync.js +209 -0
- package/bin/commands/client-generate.js +52 -0
- package/bin/commands/console.js +53 -0
- package/bin/commands/db-migrate.js +47 -2
- package/bin/commands/db-studio.js +84 -0
- package/bin/commands/deploy-check.js +242 -13
- package/bin/commands/dev.js +1 -1
- package/bin/commands/export.js +87 -0
- package/bin/commands/new.js +5 -5
- package/bin/commands/openapi.js +1 -1
- package/bin/commands/secrets-pull.js +208 -0
- package/bin/commands/start.js +1 -1
- package/bin/utils/db.js +7 -1
- package/bin/utils/project.js +2 -2
- package/bin/webspresso.js +22 -0
- package/core/app.js +421 -0
- package/core/auth/authenticate.js +93 -0
- package/core/auth/hash.js +5 -4
- package/core/auth/index.js +34 -4
- package/core/auth/jwt.js +5 -54
- package/core/auth/magic-link.js +4 -5
- package/core/auth/manager.js +53 -10
- package/core/auth/middleware.js +16 -68
- package/core/auth/oauth.js +8 -17
- package/core/auth/redis-session.js +1008 -0
- package/core/auth/sessions.js +156 -0
- package/core/auth/totp.js +2 -1
- package/core/cache/byte-size.js +123 -0
- package/core/cache/cdn.js +296 -0
- package/core/cache/index.js +33 -0
- package/core/cache/lru.js +477 -0
- package/core/cache/tagged-lru.js +354 -0
- package/core/commands/registry.js +6 -20
- package/core/console/commands.js +148 -0
- package/core/console/context.js +260 -0
- package/core/console/eval.js +70 -0
- package/core/console/index.js +22 -0
- package/core/console/repl.js +102 -0
- package/core/early-hints/index.js +267 -0
- package/core/errors/domain.js +49 -0
- package/core/errors/http.js +31 -0
- package/core/errors/index.js +10 -0
- package/core/errors/normalize.js +88 -2
- package/core/events/discovery.js +6 -24
- package/core/events/dispatcher.js +9 -7
- package/core/events/signal.js +7 -0
- package/core/export/discovery.js +191 -0
- package/core/export/exporter.js +277 -0
- package/core/export/index.js +24 -0
- package/core/flags/evaluator.js +252 -0
- package/core/flags/hasher.js +37 -0
- package/core/flags/index.js +21 -0
- package/core/flags/manager.js +263 -0
- package/core/flags/store.js +126 -0
- package/core/health/index.js +41 -0
- package/core/health/middleware.js +213 -0
- package/core/health/normalize.js +140 -0
- package/core/health/probes.js +203 -0
- package/core/http/adapter.js +74 -0
- package/core/http/express-adapter.js +46 -0
- package/core/http/hono-adapter.js +531 -0
- package/core/http/index.js +41 -0
- package/core/http/pipeline.js +485 -0
- package/core/index.js +336 -0
- package/core/limits/index.js +34 -0
- package/core/limits/middleware.js +325 -0
- package/core/limits/normalize.js +222 -0
- package/core/logger/formatters.js +264 -0
- package/core/logger/index.js +260 -0
- package/core/logger/trace.js +137 -0
- package/core/metrics/collectors.js +125 -0
- package/core/metrics/index.js +45 -0
- package/core/metrics/middleware.js +230 -0
- package/core/metrics/registry.js +366 -0
- package/core/orm/batch.js +70 -0
- package/core/orm/cache/fingerprint.js +2 -2
- package/core/orm/cache/memory-provider.js +27 -110
- package/core/orm/d1.js +265 -0
- package/core/orm/index.js +176 -13
- package/core/orm/json-fields.js +22 -8
- package/core/orm/migrate-cloud.js +194 -0
- package/core/orm/model.js +10 -0
- package/core/orm/pool.js +97 -0
- package/core/orm/query-builder.js +72 -9
- package/core/orm/repository.js +318 -19
- package/core/orm/schema-helpers.js +8 -10
- package/core/orm/scopes.js +321 -1
- package/core/orm/transaction.js +10 -2
- package/core/orm/utils.js +4 -86
- package/core/queue/adapters/cloudflare.js +131 -0
- package/core/queue/adapters/database.js +4 -8
- package/core/queue/adapters/pubsub.js +400 -0
- package/core/queue/adapters/sqs.js +419 -0
- package/core/queue/adapters/wait-until.js +77 -0
- package/core/queue/index.js +8 -0
- package/core/queue/manager.js +66 -41
- package/core/rate-limit/index.js +22 -0
- package/core/rate-limit/limiter.js +219 -0
- package/core/rate-limit/stores/memory.js +129 -0
- package/core/rate-limit/stores/redis.js +151 -0
- package/core/rate-limit/utils.js +112 -0
- package/core/resilience/circuit-breaker.js +422 -0
- package/core/resilience/errors.js +63 -0
- package/core/resilience/index.js +53 -0
- package/core/resilience/registry.js +97 -0
- package/core/resilience/retry.js +203 -0
- package/core/schema-cache.js +9 -2
- package/core/secrets/index.js +113 -0
- package/core/secrets/manager.js +308 -0
- package/core/secrets/providers/aws.js +288 -0
- package/core/secrets/providers/env.js +44 -0
- package/core/secrets/providers/gcp.js +307 -0
- package/core/secrets/providers/memory.js +76 -0
- package/core/shutdown/http-adapter.js +4 -1
- package/core/shutdown/shutdown-manager.js +129 -19
- package/core/stream/index.js +19 -0
- package/core/stream/text-stream.js +326 -0
- package/core/studio/index.js +43 -0
- package/core/studio/inspector.js +258 -0
- package/core/studio/server.js +325 -0
- package/core/studio/ui.js +681 -0
- package/core/utils/array.js +12 -0
- package/core/utils/base64url.js +8 -0
- package/core/utils/crypto.js +118 -0
- package/core/utils/ensure-leading-slash.js +6 -0
- package/core/utils/escape-regexp.js +7 -0
- package/core/utils/fetch.js +6 -5
- package/core/utils/fs.js +144 -0
- package/core/utils/hmac.js +6 -0
- package/core/utils/json.js +98 -0
- package/core/utils/object.js +106 -0
- package/core/utils/random.js +9 -0
- package/core/utils/regex.js +77 -0
- package/core/utils/sha256.js +6 -0
- package/core/utils/string.js +87 -0
- package/core/utils/strip-trailing-slash.js +6 -0
- package/core/utils/time.js +96 -0
- package/core/utils/timeout.js +348 -0
- package/core/utils/url.js +106 -0
- package/core/utils/walk.js +7 -0
- package/index.d.ts +1549 -2
- package/index.js +272 -2
- package/package.json +3 -2
- package/plugins/admin-panel/core/api-extensions.js +2 -5
- package/plugins/admin-panel/index.js +13 -6
- package/plugins/admin-panel/modules/menu.js +1 -1
- package/plugins/api-key/crypto.js +3 -3
- package/plugins/api-key/index.js +3 -2
- package/plugins/api-key/scopes.js +5 -7
- package/plugins/audit-log/api-handlers.js +6 -15
- package/plugins/audit-log/index.js +3 -1
- package/plugins/audit-log/parse.js +3 -3
- package/plugins/basic-auth/index.js +3 -2
- package/plugins/cors.js +3 -2
- package/plugins/csrf/index.js +9 -12
- package/plugins/csv/index.js +8 -5
- package/plugins/dashboard/app.js +2 -2
- package/plugins/dashboard/index.js +5 -5
- package/plugins/data-exchange/record-selection.js +2 -5
- package/plugins/email/api-handlers.js +5 -18
- package/plugins/email/auth-bridge.js +3 -2
- package/plugins/email/index.js +11 -9
- package/plugins/health-check.js +2 -1
- package/plugins/index.js +5 -0
- package/plugins/lazy.js +5 -6
- package/plugins/mcp/discovery.js +18 -17
- package/plugins/polar/src/api.js +2 -1
- package/plugins/polar/src/webhooks.js +5 -6
- package/plugins/queue/index.js +18 -2
- package/plugins/rate-limit/index.js +3 -1
- package/plugins/redirect/index.js +16 -9
- package/plugins/rls/index.js +170 -0
- package/plugins/seo-checker/index.js +2 -2
- package/plugins/site-analytics/index.js +3 -1
- package/plugins/site-analytics/tracking.js +2 -2
- package/plugins/sitemap.js +3 -2
- package/plugins/swagger.js +12 -5
- package/plugins/upload/gcs-provider.js +148 -0
- package/plugins/upload/index.js +136 -77
- package/plugins/upload/orphan-pruner.js +4 -3
- package/plugins/upload/s3-provider.js +257 -0
- package/plugins/webhooks/crypto.js +6 -11
- package/plugins/webhooks/dispatcher.js +8 -8
- package/plugins/webhooks/index.js +33 -23
- package/plugins/webhooks/matcher.js +7 -11
- package/plugins/webhooks/sender.js +8 -11
- package/plugins/xlsx/index.js +7 -5
- package/src/api/api-loader.js +12 -95
- package/src/api/define-api.js +1 -0
- package/src/app-context.js +41 -5
- package/src/client-runtime/constants.js +10 -0
- package/src/client-runtime/mount.js +2 -3
- package/src/dev/banner.js +6 -2
- package/src/dev/client-gen.js +458 -0
- package/src/discovery/scan-routes.js +5 -2
- package/src/file-router.js +3 -3
- package/src/helpers.js +212 -24
- package/src/modules/module-discovery.js +1 -9
- package/src/pages/page-loader.js +13 -154
- package/src/plugin-manager.js +99 -18
- package/src/server.js +335 -133
- package/src/services/discovery.js +19 -40
- package/src/services/executor.js +95 -25
- package/src/services/memoize.js +3 -25
- package/src/services/registry.js +15 -1
- package/src/services/validator.js +38 -20
- package/src/template/precompile.js +8 -19
package/.agents/AGENTS.md
CHANGED
|
@@ -18,6 +18,13 @@ When tasked with a feature or bugfix, **immediately consult the corresponding to
|
|
|
18
18
|
| **Authentication (Session / JWT / Guard)** | [`.agents/AUTH.md`](AUTH.md) | `core/auth/` |
|
|
19
19
|
| **Background Jobs & Worker Queue** | [`.agents/QUEUE.md`](QUEUE.md) | `jobs/` |
|
|
20
20
|
| **Decoupled Events & Signals** | [`.agents/EVENTS.md`](EVENTS.md) | `core/events/`, `listeners/` |
|
|
21
|
+
| **Fault Tolerance / Circuit Breaker / Retry** | [`.agents/RESILIENCE.md`](RESILIENCE.md) | `core/resilience/` |
|
|
22
|
+
| **Stateless Scale-Out (Redis Sessions & DB Pool)** | [`.agents/SCALE_OUT.md`](SCALE_OUT.md) | `core/auth/redis-session.js`, `core/orm/pool.js` |
|
|
23
|
+
| **Cloud Secrets (GCP & AWS Secret Manager)** | [`.agents/SECRETS.md`](SECRETS.md) | `core/secrets/`, `bin/commands/secrets-pull.js` |
|
|
24
|
+
| **Cloud Metrics & Distributed Tracing** | [`.agents/METRICS.md`](METRICS.md) | `core/metrics/`, `/metrics` |
|
|
25
|
+
| **Cloud Migration Jobs (Zero-Downtime DB Deploy)** | [`.agents/MIGRATION_JOBS.md`](MIGRATION_JOBS.md) | `bin/commands/add-migration-job.js`, `core/orm/migrate-cloud.js` |
|
|
26
|
+
| **Rate Limiting Engine (Zero-Dependency & Redis)** | [`.agents/RATE_LIMIT.md`](RATE_LIMIT.md) | `core/rate-limit/` |
|
|
27
|
+
| **Feature Flags & Canary Splitter (`core/flags`)** | [`.agents/FLAGS.md`](FLAGS.md) | `core/flags/` |
|
|
21
28
|
| **API Signatures & Types Verification** | [`index.d.ts`](../index.d.ts) | **Canonical Ground Truth** |
|
|
22
29
|
|
|
23
30
|
---
|
|
@@ -49,13 +56,25 @@ This `.agents/` customization root is organized into modular topic guides:
|
|
|
49
56
|
10. **[Realtime Layer & Adapters](.agents/REALTIME.md)** — Framework-agnostic realtime layer (`core/realtime`), generic WebSocket, SSE, and Socket.IO adapters, subscription identity, backoff reconnect, and auth lifecycle.
|
|
50
57
|
11. **[Email Plugin Guide](.agents/EMAIL.md)** — MJML template compilation, Nodemailer transport, DB delivery logs, Auth Email bridge, and Admin UI.
|
|
51
58
|
12. **[Admin Panel Customization](.agents/ADMIN.md)** — Extending Mithril.js Admin Panel SPA (Custom pages `component.js`, custom field renderers, widgets, single & bulk actions).
|
|
52
|
-
13. **[CLI Tooling & Commands](CLI.md)** — `webspresso dev`, `build`, `doctor`, `db:migrate`, `db:seed`, `polar:migrate`, `favicon:generate`, `add:tailwind`, `add:docker`, `deploy:check`, `agents:init`.
|
|
59
|
+
13. **[CLI Tooling & Commands](CLI.md)** — `webspresso dev`, `build`, `doctor`, `db:migrate`, `db:seed`, `polar:migrate`, `favicon:generate`, `add:tailwind`, `add:docker`, `add:cloudrun`, `add:aws`, `add:cloudflare`, `deploy:check`, `agents:init`.
|
|
53
60
|
14. **[Development & Testing Workflow](.agents/WORKFLOW.md)** — CLI commands, Vitest unit/integration testing, Playwright E2E tests, TypeScript type checking, and zero regression policy.
|
|
54
61
|
15. **[Coding Standards & Conventions](.agents/CONVENTIONS.md)** — Zero external dependencies policy, strict function signature & schema verification, clean component separation, and log traceback inspection rules.
|
|
55
|
-
16. **[Background Job Queue](.agents/QUEUE.md)** — In-Memory, Knex Database,
|
|
62
|
+
16. **[Background Job Queue](.agents/QUEUE.md)** — In-Memory, Knex Database, Distributed Redis, AWS SQS, and Google Cloud Pub/Sub queue adapters, job auto-discovery (`jobs/`), retries, and graceful draining.
|
|
56
63
|
17. **[SSR Streaming & Chunked Transfer](.agents/STREAMING.md)** — Native HTTP chunked streaming (`res.renderStream()`), deferred data loader slots (`defer: { key: promise }`), and TTFB optimization.
|
|
57
64
|
18. **Polar billing production checklist** — [docs/guides/polar-production-checklist.md](../docs/guides/polar-production-checklist.md) (env, webhooks, rate limits, external tier hooks, CSP). Plugin reference: [PLUGINS.md § polarPlugin](PLUGINS.md).
|
|
58
65
|
19. **[Decoupled Events & Signals Architecture](.agents/EVENTS.md)** — Zero-dependency enterprise event dispatcher (`core/events`), sync/async/parallel/serial/waterfall dispatch, wildcard listeners (`order.*`), Django-style `Signal` and sender filtering, queue bridging, and listener auto-discovery.
|
|
66
|
+
20. **[HTTP 103 Early Hints](.agents/EARLY_HINTS.md)** — Zero-dependency RFC 8288 / RFC 8297 Early Hints dispatcher (`core/early-hints`), preloading route CSS/JS and fonts before SSR loader execution, `createApp({ earlyHints })`, and `res.earlyHints(links)` / `ctx.earlyHints(links)` helpers.
|
|
67
|
+
21. **[Payload Limits & DoS Protection](.agents/LIMITS.md)** — Zero-dependency request body limits and DoS protection (`core/limits`), `createApp({ limits })`, automatic `PayloadTooLargeError` (HTTP 413) mapping, route overrides (`limits.routes`), streaming bypass, and native HMAC webhook `req.rawBody` capture.
|
|
68
|
+
22. **[Cloud & Kubernetes Health Probes](.agents/HEALTH.md)** — Zero-dependency RFC-compliant liveness (`/healthz`), readiness (`/readyz`), and combined diagnostic (`/health`) probes (`core/health`), event loop lag telemetry, database/queue health monitors, automatic HTTP 503 draining on graceful shutdown, and `createApp({ healthCheck: true })`.
|
|
69
|
+
23. **[LRU & Tagged Cache Engine](.agents/CACHE.md)** — Zero-dependency, memory-bounded in-memory LRU cache (`core/cache`), byte budget constraints (`maxBytes` / `maxMemoryMb`), TTL expiration, stampede protection (`getOrSet`), leak-free tag invalidation (`TaggedLruCache`), ORM query cache provider, and `createApp({ cache })`.
|
|
70
|
+
24. **[Enterprise Resilience & Circuit Breaker](.agents/RESILIENCE.md)** — Zero-dependency fault tolerance engine (`core/resilience`), three-state `CircuitBreaker` (`CLOSED`, `OPEN`, `HALF_OPEN`), rolling window failure rate, per-call execution timeout, fallback handlers, and exponential backoff retry engine (`retry`, `withRetry`) with randomized jitter and transient error detection.
|
|
71
|
+
25. **[Structured Cloud Logging & Distributed Tracing](.agents/LOGGING.md)** — Zero-dependency cloud logger (`core/logger`), GCP Cloud Logging, AWS CloudWatch, automatic trace propagation (`x-cloud-trace-context`, `x-amzn-trace-id`, `traceparent`), sensitive key redaction, and `req.logger` child context.
|
|
72
|
+
26. **[Stateless Scale-Out & Database Pool Management](.agents/SCALE_OUT.md)** — Distributed Redis session store (`createRedisSessionStore`), Redis session tracker (`createRedisSessionTracker`), zero-dependency RESP client, serverless DB connection pool optimizer (`normalizeServerlessPoolConfig`), and scale-out preflight audits (`deploy:check`).
|
|
73
|
+
27. **[Cloud Secrets Management](.agents/SECRETS.md)** — Zero-dependency Google Cloud Secret Manager & AWS Secrets Manager/SSM integration (`core/secrets`), in-memory caching with TTL, dot-notation JSON subkeys, process.env hydration, and `webspresso secrets:pull`.
|
|
74
|
+
28. **[Cloud Metrics & Distributed Tracing](.agents/METRICS.md)** — Zero-dependency Prometheus exposition format (`/metrics`), JSON telemetry (`/metrics.json`), HTTP latency histograms, Node.js event loop/memory/pool/cache collectors, and W3C `traceparent` & `x-trace-id` propagation (`core/metrics`).
|
|
75
|
+
29. **[Cloud Migration Jobs & Zero-Downtime Database Deploy](.agents/MIGRATION_JOBS.md)** — Dedicated pre-deploy migration jobs for Cloud Run, AWS ECS, and Kubernetes (`webspresso add:migration-job`), connection retries, and stale lock auto-healing (`webspresso db:migrate --safe`).
|
|
76
|
+
30. **[Native Zero-Dependency Rate Limiting Engine](.agents/RATE_LIMIT.md)** — Framework-agnostic rate limiter (`core/rate-limit`), sliding window in-memory & Redis stores, RFC 6585 standard headers (`RateLimit-*`, `Retry-After`), Express & Hono dual support, and `rateLimit({ window, limit })`.
|
|
77
|
+
31. **[Feature Flags & Canary Traffic Splitter](.agents/FLAGS.md)** — Zero-dependency feature flag and canary rollout engine (`core/flags`), deterministic FNV-1a bucketing, targeting rules (users, roles, email domains), A/B variants, SSR template helpers (`fsy.hasFeature`), and declarative API guards (`defineApi({ flag })`).
|
|
59
78
|
|
|
60
79
|
---
|
|
61
80
|
|
package/.agents/ARCHITECTURE.md
CHANGED
|
@@ -51,6 +51,29 @@
|
|
|
51
51
|
- **HTTP Response Compression (`core/compression`)**:
|
|
52
52
|
- Zero-dependency streaming zlib compression configured via `createApp({ server: { compression: true } })`.
|
|
53
53
|
- Content negotiation for Brotli (`br`), Gzip (`gzip`), Deflate (`deflate`), threshold filtering (1 KB), and `res.compress(false)` route opt-out.
|
|
54
|
+
- **Configurable Payload Size Limits & DoS Protection (`core/limits`)**:
|
|
55
|
+
- Zero-dependency request body limits configured via `createApp({ limits: { json: '1mb', urlencoded: '1mb', raw: false, text: false, parameterLimit: 1000 } })` or shorthand string/number (`limits: '5mb'`). Also accepted under `createApp({ server: { limits } })`.
|
|
56
|
+
- **HTTP 413 & 400 Error Mapping**: Payload limit violations and excessive form parameters automatically produce `PayloadTooLargeError` (HTTP 413) with `{ limit, length, expected }` metadata; malformed JSON bodies produce `BadRequestError` (HTTP 400) with `INVALID_JSON_PAYLOAD`.
|
|
57
|
+
- **Raw Body Capture for Webhooks**: `captureRawBody: true | string[] | Function` captures incoming request payload `Buffer` on `req.rawBody` for zero-overhead HMAC cryptographic verification (Polar, Stripe, GitHub).
|
|
58
|
+
- **Route Overrides & Exclusions**: `limits.routes` supports per-route limit adjustments (e.g. `routes: { '/api/upload': { json: '25mb' } }`), while `limits.exclude` completely bypasses body parsing for raw socket/streaming endpoints.
|
|
59
|
+
- **Cloud & Kubernetes Health Probes (`core/health`, `/healthz`, `/readyz`, `/health`)**:
|
|
60
|
+
- RFC-compliant cloud-native endpoints enabled via `createApp({ healthCheck: true })` or fine-grained `{ path: '/healthz', readyPath: '/readyz', combinedPath: '/health', db: true, queue: true, eventLoopLag: true }`.
|
|
61
|
+
- **Liveness Probe (`/healthz`)**: Non-blocking probe reporting basic process health, memory usage (`rss`, `heapUsed`, `heapTotal`, `external`), and system uptime.
|
|
62
|
+
- **Readiness Probe (`/readyz`)**: Deep dependency inspection checking database ping (`knex.raw('SELECT 1')`), worker queue status, custom user checks, and `ShutdownManager` draining state (immediately returning HTTP 503 so upstream load balancers detach the instance).
|
|
63
|
+
- **Diagnostic Health (`/health`)**: Full operational dashboard with event loop lag percentiles (`perf_hooks.monitorEventLoopDelay`), dependency breakdown, and latency metrics.
|
|
64
|
+
- **In-Memory LRU & Tagged Cache Engine (`core/cache`)**:
|
|
65
|
+
- Zero-dependency O(1) Least-Recently-Used caching engine configured via `createApp({ cache: { maxEntries, maxMemoryMb, defaultTtl } })` or `cache: false`.
|
|
66
|
+
- **Memory Budget & Leak Prevention**: Enforces byte boundaries (`maxBytes` / `maxMemoryMb`) via `approximateByteSize` to prevent process OOM errors, combined with passive and active TTL pruning (`pruneExpired()`).
|
|
67
|
+
- **Bidirectional Tag Invalidation (`TaggedLruCache`)**: Supports model and query tagging (`invalidateTag`, `invalidateTags`). When items are evicted via LRU, all associated tag sets are automatically and symmetrically cleaned up, eliminating dangling Set memory leaks.
|
|
68
|
+
- **Stampede / Thundering Herd Protection**: `getOrSet(key, asyncFactory, options)` deduplicates concurrent in-flight requests for cold keys so expensive factories execute only once.
|
|
69
|
+
- **Framework Integration**: Directly powers `core/orm/cache/memory-provider.js` (ORM query caching) and `core/schema-cache.js` (Zod schema cache), and is automatically exposed on `req.cache`, `req.context.cache`, and `app.cache`.
|
|
70
|
+
- **Enterprise Resilience, Circuit Breaker & Retry Engine (`core/resilience`)**:
|
|
71
|
+
- Zero-dependency fault tolerance and cascading failure prevention system built natively on `events` and `perf_hooks`.
|
|
72
|
+
- **Three-State Circuit Breaker (`CircuitBreaker`)**: Standard `CLOSED`, `OPEN`, and `HALF_OPEN` states. Trips to `OPEN` when consecutive failures reach `failureThreshold` or failure rate percentage exceeds `failureRateThreshold` in a rolling sample window (`rollingWindow`).
|
|
73
|
+
- **Fail-Fast & Graceful Fallbacks**: Fast-fails calls with `CircuitBreakerOpenError` (HTTP 503) without executing downstream code when open, or seamlessly executes fallback handlers (`fallback: (err, ...args) => ...`).
|
|
74
|
+
- **Trial Recovery Probing**: Automatically transitions to `HALF_OPEN` after `resetTimeout` and tests downstream health using trial probes (`successThreshold`).
|
|
75
|
+
- **Exponential Backoff Retry with Full Jitter (`retry`, `withRetry`)**: Automatically retries transient network errors (`ECONNRESET`, `ETIMEDOUT`, 429 Too Many Requests, and 5xx errors) with randomized full jitter to prevent thundering herd spikes while avoiding retrying 4xx client errors.
|
|
76
|
+
- **Services Layer Integration**: Declarative `defineService({ circuitBreaker, retry })` seamlessly wraps service execution. Also accessible on `app.breakers`, `app.getBreaker()`, `req.breaker()`, `req.retry()`, `ctx.breaker()`, and `ctx.retry()`.
|
|
54
77
|
- **Custom Error & 404 Pages (`errorPages`)**:
|
|
55
78
|
- Configured via `createApp({ errorPages: { notFound, serverError, timeout } })`.
|
|
56
79
|
- **404 Not Found (`notFound`)**: Template path (`'404.njk'`) or handler `(req, res, ctx) => ...`.
|
package/.agents/CACHE.md
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# High-Performance In-Memory LRU & Tagged Cache Engine (`core/cache`)
|
|
2
|
+
|
|
3
|
+
Webspresso includes a zero-dependency, memory-bounded, leak-free in-memory cache engine featuring O(1) Least-Recently-Used (LRU) eviction, byte budget constraints (`maxBytes` / `maxMemoryMb`), TTL expiration, stampede protection (thundering herd prevention), and O(1) bidirectional tag-based invalidation.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🎯 Key Capabilities & Design Guarantees
|
|
8
|
+
|
|
9
|
+
1. **True O(1) LRU Eviction**: Built on V8's native insertion-order Map mechanics with zero extra memory allocation for linked-list node wrappers.
|
|
10
|
+
2. **Dual Capacity Boundaries**:
|
|
11
|
+
- **`maxEntries`**: Restricts the maximum number of items stored.
|
|
12
|
+
- **`maxBytes` / `maxMemoryMb`**: Enforces strict memory budgets using `approximateByteSize` to prevent process Out-Of-Memory (OOM) crashes under heavy or large payload loads.
|
|
13
|
+
3. **Symmetrical Tag Cleanup (Zero Leaks)**: When an item is evicted via LRU, expired via TTL, or deleted, all associated tag index sets are automatically pruned. Empty tag sets are deleted immediately, preventing the classic "dangling Set memory leak".
|
|
14
|
+
4. **Stampede / Thundering Herd Protection**: `getOrSet(key, asyncFactory)` coalesces concurrent requests for the same missing key, invoking the expensive calculation or DB query exactly once.
|
|
15
|
+
5. **Universal Integration**:
|
|
16
|
+
- **ORM Query Cache**: Powers `core/orm/cache/memory-provider.js` with true LRU and memory budgets.
|
|
17
|
+
- **Zod Schema Cache**: Powers `core/schema-cache.js` with bounded 2,000 schemas capacity.
|
|
18
|
+
- **Application & Context**: Automatically mounted on `app.cache`, `req.cache`, and `req.context.cache` unless `cache: false` is configured.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 🚀 Quick Usage
|
|
23
|
+
|
|
24
|
+
### 1. Standalone `LruCache`
|
|
25
|
+
```javascript
|
|
26
|
+
const { createLruCache } = require('webspresso');
|
|
27
|
+
|
|
28
|
+
const cache = createLruCache({
|
|
29
|
+
maxEntries: 1000,
|
|
30
|
+
maxMemoryMb: 50, // 50 MB byte budget
|
|
31
|
+
defaultTtl: '15m', // 15 minutes default TTL
|
|
32
|
+
clone: false, // Set true if cached objects must not be mutated
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
cache.set('user:42', { name: 'Alice', role: 'admin' });
|
|
36
|
+
|
|
37
|
+
const user = cache.get('user:42'); // Refreshes LRU position
|
|
38
|
+
const peekUser = cache.peek('user:42'); // Reads without refreshing LRU position
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 2. Tagged Invalidation (`TaggedLruCache`)
|
|
42
|
+
```javascript
|
|
43
|
+
const { createTaggedLruCache } = require('webspresso');
|
|
44
|
+
|
|
45
|
+
const cache = createTaggedLruCache({
|
|
46
|
+
maxEntries: 5000,
|
|
47
|
+
maxMemoryMb: 100,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Tag items by model and primary key
|
|
51
|
+
cache.set('query:users:active', usersList, { tags: ['model:User', 'q:active'] });
|
|
52
|
+
cache.set('user:1:profile', userProfile, { tags: ['model:User', 'pk:1'] });
|
|
53
|
+
|
|
54
|
+
// Invalidate single primary key
|
|
55
|
+
cache.invalidateTag('pk:1');
|
|
56
|
+
|
|
57
|
+
// Invalidate all queries related to the User model
|
|
58
|
+
cache.invalidateTags(['model:User']);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 3. Stampede / Thundering Herd Protection (`getOrSet`)
|
|
62
|
+
```javascript
|
|
63
|
+
// 50 concurrent requests for 'expensive:report' will execute the factory only once:
|
|
64
|
+
const report = await cache.getOrSet('expensive:report', async (key) => {
|
|
65
|
+
return await generateHeavyReport();
|
|
66
|
+
}, { ttl: '1h' });
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## ⚙️ Application Configuration (`createApp`)
|
|
72
|
+
|
|
73
|
+
Configure the process-wide cache directly when bootstrapping Webspresso:
|
|
74
|
+
|
|
75
|
+
```javascript
|
|
76
|
+
const { createApp } = require('webspresso');
|
|
77
|
+
|
|
78
|
+
const app = createApp({
|
|
79
|
+
pagesDir: './pages',
|
|
80
|
+
cache: {
|
|
81
|
+
maxEntries: 5000,
|
|
82
|
+
maxMemoryMb: 64, // 64 MB budget
|
|
83
|
+
defaultTtl: '10m',
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
To disable the app cache completely:
|
|
89
|
+
```javascript
|
|
90
|
+
const app = createApp({
|
|
91
|
+
pagesDir: './pages',
|
|
92
|
+
cache: false,
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 🌐 Context & Route Usage
|
|
99
|
+
|
|
100
|
+
Inside page loaders, services, or API route handlers:
|
|
101
|
+
|
|
102
|
+
```javascript
|
|
103
|
+
// In API routes (pages/api/stats.get.js)
|
|
104
|
+
module.exports = defineApi({
|
|
105
|
+
handler: async (req, res) => {
|
|
106
|
+
const stats = await req.cache.getOrSet('site:stats', async () => {
|
|
107
|
+
return await req.db.getRepository('Order').getSummaryStats();
|
|
108
|
+
}, { ttl: '5m', tags: ['stats', 'model:Order'] });
|
|
109
|
+
|
|
110
|
+
return res.json(stats);
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
```javascript
|
|
116
|
+
// From any background job or script using app-context
|
|
117
|
+
const { getCache } = require('webspresso');
|
|
118
|
+
|
|
119
|
+
const cache = getCache();
|
|
120
|
+
if (cache) {
|
|
121
|
+
cache.invalidateTag('stats');
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 📊 Telemetry & Observability Metrics
|
|
128
|
+
|
|
129
|
+
Access real-time cache performance and memory metrics:
|
|
130
|
+
|
|
131
|
+
```javascript
|
|
132
|
+
const stats = app.cache.getStats();
|
|
133
|
+
console.log(stats);
|
|
134
|
+
// {
|
|
135
|
+
// entries: 42,
|
|
136
|
+
// tags: 5,
|
|
137
|
+
// currentBytes: 124850,
|
|
138
|
+
// maxBytes: 67108864,
|
|
139
|
+
// maxEntries: 5000,
|
|
140
|
+
// hits: 1540,
|
|
141
|
+
// misses: 23,
|
|
142
|
+
// hitRate: 0.985,
|
|
143
|
+
// sets: 65,
|
|
144
|
+
// evictions: 0,
|
|
145
|
+
// expirations: 12
|
|
146
|
+
// }
|
|
147
|
+
```
|
package/.agents/CLI.md
CHANGED
|
@@ -313,7 +313,7 @@ Generate production-ready, security-hardened, multi-stage `Dockerfile`, `.docker
|
|
|
313
313
|
npx webspresso add:docker
|
|
314
314
|
|
|
315
315
|
# Customize Node.js version, database service, or container port
|
|
316
|
-
npx webspresso add:docker --node 22-alpine --db postgres --redis --port
|
|
316
|
+
npx webspresso add:docker --node 22-alpine --db postgres --redis --port 7331
|
|
317
317
|
|
|
318
318
|
# Overwrite existing files
|
|
319
319
|
npx webspresso add:docker --force
|
|
@@ -332,12 +332,17 @@ npx webspresso add:docker --force
|
|
|
332
332
|
|
|
333
333
|
## 17. Production Deployment Preflight Check (`deploy:check` / `check:deploy`)
|
|
334
334
|
|
|
335
|
-
Run comprehensive pre-flight verification before deploying to Fly.io, Railway, Render, VPS, or Kubernetes:
|
|
335
|
+
Run comprehensive pre-flight verification before deploying to Google Cloud Run, AWS (App Runner / ECS), Cloudflare Workers, Fly.io, Railway, Render, VPS, or Kubernetes:
|
|
336
336
|
|
|
337
337
|
```bash
|
|
338
|
-
# Run production preflight verification
|
|
338
|
+
# Run production preflight verification (auto-detects target platform)
|
|
339
339
|
npx webspresso deploy:check
|
|
340
340
|
|
|
341
|
+
# Target a specific cloud platform explicitly (cloudrun, aws, cloudflare, docker)
|
|
342
|
+
npx webspresso deploy:check --platform cloudrun
|
|
343
|
+
npx webspresso deploy:check --platform aws
|
|
344
|
+
npx webspresso deploy:check -p cloudflare
|
|
345
|
+
|
|
341
346
|
# Run against a specific environment (.env.staging or .env.production)
|
|
342
347
|
npx webspresso deploy:check --env staging
|
|
343
348
|
|
|
@@ -349,11 +354,17 @@ npx webspresso deploy:check --json
|
|
|
349
354
|
```
|
|
350
355
|
|
|
351
356
|
### Audited Verification Areas:
|
|
352
|
-
1. **
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
+
1. **Platform-Specific Cloud Preflight**:
|
|
358
|
+
- **Google Cloud Run**: Ephemeral SQLite/local upload warnings, SIGTERM timeout alignment (<= 10000ms), `.gcloudignore` secrets exclusion (`.env`), `cloudbuild.yaml` pipeline, and dynamic `PORT` binding.
|
|
359
|
+
- **AWS (App Runner / ECS Fargate)**: Ephemeral storage audits, `apprunner.yaml` / `ecs-task-definition.json` validity, and CloudWatch `awslogs` log driver configuration.
|
|
360
|
+
- **Cloudflare Workers**: `wrangler.toml` configuration and `nodejs_compat` compatibility flag verification.
|
|
361
|
+
- **Stateless Scale-Out**: Distributed Redis sessions and serverless connection pool limits.
|
|
362
|
+
2. **Secrets & Cryptography**: Ensures `SESSION_SECRET` or `APP_KEY` is set, >= 32 characters, and not using weak placeholder defaults.
|
|
363
|
+
3. **Git & Leak Prevention**: Verifies `.env` and local database files are excluded in `.gitignore`.
|
|
364
|
+
4. **Container Hardening**: Ensures `Dockerfile` runs as a non-root `USER`, configures a `HEALTHCHECK`, and uses multi-stage caching.
|
|
365
|
+
5. **Database & Migrations**: Audits for pending unapplied migrations and warns against ephemeral SQLite storage.
|
|
366
|
+
6. **Server Optimizations**: Validates HTTP compression (`compression: true`), graceful shutdown, and health check endpoints.
|
|
367
|
+
7. **Actionable Remediations**: Emits precise, single-command remediation steps for every warning and error detected.
|
|
357
368
|
|
|
358
369
|
---
|
|
359
370
|
|
|
@@ -435,3 +446,204 @@ npx webspresso make:mail Welcome
|
|
|
435
446
|
# Outputs: emails/WelcomeEmail.js
|
|
436
447
|
```
|
|
437
448
|
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
## 21. Google Cloud Run Deployment (`add:cloudrun` / `cloudrun`)
|
|
452
|
+
|
|
453
|
+
Generate production-ready Google Cloud Run configuration with Google Cloud Build CI/CD pipeline, `.gcloudignore`, and one-command deployment script:
|
|
454
|
+
|
|
455
|
+
```bash
|
|
456
|
+
# Generate cloudbuild.yaml, .gcloudignore, deploy-cloudrun.sh, and Dockerfile
|
|
457
|
+
npx webspresso add:cloudrun
|
|
458
|
+
|
|
459
|
+
# Customize region, container resources, scaling limits, and Cloud SQL
|
|
460
|
+
npx webspresso add:cloudrun --region europe-west1 --memory 1Gi --cpu 2 --min-instances 1 --max-instances 20 --cloud-sql my-project:europe-west1:my-db
|
|
461
|
+
|
|
462
|
+
# Overwrite existing files
|
|
463
|
+
npx webspresso add:cloudrun --force
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
### Generated Artifacts:
|
|
467
|
+
- **`cloudbuild.yaml`**: Multi-stage Docker image build, Google Artifact Registry push, and zero-downtime serverless Cloud Run deployment with Gen2 execution environment.
|
|
468
|
+
- **`.gcloudignore`**: Prevents `.env`, SQLite files, node_modules, and test directories from entering the Cloud Build upload context.
|
|
469
|
+
- **`deploy-cloudrun.sh`**: Executable bash script for direct zero-friction deployment (`chmod +x`).
|
|
470
|
+
- **`package.json` Scripts**: Adds `gcp:deploy` and `gcp:build`.
|
|
471
|
+
|
|
472
|
+
---
|
|
473
|
+
|
|
474
|
+
## 22. AWS App Runner & ECS Fargate Deployment (`add:aws` / `aws`)
|
|
475
|
+
|
|
476
|
+
Generate production-ready AWS deployment configuration supporting both AWS App Runner and Amazon ECS (Fargate):
|
|
477
|
+
|
|
478
|
+
```bash
|
|
479
|
+
# Generate apprunner.yaml, ecs-task-definition.json, deploy-aws.sh, and Dockerfile
|
|
480
|
+
npx webspresso add:aws
|
|
481
|
+
|
|
482
|
+
# Customize region, CPU, and memory allocations
|
|
483
|
+
npx webspresso add:aws --region us-east-1 --cpu "1 vCPU" --memory "2 GB"
|
|
484
|
+
|
|
485
|
+
# Overwrite existing files
|
|
486
|
+
npx webspresso add:aws --force
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### Generated Artifacts:
|
|
490
|
+
- **`apprunner.yaml`**: AWS App Runner configuration with build commands (`npm ci --omit=dev`), start command, and port network mapping.
|
|
491
|
+
- **`ecs-task-definition.json`**: Production ECS Fargate task definition with `awsvpc` network mode, container resource constraints, CloudWatch `awslogs`, and native `/healthz` health checks.
|
|
492
|
+
- **`deploy-aws.sh`**: Automated deployment shell script that verifies AWS credentials, creates Amazon ECR repositories, builds and pushes Docker images, and updates services.
|
|
493
|
+
- **`package.json` Scripts**: Adds `aws:deploy`.
|
|
494
|
+
|
|
495
|
+
---
|
|
496
|
+
|
|
497
|
+
## 23. Cloudflare Workers Deployment (`add:cloudflare` / `cloudflare`)
|
|
498
|
+
|
|
499
|
+
Generate serverless edge deployment files for Cloudflare Workers with D1, KV, and Queues support:
|
|
500
|
+
|
|
501
|
+
```bash
|
|
502
|
+
# Generate wrangler.toml and worker.js
|
|
503
|
+
npx webspresso add:cloudflare
|
|
504
|
+
|
|
505
|
+
# Include Cloudflare D1, KV, and Queues
|
|
506
|
+
npx webspresso add:cloudflare --d1 --kv --queue
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
---
|
|
510
|
+
|
|
511
|
+
## 24. Cloud Static Asset Sync (`assets:sync` / `assets-sync`)
|
|
512
|
+
|
|
513
|
+
Upload and synchronize compiled static assets (`public/assets/`, `dist/`, fonts, images) to S3, Cloudflare R2, or Google Cloud Storage with immutable CDN cache headers:
|
|
514
|
+
|
|
515
|
+
```bash
|
|
516
|
+
# Preview files to be uploaded without transmitting data
|
|
517
|
+
npx webspresso assets:sync --dry-run
|
|
518
|
+
|
|
519
|
+
# Sync assets to an AWS S3 bucket
|
|
520
|
+
npx webspresso assets:sync --bucket my-cdn-bucket --provider s3
|
|
521
|
+
|
|
522
|
+
# Sync assets to Google Cloud Storage
|
|
523
|
+
npx webspresso assets:sync --bucket my-gcs-bucket --provider gcs --prefix assets
|
|
524
|
+
|
|
525
|
+
# Override directory or custom Cache-Control header
|
|
526
|
+
npx webspresso assets:sync --dir public --cache-control "public, max-age=604800"
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
---
|
|
530
|
+
|
|
531
|
+
## 25. Cloud Secrets Synchronization (`secrets:pull` / `pull:secrets`)
|
|
532
|
+
|
|
533
|
+
Pull cloud secrets from Google Cloud Secret Manager or AWS Secrets Manager into a local `.env.local` file for secure local development:
|
|
534
|
+
|
|
535
|
+
```bash
|
|
536
|
+
# Auto-detect cloud platform and pull expected secrets
|
|
537
|
+
npx webspresso secrets:pull
|
|
538
|
+
|
|
539
|
+
# Explicitly pull specific secrets from Google Cloud Secret Manager
|
|
540
|
+
npx webspresso secrets:pull --platform cloudrun -s SESSION_SECRET DATABASE_URL
|
|
541
|
+
|
|
542
|
+
# Explicitly pull from AWS Secrets Manager
|
|
543
|
+
npx webspresso secrets:pull --platform aws -s SESSION_SECRET DATABASE_URL
|
|
544
|
+
|
|
545
|
+
# Unpack a JSON secret bundle to stdout (dry run)
|
|
546
|
+
npx webspresso secrets:pull --bundle prod/app/config --dry-run
|
|
547
|
+
|
|
548
|
+
# Output secrets in JSON format
|
|
549
|
+
npx webspresso secrets:pull -s API_KEY DB_PASS --format json -o secrets.json
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
---
|
|
553
|
+
|
|
554
|
+
## 26. Zero-Secret CI/CD Pipeline Generator (`add:ci` / `add:workflow`)
|
|
555
|
+
|
|
556
|
+
Scaffold automated, keyless GitHub Actions workflows (Google WIF, AWS IAM OIDC, Cloudflare) and GitLab CI pipelines with integrated test suites and `webspresso deploy:check --strict` gating:
|
|
557
|
+
|
|
558
|
+
```bash
|
|
559
|
+
# Auto-detect cloud platform and scaffold GitHub Actions workflows
|
|
560
|
+
npx webspresso add:ci
|
|
561
|
+
|
|
562
|
+
# Explicitly target Google Cloud Run (Workload Identity Federation)
|
|
563
|
+
npx webspresso add:ci --platform cloudrun
|
|
564
|
+
|
|
565
|
+
# Explicitly target AWS (IAM OIDC Role & Amazon ECR)
|
|
566
|
+
npx webspresso add:ci --platform aws
|
|
567
|
+
|
|
568
|
+
# Explicitly target Cloudflare Workers
|
|
569
|
+
npx webspresso add:ci --platform cloudflare
|
|
570
|
+
|
|
571
|
+
# Scaffold all cloud workflows alongside a GitLab CI pipeline (.gitlab-ci.yml)
|
|
572
|
+
npx webspresso add:ci --platform all --gitlab
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
---
|
|
576
|
+
|
|
577
|
+
## 27. Type-Safe Frontend Client Generator (`client:generate` / `client:gen`)
|
|
578
|
+
|
|
579
|
+
Generate an end-to-end typed TypeScript HTTP client from your Webspresso API routes and Zod schemas for React, Next.js, Vite, Vue, Svelte, or mobile apps:
|
|
580
|
+
|
|
581
|
+
```bash
|
|
582
|
+
# Generate client into src/client.ts (or .webspresso/client.ts)
|
|
583
|
+
npx webspresso client:generate
|
|
584
|
+
|
|
585
|
+
# Specify custom output path and base URL
|
|
586
|
+
npx webspresso client:generate --out src/api-client.ts --base-url https://api.myapp.com
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
---
|
|
590
|
+
|
|
591
|
+
## 28. DB Studio Live Telemetry & SQL Runner (`db:studio`)
|
|
592
|
+
|
|
593
|
+
Launch an interactive database inspector, SQL query runner, and real-time system monitoring dashboard:
|
|
594
|
+
|
|
595
|
+
```bash
|
|
596
|
+
# Launch DB Studio on default port 4567
|
|
597
|
+
npx webspresso db:studio
|
|
598
|
+
|
|
599
|
+
# Custom port without opening default browser
|
|
600
|
+
npx webspresso db:studio --port 5000 --no-open
|
|
601
|
+
```
|
|
602
|
+
- Schema inspection & CRUD operations for all database tables.
|
|
603
|
+
- Real-time SSE Live Telemetry streaming Node.js memory metrics (RSS, Heap), Knex connection pool utilization, background queues, and circuit breaker trip states.
|
|
604
|
+
- Interactive Circuit Breaker manual reset (`POST /_studio/api/breakers/:name/reset`).
|
|
605
|
+
|
|
606
|
+
---
|
|
607
|
+
|
|
608
|
+
## 29. Interactive REPL Console (`console` / `c`)
|
|
609
|
+
|
|
610
|
+
Launch an interactive Node.js REPL session with auto-injected framework context (database, repositories, services, queues, events, feature flags, and cache):
|
|
611
|
+
|
|
612
|
+
```bash
|
|
613
|
+
# Start interactive console
|
|
614
|
+
npx webspresso console
|
|
615
|
+
# Alias:
|
|
616
|
+
npx webspresso c
|
|
617
|
+
|
|
618
|
+
# Evaluate a single expression and print output (with top-level await support)
|
|
619
|
+
npx webspresso console -e "await Note.find({ status: 'published' })"
|
|
620
|
+
|
|
621
|
+
# Target specific environment or config file
|
|
622
|
+
npx webspresso console -E production -c config/db.js
|
|
623
|
+
|
|
624
|
+
# Disable command history persistence or banner
|
|
625
|
+
npx webspresso console --no-history --no-banner
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
### Context & Shortcuts Injected:
|
|
629
|
+
- `db`: Knex / ORM database instance.
|
|
630
|
+
- `<ModelName>` (e.g. `Note`, `User`): Direct repository shortcuts (`await Note.find()`, `await Note.findById(1)`).
|
|
631
|
+
- `models`: Dictionary of all loaded model repositories (`models.Note`).
|
|
632
|
+
- `services`: ServiceRegistry instance.
|
|
633
|
+
- `service(name, input)`: Direct helper to invoke domain services (`await service('notes.create', payload)`).
|
|
634
|
+
- `queue`: Background QueueDispatcher (`await queue.dispatch('email.send', data)`).
|
|
635
|
+
- `events`: Decoupled EventDispatcher (`events.emit('order.created', order)`).
|
|
636
|
+
- `flags`: FeatureFlagManager (`flags.isEnabled('new_checkout', { user })`).
|
|
637
|
+
- `cache`: TaggedLruCache instance (`await cache.get('key')`).
|
|
638
|
+
- `mailer`: Framework mailer service.
|
|
639
|
+
- `reload()`: Hot-reloads all models and services from filesystem without exiting the REPL.
|
|
640
|
+
- `help()`: Displays interactive help menu with all available objects and commands.
|
|
641
|
+
|
|
642
|
+
### Custom REPL Dot-Commands:
|
|
643
|
+
- `.models`: List all loaded models, table names, and available repository methods.
|
|
644
|
+
- `.services`: List all registered business services and descriptions.
|
|
645
|
+
- `.routes`: Scan and list all API endpoints and SSR pages.
|
|
646
|
+
- `.flags`: List active feature flags and targeting rules.
|
|
647
|
+
- `.reload`: Hot-reload models and services from filesystem.
|
|
648
|
+
- `.exit`: Exit the console session (`Ctrl+D`).
|
|
649
|
+
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# HTTP 103 Early Hints & Critical Asset Preloading
|
|
2
|
+
|
|
3
|
+
Webspresso features built-in, zero-dependency support for **HTTP 103 Early Hints** (RFC 8288 / RFC 8297).
|
|
4
|
+
Early Hints allow Webspresso to send informational HTTP headers (containing CSS, JavaScript, and font preload instructions) to the client **before** server-side rendering (`load()`, database queries, external API calls) finishes, allowing the browser to download critical page assets in parallel.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 🚀 How It Works
|
|
9
|
+
|
|
10
|
+
1. The client sends an HTTP request (`GET /products/123`).
|
|
11
|
+
2. Webspresso resolves the matching route and its companion CSS/JS asset candidates via `AssetManager`.
|
|
12
|
+
3. If Early Hints are enabled, Webspresso immediately writes an `HTTP/1.1 103 Early Hints` response with `Link: </css/products.css>; rel=preload; as=style, </js/products.js>; rel=preload; as=script`.
|
|
13
|
+
4. While the browser starts downloading stylesheets and scripts, Webspresso runs the page's async `load()` function and Nunjucks rendering.
|
|
14
|
+
5. Once the HTML is ready, Webspresso returns `HTTP/1.1 200 OK` with the final document.
|
|
15
|
+
6. The browser can immediately render without waiting for secondary asset network round-trips (reducing TTFB, FCP and LCP).
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 🛠️ Configuration
|
|
20
|
+
|
|
21
|
+
### Global Configuration (`createApp`)
|
|
22
|
+
|
|
23
|
+
Enable automatic route asset preloading globally:
|
|
24
|
+
|
|
25
|
+
```javascript
|
|
26
|
+
const { createApp } = require('webspresso');
|
|
27
|
+
|
|
28
|
+
const app = createApp({
|
|
29
|
+
earlyHints: true, // Automatically preloads route CSS & JS
|
|
30
|
+
// Or with custom default links:
|
|
31
|
+
// earlyHints: {
|
|
32
|
+
// auto: true,
|
|
33
|
+
// links: ['/css/global.css', '/fonts/inter.woff2'],
|
|
34
|
+
// }
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Route / Page Configuration (`definePage`)
|
|
39
|
+
|
|
40
|
+
Configure Early Hints per-page inside your page module:
|
|
41
|
+
|
|
42
|
+
```javascript
|
|
43
|
+
const { definePage } = require('webspresso');
|
|
44
|
+
|
|
45
|
+
module.exports = definePage({
|
|
46
|
+
// Preload route assets automatically
|
|
47
|
+
earlyHints: true,
|
|
48
|
+
|
|
49
|
+
// Or specify exact links:
|
|
50
|
+
// earlyHints: [
|
|
51
|
+
// '/css/special.css',
|
|
52
|
+
// { url: '/fonts/inter.woff2', as: 'font', crossOrigin: 'anonymous' }
|
|
53
|
+
// ],
|
|
54
|
+
|
|
55
|
+
load: async (ctx) => {
|
|
56
|
+
// You can also dispatch hints manually during load:
|
|
57
|
+
ctx.earlyHints(['/extra-chunk.js']);
|
|
58
|
+
|
|
59
|
+
const product = await ctx.db.getRepository('Product').findById(ctx.params.id);
|
|
60
|
+
return { product };
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### In Route Handlers and API Middleware
|
|
66
|
+
|
|
67
|
+
`res.earlyHints(links, [callback])` is attached to `res` on every request:
|
|
68
|
+
|
|
69
|
+
```javascript
|
|
70
|
+
app.get('/dashboard', (req, res) => {
|
|
71
|
+
// Send 103 Early Hints
|
|
72
|
+
res.earlyHints([
|
|
73
|
+
'/css/dashboard.css',
|
|
74
|
+
'/js/charts.js',
|
|
75
|
+
]);
|
|
76
|
+
|
|
77
|
+
// Run async queries...
|
|
78
|
+
setTimeout(() => {
|
|
79
|
+
res.send('<h1>Dashboard</h1>');
|
|
80
|
+
}, 200);
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## 📋 Link Options & Deduction
|
|
87
|
+
|
|
88
|
+
Webspresso automatically deduces `as` and `crossorigin` attributes based on URL file extensions:
|
|
89
|
+
|
|
90
|
+
| Extension | Inferred `as` | Browser CORS Requirement |
|
|
91
|
+
| :--- | :--- | :--- |
|
|
92
|
+
| `.css` | `style` | - |
|
|
93
|
+
| `.js`, `.mjs`, `.cjs` | `script` | - |
|
|
94
|
+
| `.woff2`, `.woff`, `.ttf` | `font` | Auto-adds `crossorigin` |
|
|
95
|
+
| `.png`, `.jpg`, `.webp`, `.svg` | `image` | - |
|
|
96
|
+
| `.json` | `fetch` | - |
|
|
97
|
+
|
|
98
|
+
You can also pass full descriptor objects:
|
|
99
|
+
|
|
100
|
+
```javascript
|
|
101
|
+
res.earlyHints([
|
|
102
|
+
{
|
|
103
|
+
url: '/fonts/inter.woff2',
|
|
104
|
+
as: 'font',
|
|
105
|
+
crossOrigin: 'anonymous',
|
|
106
|
+
fetchPriority: 'high',
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
url: 'https://cdn.example.com',
|
|
110
|
+
rel: 'preconnect',
|
|
111
|
+
},
|
|
112
|
+
]);
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## 🛡️ Resilience & Fallbacks
|
|
118
|
+
|
|
119
|
+
- If the client or proxy does not support HTTP 103, or if running in an environment without `res.writeEarlyHints` (HTTP/1.0, test mocks), `sendEarlyHints` returns `false` safely without throwing.
|
|
120
|
+
- Calling `earlyHints` after response headers have been sent (`res.headersSent === true`) is a safe no-op.
|