tina4-nodejs 3.13.3 → 3.13.4

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/CLAUDE.md CHANGED
@@ -1,10 +1,10 @@
1
- # CLAUDE.md — AI Developer Guide for tina4-nodejs (v3.13.3)
1
+ # CLAUDE.md — AI Developer Guide for tina4-nodejs (v3.13.4)
2
2
 
3
3
  > This file helps AI assistants (Claude, Copilot, Cursor, etc.) understand and work on this codebase effectively.
4
4
 
5
5
  ## What This Project Is
6
6
 
7
- Tina4 for Node.js/TypeScript v3.13.3 — The Intelligent Native Application 4ramework. A convention-over-configuration structural paradigm. The developer writes TypeScript; Tina4 is invisible infrastructure.
7
+ Tina4 for Node.js/TypeScript v3.13.4 — The Intelligent Native Application 4ramework. A convention-over-configuration structural paradigm. The developer writes TypeScript; Tina4 is invisible infrastructure.
8
8
 
9
9
  The philosophy: zero ceremony, batteries included, file system as source of truth.
10
10
 
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
 
5
5
 
6
- "version": "3.13.3",
6
+ "version": "3.13.4",
7
7
 
8
8
  "type": "module",
9
9
  "description": "Tina4 for Node.js/TypeScript \u2014 54 built-in features, zero dependencies",
@@ -20,7 +20,7 @@ export type { RouteInfo } from "./router.js";
20
20
  export { discoverRoutes } from "./routeDiscovery.js";
21
21
  export { MiddlewareChain, MiddlewareRunner, cors, requestLogger, CorsMiddleware, RateLimiterMiddleware, RequestLogger, SecurityHeadersMiddleware, CsrfMiddleware } from "./middleware.js";
22
22
  export type { CorsConfig } from "./middleware.js";
23
- export { createRequest } from "./request.js";
23
+ export { createRequest, makeCaseInsensitiveHeaders } from "./request.js";
24
24
  export { createResponse, errorResponse, setDefaultTemplatesDir, getFrond, setFrond, getFrameworkFrond } from "./response.js";
25
25
  export { tryServeStatic } from "./static.js";
26
26
  export { loadEnv, getEnv, requireEnv, hasEnv, allEnv, resetEnv, isTruthy } from "./dotenv.js";
@@ -1,8 +1,42 @@
1
- import type { IncomingMessage } from "node:http";
1
+ import type { IncomingMessage, IncomingHttpHeaders } from "node:http";
2
2
  import type { Tina4Request, UploadedFile } from "./types.js";
3
3
 
4
+ /**
5
+ * Wrap Node's `IncomingHttpHeaders` in a Proxy so mixed-case lookups
6
+ * (`req.headers["Content-Type"]`) work alongside the canonical lowercase
7
+ * form Node already provides. Parity with PY-10-03 (Python ships a
8
+ * `CaseInsensitiveDict` for the same reason).
9
+ *
10
+ * The raw object is returned as-is by `Object.keys` / iteration — only
11
+ * string property reads/`in` checks are normalised.
12
+ */
13
+ export function makeCaseInsensitiveHeaders(
14
+ raw: IncomingHttpHeaders,
15
+ ): IncomingHttpHeaders {
16
+ return new Proxy(raw, {
17
+ get(target, prop, receiver) {
18
+ if (typeof prop === "string") {
19
+ const lower = prop.toLowerCase();
20
+ if (lower in target) return (target as Record<string, unknown>)[lower];
21
+ return Reflect.get(target, prop, receiver);
22
+ }
23
+ return Reflect.get(target, prop, receiver);
24
+ },
25
+ has(target, prop) {
26
+ if (typeof prop === "string") {
27
+ return prop.toLowerCase() in target || Reflect.has(target, prop);
28
+ }
29
+ return Reflect.has(target, prop);
30
+ },
31
+ }) as IncomingHttpHeaders;
32
+ }
33
+
4
34
  export function createRequest(req: IncomingMessage): Tina4Request {
5
35
  const tReq = req as Tina4Request;
36
+ // Wrap `req.headers` so mixed-case lookups work — Node's underlying object
37
+ // is already lower-cased, this just lets readers use any casing they like.
38
+ (tReq as unknown as { headers: IncomingHttpHeaders }).headers =
39
+ makeCaseInsensitiveHeaders(req.headers);
6
40
 
7
41
  // Resolve scheme + host honouring proxy headers — parity with PHP/Python/Ruby.
8
42
  const xfProto = req.headers["x-forwarded-proto"];
@@ -131,12 +131,13 @@ export class Router {
131
131
  routes.splice(existingIndex, 1);
132
132
  }
133
133
 
134
- // Write methods (POST/PUT/PATCH/DELETE) are secure by default,
135
- // unless custom middleware is registered (developer handles auth themselves)
134
+ // Write methods (POST/PUT/PATCH/DELETE) are secure by default. Middleware is
135
+ // purely additive — registering custom middleware must NOT silently disable the
136
+ // built-in Bearer-token gate (parity with PY-10-02). Use `noAuth()` to open a
137
+ // write route explicitly.
136
138
  const WRITE_METHODS = new Set(["POST", "PUT", "PATCH", "DELETE"]);
137
139
  const isWrite = WRITE_METHODS.has(method);
138
- const hasMiddleware = definition.middlewares && definition.middlewares.length > 0;
139
- const secureDefault = isWrite && !hasMiddleware ? (definition.secure ?? true) : definition.secure;
140
+ const secureDefault = isWrite ? (definition.secure ?? true) : definition.secure;
140
141
 
141
142
  const compiled: CompiledRoute = {
142
143
  pattern: definition.pattern,