aris 1.4.2 → 1.5.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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +259 -0
  3. data/README.md +18 -0
  4. data/docs/ADAPTERS.md +478 -0
  5. data/docs/ARCHITECTURE.md +222 -0
  6. data/docs/CONTENT.md +967 -0
  7. data/docs/PERFORMANCE.md +492 -0
  8. data/docs/PLUGIN_DEVELOPMENT.md +688 -0
  9. data/docs/USAGE.md +4998 -0
  10. data/docs/plugins/API_KEY_AUTH.md +232 -0
  11. data/docs/plugins/BASIC_AUTH.md +582 -0
  12. data/docs/plugins/BEARER_AUTH.md +394 -0
  13. data/docs/plugins/CACHE.md +369 -0
  14. data/docs/plugins/COMPRESSION.md +216 -0
  15. data/docs/plugins/COOKIES.md +30 -0
  16. data/docs/plugins/CORS.md +283 -0
  17. data/docs/plugins/CSRF.md +751 -0
  18. data/docs/plugins/ETAG.md +308 -0
  19. data/docs/plugins/FORM_PARSER.md +193 -0
  20. data/docs/plugins/HEALTH_CHECK.md +469 -0
  21. data/docs/plugins/JSON.md +291 -0
  22. data/docs/plugins/MULTIPART.md +427 -0
  23. data/docs/plugins/RATE_LIMITER.md +368 -0
  24. data/docs/plugins/REQUEST_ID.md +369 -0
  25. data/docs/plugins/REQUEST_LOGGER.md +151 -0
  26. data/docs/plugins/SECURITY.md +193 -0
  27. data/docs/plugins/SESSION.md +98 -0
  28. data/lib/aris/adapters/rack/adapter.rb +17 -2
  29. data/lib/aris/adapters/rack/request.rb +29 -11
  30. data/lib/aris/plugins/basic_auth.rb +3 -1
  31. data/lib/aris/plugins/cookies.rb +4 -32
  32. data/lib/aris/plugins/cors.rb +8 -1
  33. data/lib/aris/plugins/csrf.rb +63 -22
  34. data/lib/aris/plugins/flash.rb +3 -1
  35. data/lib/aris/plugins/form_parser.rb +52 -31
  36. data/lib/aris/plugins/multipart.rb +34 -6
  37. data/lib/aris/plugins/request_logger.rb +8 -1
  38. data/lib/aris/plugins/security_headers.rb +8 -1
  39. data/lib/aris/plugins/session.rb +150 -99
  40. data/lib/aris/response_helpers.rb +41 -0
  41. data/lib/aris/router.rb +7 -0
  42. data/lib/aris/version.rb +2 -2
  43. metadata +31 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 522385f073c3f854d6c1c257177a18cb47584eccde6c78bbd2f8f15a2252ec6a
4
- data.tar.gz: 20d7625e69e21e364d790fa45393be6bce546783c061422d419e310c3d12dea1
3
+ metadata.gz: 177c81e9724b54870daf6b964a57dd9fd3266c7aba9a33e6e2ad86739a03abfa
4
+ data.tar.gz: f3cb1744bd6822871889d9e8e8d3b59c3e26dd02409bd9de5f6e8824cb4a6760
5
5
  SHA512:
6
- metadata.gz: 3dc13fa33795500031ecf33ce8d83d2edee2b39914f707d8275f4f8dbe827a8bebd022394d5471b0f46a00a1c17c3c67a23e6f85c42af1497e0db2ed9deb2bd6
7
- data.tar.gz: fbf7c8643a0b5a793ca5bb66ee0c3dc0ba1a2b2f83f09d393a9914e6b0a5bac262928273b1ff45c7270cf07ef455e5580d99b60ae7f875a55287654fd0042164
6
+ metadata.gz: ebd7ca4a073b9d073c192ce21bc84aaf831257968bb1f5f22c93a7eff45f6e57bc487944596aa7ad4881abe61a56db73b8fae4d5935455e102a4dce1804c0eab
7
+ data.tar.gz: 9ab6127bf992f2341bf827f063ad013795ecae774264207afdc3421d08c703daa56c644e1596dbd74d09dde18b78c0a6d61c4d6a38cf840fe43fb549dc4f9b89
data/CHANGELOG.md ADDED
@@ -0,0 +1,259 @@
1
+ # Changelog
2
+
3
+ ## [1.5.1] - 2026-09-13
4
+
5
+ Text is text. Suite: 426 tests / 1294 assertions, green.
6
+
7
+ ### 🐛 Fixed
8
+
9
+ * **Path params and multipart fields came out as raw bytes (ASCII-8BIT).** Servers hand `PATH_INFO` and the request body over as binary strings, and aris passed them straight through. That is invisible until something cares about encoding: the `sqlite3` gem binds a binary string as a BLOB, so `WHERE book = ?` with a route param never matched, and a form value saved through a multipart form landed in the database as a BLOB instead of TEXT. Route params (`params[:book]`) and multipart field values, names and filenames are now UTF-8 text (invalid bytes are scrubbed). File data stays binary. Urlencoded forms were already fine (Rack decodes them as UTF-8).
10
+
11
+ ## [1.5.0] - 2026-09-12
12
+
13
+ Sessions you can build a login on, and Rack 3 correct responses. Suite: 424 tests / 1289 assertions, green.
14
+
15
+ ### 🔒 Security
16
+
17
+ * **Sessions are encrypted and authenticated.** The session cookie is now an AES-256-GCM payload keyed from `Aris::Config.secret_key_base`. Before, it was Base64-encoded JSON: readable, and forgeable by anyone who could type `{"user_id":1}`. A tampered, forged, expired, or wrong-key cookie loads as an empty session. `expire_after` is enforced server-side. A missing or short secret raises a clear `ArgumentError`. **Any 1.4 session cookie is ignored.** See `docs/plugins/SESSION.md`.
18
+ * **CSRF tokens are session-backed.** The old plugin kept the token in `Thread.current` and compared it across requests, which is meaningless under a threaded server. Tokens now live in the session, are exposed as `request.csrf_token`, and are accepted from the `_csrf` form field or the `X-CSRF-Token` header, compared in constant time. Requires `use: [:session, :form_parser, :csrf]` in that order. See `docs/plugins/CSRF.md`.
19
+
20
+ ### 🐛 Fixed
21
+
22
+ * **Cookies were never read under the Rack adapter.** `Aris::Adapters::Rack::Request#cookies` looked at `env['rack.request.cookie_hash']`, which nothing populated, so sessions and flash could not persist in production. It now parses the `Cookie` header.
23
+ * **Several `Set-Cookie` values were comma-joined into one header**, which browsers cannot parse — setting a session and a flash in one response lost one of them. Cookies are emitted as a Rack 3 Array under `set-cookie`.
24
+ * **`FormParser.build` returned an instance that could not be called** (every request 500'd — 16 red tests since 1.4.2). Instances and the bare class both work now, on both adapters.
25
+ * **`Session.build` had the same problem**; instances work.
26
+ * `request.body` on the Rack adapter can be read more than once (memoized, input rewound).
27
+ * `:flash`, `:security_headers`, `:cors`, `:request_logger` are self-registered like every other plugin, so `use: [:flash]` works without a manual `register_plugin`. The three configurable ones run with defaults when used by symbol. (`BasicAuth` still needs `.build(username:, password:)`.)
28
+ * Tests that asserted a capitalized `Location` header against Rack-3 lowercase output fixed.
29
+
30
+ ### ✨ Added
31
+
32
+ * `response.set_cookie` / `response.delete_cookie` on every response (Mock and Rack), with `path`, `domain`, `max_age`, `expires`, `httponly`, `secure`, `same_site`. The `:cookies` plugin is now a no-op kept for compatibility. See `docs/plugins/COOKIES.md`.
33
+ * `request.form_params` and `request.params` (query + form) after `:form_parser`; `request.multipart_params`, `request.multipart_files`, `request.multipart_data` after `:multipart`, with fields merged into `request.params`.
34
+ * The Rack adapter normalizes every response header name to lowercase and merges duplicates, as Rack 3 requires. Plugins may keep setting `'Cache-Control'` etc.; the wire output is `cache-control`.
35
+
36
+ ### 🔧 Changed
37
+
38
+ * `request.cookies` is available on Rack requests without any plugin.
39
+ * Session data keys are always symbols.
40
+
41
+
42
+ ## [1.4.2] - 2026-01-22
43
+
44
+ ### 🐛 Fixed
45
+
46
+ * Fixed a bug where form_parser plugin failed to pass parameters to handlers
47
+
48
+ Parameters are reached as follows:
49
+
50
+ ```ruby
51
+ def self.send(req, res, params)
52
+ email = req.form_params['email']
53
+ ```
54
+
55
+ ## [1.4.0] - 2025-12-30
56
+ This release adds native static file serving with production-grade MIME type handling.
57
+
58
+ ### ✨ Added
59
+ * **Static File Serving:** Introduced `Aris::Config.serve_static` to serve static assets directly from the `public/` directory in development. Works seamlessly with nginx in production (nginx handles static files, Aris handles dynamic routes).
60
+ * **Configurable MIME Types:** Added `Aris::Config.mime_types` with sensible defaults for common file types (images, fonts, CSS, JS). Fully extensible for custom file formats.
61
+ * **Cache Headers:** Static files are served with `Cache-Control: public, max-age=31536000` for optimal browser caching.
62
+
63
+ ### 🔧 Changed
64
+ * Both `RackApp` and `MockAdapter` now check for static files before routing, improving performance for asset-heavy applications.
65
+
66
+ ### 📝 Usage
67
+ ```ruby
68
+ # Enable in development (disabled by default)
69
+ Aris.configure do |c|
70
+ c.serve_static = ENV['RACK_ENV'] != 'production'
71
+
72
+ # Optional: Add custom MIME types
73
+ c.mime_types = {
74
+ '.webm' => 'video/webm',
75
+ '.flac' => 'audio/flac'
76
+ }
77
+ end
78
+ ```
79
+
80
+ ## [1.3.0] - 2025-12-30
81
+
82
+ This release focuses on state management and fine-tuning URL strictness.
83
+
84
+ ### ✨ Added
85
+
86
+ * **Session & Flash Support:** Introduced `Aris::Plugins::Session` and `Aris::Plugins::Flash`. Supports persistence across redirects and "flash.now" for the current request cycle.
87
+ * **Trailing Slash Configuration:** Added `Aris::Config.trailing_slash`. You can now choose between `:strict` (default), `:ignore`, or `:redirect` (301/302) to normalize incoming paths.
88
+ * **Cookie Management:** Added `Aris::Plugins::Cookies` with a fluent helper API for reading, writing, and deleting cookies with secure defaults.
89
+
90
+ ### 🐛 Fixed
91
+
92
+ * Fixed a bug where the `MockAdapter` would not correctly pass the response object into handler blocks, causing issues with state-dependent plugins.
93
+
94
+ ---
95
+
96
+ ## [1.2.0] - 2025-12-15
97
+
98
+ Deep integration for internationalization and complex domain patterns.
99
+
100
+ ### ✨ Added
101
+
102
+ * **First-Class Locales:** Added `Aris::LocaleInjector`. Routes can now be expanded per-locale (e.g., `/en/about` and `/es/acerca` pointing to the same handler).
103
+ * **Locale-Aware Path Generation:** `Aris.path` now accepts a `locale:` argument to generate localized URLs automatically.
104
+ * **Root Locale Redirect:** Added `root_locale_redirect: true` to domain configurations to automatically bounce users from `/` to their default locale.
105
+ * **Subdomain Wildcards:** Enhanced the Trie to support `*.example.com` routing. The `request.subdomain` helper now correctly extracts multi-level subdomains (e.g., "app.staging").
106
+
107
+ ### 💥 Changed
108
+
109
+ * **Response Helpers:** Refactored `Aris::Response` into a modular helper system. Handlers now have access to `res.json`, `res.html`, `res.text`, and `res.xml`.
110
+
111
+ ---
112
+
113
+ ## [1.1.0] - 2025-11-20
114
+
115
+ Introduction of the "Utils" layer for SEO and automated metadata.
116
+
117
+ ### ✨ Added
118
+
119
+ * **Sitemap Generator:** Added `Aris::Utils::Sitemap`. Automatically generates `sitemap.xml` based on discovered routes and provided metadata (priority, changefreq).
120
+ * **Redirects Manager:** Added `Aris::Utils::Redirects`. Allows registering legacy URL mappings directly within route handlers using the `redirects_from` helper.
121
+ * **Content Negotiation:** Added `res.negotiate`. Handlers can now respond to different formats (JSON, XML, HTML) using a single block.
122
+
123
+ ### 💥 Changed
124
+
125
+ * **Header Normalization:** Aris now internally downcases all header keys to ensure compatibility between different Rack servers and the Mock adapter.
126
+
127
+ ---
128
+
129
+ ## [1.0.0] - 2025-10-30
130
+
131
+ The "Autodiscovery" Milestone. This version marks the transition to a file-based convention for large-scale applications.
132
+
133
+ ### ✨ Added
134
+
135
+ * **Route Autodiscovery:** Introduced `Aris.discover_and_define(routes_dir)`. Aris now scans your directory structure (e.g., `domain/path/_id/get.rb`) to build the routing tree automatically.
136
+ * **Convention-over-Configuration:** Parameterized routes are now identified by the `_` prefix in the filesystem (e.g., `_slug` becomes `:slug`).
137
+ * **OpenAPI/Swagger Metadata:** Added `api_doc` helper to handlers to facilitate automatic documentation generation.
138
+
139
+ ### 💥 Changed
140
+
141
+ * **Handler Resolution:** The `PipelineRunner` now lazily loads `Handler` constants from Ruby files only when the route is matched, significantly reducing boot time for thousands of routes.
142
+
143
+ ---
144
+
145
+ ## [0.9.0] - 2025-10-05
146
+
147
+ Performance optimization and production hardening.
148
+
149
+ ### ✨ Added
150
+
151
+ * **Request ID Tracking:** Added `Aris::Plugins::RequestId`. Automatically preserves or generates `X-Request-ID` headers for distributed tracing.
152
+ * **Response Compression:** Added `Aris::Plugins::Compression`. Transparent Gzip compression for text-based responses over a configurable size threshold.
153
+ * **Security Headers:** Added `Aris::Plugins::SecurityHeaders`. Configurable defaults for HSTS, CSP, X-Frame-Options, and Referrer-Policy.
154
+
155
+ ### ⚡ Performance
156
+
157
+ * Optimized Trie traversal by caching path segments, resulting in a 15% speed increase for deeply nested routes.
158
+
159
+ ---
160
+
161
+ ## [0.8.0] - 2025-09-10
162
+
163
+ Advanced matching features.
164
+
165
+ ### ✨ Added
166
+
167
+ * **Path Constraints:** Added `constraints: { id: /\d+/ }` support. Routes now only match if parameters satisfy the provided regex.
168
+ * **Wildcard Globbing:** Added support for `*path` segments to capture remaining path parts into a single parameter.
169
+ * **Health Checks:** Added `Aris::Plugins::HealthCheck`. A highly configurable plugin for liveness/readiness probes with dependency monitoring.
170
+
171
+ ---
172
+
173
+ ## [0.7.0] - 2025-08-15
174
+
175
+ Middleware and the Plugin Pipeline.
176
+
177
+ ### ✨ Added
178
+
179
+ * **The Plugin System:** Introduced the `use:` key at domain, scope, and route levels. Plugins follow a `call(request, response)` contract.
180
+ * **JSON Body Parser:** Added `Aris::Plugins::Json` to automatically parse incoming payloads into `request.json_body`.
181
+ * **Form Parser:** Added support for `application/x-www-form-urlencoded` payloads via `Aris::Plugins::FormParser`.
182
+
183
+ ---
184
+
185
+ ## [0.6.0] - 2025-07-20
186
+
187
+ Hardened Authentication.
188
+
189
+ ### ✨ Added
190
+
191
+ * **Bearer Auth Plugin:** Standardized token-based authentication.
192
+ * **Basic Auth Plugin:** Easy username/password protection for admin scopes.
193
+ * **API Key Auth Plugin:** Header-based key validation with custom validator support.
194
+ * **CORS Plugin:** Full support for origins, methods, credentials, and preflight `OPTIONS` handling.
195
+
196
+ ---
197
+
198
+ ## [0.5.0] - 2025-06-28
199
+
200
+ Integrated CSRF and Mocking.
201
+
202
+ ### ✨ Added
203
+
204
+ * **CSRF Protection:** A two-phase plugin (`CsrfTokenGenerator` and `CsrfProtection`) to secure state-changing requests.
205
+ * **Mock Adapter:** Built `Aris::Adapters::Mock` to allow full integration testing of routes and plugins without a live Rack server.
206
+
207
+ ---
208
+
209
+ ## [0.4.0] - 2025-06-01
210
+
211
+ The "Rack" release.
212
+
213
+ ### ✨ Added
214
+
215
+ * **Rack Adapter:** Official production adapter `Aris::Adapters::RackApp`.
216
+ * **Agnostic Request/Response:** Wrapped Rack environment in `Aris::Request` and `Aris::Response` to ensure handlers remain server-agnostic.
217
+
218
+ ---
219
+
220
+ ## [0.3.0] - 2025-05-15
221
+
222
+ Named routes and URL generation.
223
+
224
+ ### ✨ Added
225
+
226
+ * **Named Routes:** Added the `as:` option to route definitions.
227
+ * **Path/URL Helpers:** Introduced `Aris.path` and `Aris.url`. Support for query parameter appending and automatic URI encoding.
228
+ * **Domain Context:** Added `Aris.with_domain` for scoped URL generation.
229
+
230
+ ---
231
+
232
+ ## [0.2.0] - 2025-04-25
233
+
234
+ Multi-domain support.
235
+
236
+ ### ✨ Added
237
+
238
+ * **Multi-Domain Routing:** The routing hash now accepts domain strings as top-level keys.
239
+ * **Wildcard Domain Fallback:** Support for the `"*"` domain key to handle health checks or generic responses across all hosts.
240
+
241
+ ---
242
+
243
+ ## [0.1.0] - 2025-04-10
244
+
245
+ ### ✨ Added
246
+
247
+ * **Initial Release!**
248
+ * Core Trie-based routing engine.
249
+ * Support for standard HTTP verbs (GET, POST, PUT, PATCH, DELETE).
250
+ * Parameter extraction (e.g., `/users/:id`).
251
+ * Global `Aris.routes` configuration.
252
+
253
+ ---
254
+
255
+ **Would you like me to ...**
256
+
257
+ * Generate the `VERSION` file for this project?
258
+ * Create a `ROADMAP.md` for 2026?
259
+ * Implement a CLI command to auto-generate this changelog from git tags?
data/README.md CHANGED
@@ -118,6 +118,24 @@ Aris.routes({
118
118
  })
119
119
  ```
120
120
 
121
+ ### Sessions, cookies, CSRF, forms
122
+
123
+ ```ruby
124
+ Aris.configure { |c| c.secret_key_base = ENV.fetch('SECRET_KEY_BASE') }
125
+
126
+ Aris.routes({
127
+ "example.com": {
128
+ use: [:session, :form_parser, :csrf],
129
+ "/login": { post: { to: ->(req, res, prm) {
130
+ req.session[:user_id] = 1 # encrypted + authenticated cookie
131
+ res.redirect('/')
132
+ } } }
133
+ }
134
+ })
135
+ ```
136
+
137
+ `request.session`, `request.cookies`, `request.form_params`, `request.csrf_token`, `response.set_cookie` — see `docs/plugins/`.
138
+
121
139
  ### Composable Plugins
122
140
 
123
141
  Plugins execute between routing and handler dispatch. They're just callables that can inspect, modify, or halt the request.