tina4-nodejs 3.13.136 → 3.13.138

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 (243) hide show
  1. package/CLAUDE.md +33 -3
  2. package/COMMERCIAL-LICENSE.md +8 -0
  3. package/LICENSE +373 -0
  4. package/NOTICE +11 -0
  5. package/README.md +24 -2
  6. package/package.json +44 -6
  7. package/packages/cli/dist/bin.js +19440 -18017
  8. package/packages/cli/src/bin.ts +8 -0
  9. package/packages/cli/src/commands/build.ts +8 -0
  10. package/packages/cli/src/commands/generate.ts +8 -0
  11. package/packages/cli/src/commands/init.ts +8 -0
  12. package/packages/cli/src/commands/lint.ts +8 -0
  13. package/packages/cli/src/commands/migrate.ts +8 -0
  14. package/packages/cli/src/commands/migrateCreate.ts +8 -0
  15. package/packages/cli/src/commands/migrateRollback.ts +8 -0
  16. package/packages/cli/src/commands/migrateStatus.ts +8 -0
  17. package/packages/cli/src/commands/queue.ts +8 -0
  18. package/packages/cli/src/commands/routes.ts +8 -0
  19. package/packages/cli/src/commands/seed.ts +8 -0
  20. package/packages/cli/src/commands/serve.ts +11 -0
  21. package/packages/cli/src/commands/test.ts +8 -0
  22. package/packages/core/dist/index.js +19432 -18012
  23. package/packages/core/gallery/auth/src/routes/api/gallery/auth/login/post.ts +8 -0
  24. package/packages/core/gallery/auth/src/routes/api/gallery/auth/verify/get.ts +8 -0
  25. package/packages/core/gallery/auth/src/routes/gallery/auth/get.ts +8 -0
  26. package/packages/core/gallery/database/src/routes/api/gallery/db/notes/get.ts +8 -0
  27. package/packages/core/gallery/database/src/routes/api/gallery/db/notes/post.ts +8 -0
  28. package/packages/core/gallery/database/src/routes/api/gallery/db/tables/get.ts +8 -0
  29. package/packages/core/gallery/error-overlay/src/routes/api/gallery/crash/get.ts +8 -0
  30. package/packages/core/gallery/orm/src/routes/api/gallery/products/get.ts +8 -0
  31. package/packages/core/gallery/orm/src/routes/api/gallery/products/post.ts +8 -0
  32. package/packages/core/gallery/queue/src/lib/queueDb.ts +8 -0
  33. package/packages/core/gallery/queue/src/routes/api/gallery/queue/consume/post.ts +8 -0
  34. package/packages/core/gallery/queue/src/routes/api/gallery/queue/fail/post.ts +8 -0
  35. package/packages/core/gallery/queue/src/routes/api/gallery/queue/produce/post.ts +8 -0
  36. package/packages/core/gallery/queue/src/routes/api/gallery/queue/retry/post.ts +8 -0
  37. package/packages/core/gallery/queue/src/routes/api/gallery/queue/status/get.ts +8 -0
  38. package/packages/core/gallery/queue/src/routes/gallery/queue/get.ts +8 -0
  39. package/packages/core/gallery/rest-api/src/routes/api/gallery/hello/get.ts +8 -0
  40. package/packages/core/gallery/rest-api/src/routes/api/gallery/hello/post.ts +8 -0
  41. package/packages/core/gallery/templates/src/routes/gallery/page/get.ts +8 -0
  42. package/packages/core/gallery/templates/src/templates/gallery_page.twig +8 -0
  43. package/packages/core/public/THIRD-PARTY-NOTICES.md +55 -0
  44. package/packages/core/public/bundled-component-provenance.json +48 -0
  45. package/packages/core/public/js/tina4js.min.js +13 -3
  46. package/packages/core/public/licenses/swagger-ui-3.10.0-original-notice.txt +11 -0
  47. package/packages/core/public/licenses/swagger-ui-5.17.14-NOTICE.txt +2 -0
  48. package/packages/core/public/licenses/swagger-ui-Apache-2.0.txt +202 -0
  49. package/packages/core/public/licenses/tina4-css-MIT.txt +21 -0
  50. package/packages/core/public/licenses/tina4-dev-admin-components.json +240 -0
  51. package/packages/core/public/licenses/tina4-dev-admin-third-party.txt +919 -0
  52. package/packages/core/public/licenses/tina4-js-MIT.txt +20 -0
  53. package/packages/core/src/__feedback/widget.js +8 -0
  54. package/packages/core/src/_missing.ts +8 -0
  55. package/packages/core/src/ai.ts +8 -0
  56. package/packages/core/src/aiClient.ts +22 -7
  57. package/packages/core/src/api.ts +15 -3
  58. package/packages/core/src/auth.ts +21 -8
  59. package/packages/core/src/authGate.ts +8 -0
  60. package/packages/core/src/background.ts +8 -0
  61. package/packages/core/src/cache.ts +43 -4
  62. package/packages/core/src/constants.ts +8 -0
  63. package/packages/core/src/container.ts +8 -0
  64. package/packages/core/src/context/chunker.ts +8 -0
  65. package/packages/core/src/context/index.ts +8 -0
  66. package/packages/core/src/devAdmin.ts +185 -59
  67. package/packages/core/src/devMailbox.ts +8 -0
  68. package/packages/core/src/dispatchPipeline.ts +8 -0
  69. package/packages/core/src/docs.ts +8 -0
  70. package/packages/core/src/docsAutoDiscovery.ts +8 -0
  71. package/packages/core/src/docsParser.ts +8 -0
  72. package/packages/core/src/docsScanner.ts +44 -0
  73. package/packages/core/src/docsSignatures.ts +8 -0
  74. package/packages/core/src/dotenv.ts +8 -0
  75. package/packages/core/src/env.ts +8 -0
  76. package/packages/core/src/errorOverlay.ts +8 -0
  77. package/packages/core/src/events.ts +8 -0
  78. package/packages/core/src/fakeData.ts +8 -0
  79. package/packages/core/src/feedback.ts +8 -0
  80. package/packages/core/src/graphql.ts +16 -5
  81. package/packages/core/src/health.ts +8 -0
  82. package/packages/core/src/htmlElement.ts +8 -0
  83. package/packages/core/src/i18n.ts +8 -0
  84. package/packages/core/src/index.ts +8 -0
  85. package/packages/core/src/job.ts +8 -0
  86. package/packages/core/src/logger.ts +8 -0
  87. package/packages/core/src/mcp.test.ts +8 -0
  88. package/packages/core/src/mcp.ts +8 -0
  89. package/packages/core/src/messenger.ts +143 -86
  90. package/packages/core/src/metrics.ts +13 -0
  91. package/packages/core/src/middleware.ts +1178 -1096
  92. package/packages/core/src/mqtt.ts +8 -0
  93. package/packages/core/src/mqttMessage.ts +8 -0
  94. package/packages/core/src/optionalPackage.ts +48 -0
  95. package/packages/core/src/plan.ts +8 -0
  96. package/packages/core/src/portTakeover.ts +8 -0
  97. package/packages/core/src/projectIndex.ts +8 -0
  98. package/packages/core/src/projectIndexExtractors.ts +8 -0
  99. package/packages/core/src/projectIndexStorage.ts +8 -0
  100. package/packages/core/src/push.ts +8 -0
  101. package/packages/core/src/queue.ts +8 -0
  102. package/packages/core/src/queueBackends/kafkaBackend.ts +8 -0
  103. package/packages/core/src/queueBackends/liteBackend.ts +8 -0
  104. package/packages/core/src/queueBackends/mongoBackend.ts +21 -8
  105. package/packages/core/src/queueBackends/rabbitmqBackend.ts +8 -0
  106. package/packages/core/src/rateLimiter.ts +8 -0
  107. package/packages/core/src/request.ts +59 -10
  108. package/packages/core/src/response.ts +79 -5
  109. package/packages/core/src/routeDiscovery.ts +8 -0
  110. package/packages/core/src/router.ts +8 -0
  111. package/packages/core/src/server.ts +73 -24
  112. package/packages/core/src/service.ts +8 -0
  113. package/packages/core/src/session.ts +8 -0
  114. package/packages/core/src/sessionHandlers/childError.ts +8 -0
  115. package/packages/core/src/sessionHandlers/databaseHandler.ts +8 -0
  116. package/packages/core/src/sessionHandlers/memcachedHandler.ts +8 -0
  117. package/packages/core/src/sessionHandlers/mongoClient.ts +8 -0
  118. package/packages/core/src/sessionHandlers/mongoHandler.ts +8 -0
  119. package/packages/core/src/sessionHandlers/respClient.ts +8 -0
  120. package/packages/core/src/sessionHandlers/sqlClient.ts +8 -0
  121. package/packages/core/src/sessionHandlers/syncBridge.ts +8 -0
  122. package/packages/core/src/sessionHandlers/syncSocket.ts +8 -0
  123. package/packages/core/src/sessionHandlers/valkeyHandler.ts +8 -0
  124. package/packages/core/src/sso.ts +8 -0
  125. package/packages/core/src/static.ts +8 -0
  126. package/packages/core/src/test.ts +8 -0
  127. package/packages/core/src/testClient.ts +8 -0
  128. package/packages/core/src/testing.ts +8 -0
  129. package/packages/core/src/transport.ts +369 -0
  130. package/packages/core/src/trustedProxy.ts +8 -0
  131. package/packages/core/src/types.ts +13 -0
  132. package/packages/core/src/validator.ts +8 -0
  133. package/packages/core/src/version.ts +8 -0
  134. package/packages/core/src/websocket.ts +8 -0
  135. package/packages/core/src/websocketBackplane.ts +49 -32
  136. package/packages/core/src/websocketConnection.ts +8 -0
  137. package/packages/core/src/wsdl.ts +197 -115
  138. package/packages/core/templates/errors/302.twig +8 -0
  139. package/packages/core/templates/errors/401.twig +8 -0
  140. package/packages/core/templates/errors/403.twig +8 -0
  141. package/packages/core/templates/errors/404.twig +8 -0
  142. package/packages/core/templates/errors/500.twig +8 -0
  143. package/packages/core/templates/errors/502.twig +8 -0
  144. package/packages/core/templates/errors/503.twig +8 -0
  145. package/packages/core/templates/errors/base.twig +8 -0
  146. package/packages/frond/dist/index.js +151 -17
  147. package/packages/frond/src/engine.ts +177 -17
  148. package/packages/frond/src/index.ts +8 -0
  149. package/packages/orm/dist/index.js +8135 -6713
  150. package/packages/orm/src/adapters/firebird.ts +50 -3
  151. package/packages/orm/src/adapters/mongodb.ts +8 -0
  152. package/packages/orm/src/adapters/mssql.ts +29 -7
  153. package/packages/orm/src/adapters/mysql.ts +17 -1
  154. package/packages/orm/src/adapters/odbc.ts +11 -0
  155. package/packages/orm/src/adapters/pg-types.d.ts +8 -0
  156. package/packages/orm/src/adapters/postgres.ts +34 -8
  157. package/packages/orm/src/adapters/sqlDialect.ts +57 -0
  158. package/packages/orm/src/adapters/sqlite.ts +26 -0
  159. package/packages/orm/src/autoCrud.ts +78 -36
  160. package/packages/orm/src/baseModel.ts +61 -29
  161. package/packages/orm/src/cachedDatabase.ts +67 -1
  162. package/packages/orm/src/connectTimeout.ts +8 -0
  163. package/packages/orm/src/database.ts +649 -401
  164. package/packages/orm/src/databaseResult.ts +8 -0
  165. package/packages/orm/src/databaseUrl.ts +8 -0
  166. package/packages/orm/src/docstore.ts +23 -1
  167. package/packages/orm/src/fakeData.ts +8 -0
  168. package/packages/orm/src/graph/adapters/arango.ts +8 -0
  169. package/packages/orm/src/graph/adapters/bolt.ts +8 -0
  170. package/packages/orm/src/graph/adapters/ultipa.ts +8 -0
  171. package/packages/orm/src/graph/connectTimeout.ts +8 -0
  172. package/packages/orm/src/graph/errors.ts +8 -0
  173. package/packages/orm/src/graph/graphAdapter.ts +8 -0
  174. package/packages/orm/src/graph/graphDatabase.ts +8 -0
  175. package/packages/orm/src/graph/graphUrl.ts +10 -1
  176. package/packages/orm/src/graph/shapes.ts +8 -0
  177. package/packages/orm/src/index.ts +147 -139
  178. package/packages/orm/src/migration.ts +21 -0
  179. package/packages/orm/src/model.ts +8 -0
  180. package/packages/orm/src/modelCollection.ts +8 -0
  181. package/packages/orm/src/point.ts +8 -0
  182. package/packages/orm/src/query.ts +149 -33
  183. package/packages/orm/src/queryBuilder.ts +8 -0
  184. package/packages/orm/src/realtime/index.ts +8 -0
  185. package/packages/orm/src/realtime/models/attachment.ts +8 -0
  186. package/packages/orm/src/realtime/models/channel.ts +8 -0
  187. package/packages/orm/src/realtime/models/channelMember.ts +8 -0
  188. package/packages/orm/src/realtime/models/message.ts +8 -0
  189. package/packages/orm/src/realtime/models/workspace.ts +8 -0
  190. package/packages/orm/src/realtime/realtime.ts +8 -0
  191. package/packages/orm/src/realtime/storage.ts +43 -12
  192. package/packages/orm/src/seeder.ts +8 -0
  193. package/packages/orm/src/seederTable.ts +8 -0
  194. package/packages/orm/src/seederTypes.ts +8 -0
  195. package/packages/orm/src/sqlTranslator.ts +185 -8
  196. package/packages/orm/src/types.ts +15 -0
  197. package/packages/orm/src/validation.ts +8 -0
  198. package/packages/swagger/src/generator.ts +8 -0
  199. package/packages/swagger/src/index.ts +8 -0
  200. package/packages/swagger/src/ui.ts +8 -0
  201. package/types/core/src/aiClient.d.ts +2 -2
  202. package/types/core/src/background.d.ts +0 -16
  203. package/types/core/src/cache.d.ts +6 -0
  204. package/types/core/src/devAdmin.d.ts +18 -12
  205. package/types/core/src/docs.d.ts +0 -17
  206. package/types/core/src/errorOverlay.d.ts +0 -24
  207. package/types/core/src/events.d.ts +0 -12
  208. package/types/core/src/feedback.d.ts +0 -23
  209. package/types/core/src/graphql.d.ts +0 -21
  210. package/types/core/src/htmlElement.d.ts +0 -15
  211. package/types/core/src/messenger.d.ts +12 -1
  212. package/types/core/src/metrics.d.ts +2 -0
  213. package/types/core/src/middleware.d.ts +45 -1
  214. package/types/core/src/mqtt.d.ts +0 -33
  215. package/types/core/src/optionalPackage.d.ts +25 -0
  216. package/types/core/src/plan.d.ts +0 -10
  217. package/types/core/src/projectIndex.d.ts +0 -10
  218. package/types/core/src/queueBackends/mongoBackend.d.ts +2 -0
  219. package/types/core/src/request.d.ts +12 -0
  220. package/types/core/src/response.d.ts +13 -0
  221. package/types/core/src/server.d.ts +19 -0
  222. package/types/core/src/sessionHandlers/childError.d.ts +0 -15
  223. package/types/core/src/transport.d.ts +28 -0
  224. package/types/core/src/trustedProxy.d.ts +0 -16
  225. package/types/core/src/types.d.ts +5 -0
  226. package/types/core/src/websocketBackplane.d.ts +1 -0
  227. package/types/core/src/wsdl.d.ts +8 -22
  228. package/types/frond/src/engine.d.ts +7 -1
  229. package/types/orm/src/adapters/firebird.d.ts +12 -0
  230. package/types/orm/src/adapters/mssql.d.ts +11 -0
  231. package/types/orm/src/adapters/mysql.d.ts +2 -0
  232. package/types/orm/src/adapters/postgres.d.ts +11 -0
  233. package/types/orm/src/adapters/sqlDialect.d.ts +25 -0
  234. package/types/orm/src/adapters/sqlite.d.ts +7 -0
  235. package/types/orm/src/baseModel.d.ts +5 -0
  236. package/types/orm/src/cachedDatabase.d.ts +27 -0
  237. package/types/orm/src/database.d.ts +46 -7
  238. package/types/orm/src/graph/graphUrl.d.ts +0 -8
  239. package/types/orm/src/index.d.ts +1 -1
  240. package/types/orm/src/query.d.ts +48 -2
  241. package/types/orm/src/realtime/storage.d.ts +2 -1
  242. package/types/orm/src/sqlTranslator.d.ts +70 -18
  243. package/types/orm/src/types.d.ts +6 -0
@@ -1,4 +1,13 @@
1
+ /*
2
+ Copyright (c) 2026 Code Infinity
3
+ SPDX-License-Identifier: MPL-2.0
4
+ This Source Code Form is subject to the terms of the Mozilla Public
5
+ License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
+ */
8
+
1
9
  import { createServer, IncomingMessage, ServerResponse } from "node:http";
10
+ import { createTina4HttpServer, guardUnsafeHeaders, sendTransportRejection } from "./transport.js";
2
11
  import { randomBytes } from "node:crypto";
3
12
  import { resolve, dirname, join, relative } from "node:path";
4
13
  import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
@@ -21,7 +30,7 @@ import {
21
30
  TAKEOVER_KILLED,
22
31
  TAKEOVER_REFUSALS,
23
32
  } from "./portTakeover.js";
24
- import { createRequest } from "./request.js";
33
+ import { createRequest, PayloadTooLargeError } from "./request.js";
25
34
  import {
26
35
  resetRequestCaches,
27
36
  headStripIntercept,
@@ -36,7 +45,7 @@ import { isDebugMode } from "./errorOverlay.js";
36
45
  import { createHealthRoutes } from "./health.js";
37
46
  import { rateLimiter } from "./rateLimiter.js";
38
47
  import { Log } from "./logger.js";
39
- import { DevAdmin, RequestInspector, WsTracker, devMutationDenial, DEV_SAFE_METHODS } from "./devAdmin.js";
48
+ import { DevAdmin, RequestInspector, WsTracker, devRequestDenial, devHostAllowed } from "./devAdmin.js";
40
49
  import { CLOSE_GOING_AWAY, devReloadWs, serveWebSocketRoute, wsRouteManager } from "./websocket.js";
41
50
  import { feedbackEnabled, injectFeedbackWidget } from "./feedback.js";
42
51
  import { I18n } from "./i18n.js";
@@ -355,6 +364,35 @@ function findAvailablePort(start: number): number {
355
364
  }
356
365
  }
357
366
 
367
+ /**
368
+ * Variables that mark a CI run, in ADR-0070's order (ci_env_vars). A run is CI
369
+ * when any of them holds a value that, trimmed and lower-cased, is non-empty
370
+ * and not in CI_NOT_SET_VALUES.
371
+ */
372
+ export const CI_ENVIRONMENT_VARIABLES = ["CI", "CONTINUOUS_INTEGRATION", "GITHUB_ACTIONS", "GITLAB_CI", "BUILDKITE", "JENKINS_URL", "TF_BUILD", "TEAMCITY_VERSION"];
373
+
374
+ /** Values that say "not under CI" (ADR-0070 ci_not_set_values), compared trimmed and lower-cased. */
375
+ export const CI_NOT_SET_VALUES = ["false", "0", "no", "off"];
376
+
377
+ /**
378
+ * Whether the server may open a browser (ADR-0070): only for a developer at a
379
+ * desk. Every rule is a veto; nothing forces a browser open past one.
380
+ *
381
+ * 1. development only - the caller's resolved debug mode, and never with
382
+ * TINA4_PRODUCTION truthy or in a cluster worker (the primary decides);
383
+ * 2. never when TINA4_NO_BROWSER is truthy (true/1/yes/on);
384
+ * 3. never with --no-browser / a programmatic noBrowser (it can only veto);
385
+ * 4. never under CI.
386
+ */
387
+ export function shouldOpenBrowser(isDevelopment: boolean, noBrowser = false): boolean {
388
+ if (!isDevelopment || isTruthy(process.env.TINA4_PRODUCTION) || cluster.isWorker) return false;
389
+ if (noBrowser || isTruthy(process.env.TINA4_NO_BROWSER)) return false;
390
+ return !CI_ENVIRONMENT_VARIABLES.some((name) => {
391
+ const value = (process.env[name] ?? "").trim().toLowerCase();
392
+ return value !== "" && !CI_NOT_SET_VALUES.includes(value);
393
+ });
394
+ }
395
+
358
396
  /**
359
397
  * Open the user's default browser after a short delay so the server is ready.
360
398
  */
@@ -578,9 +616,9 @@ const HTTP_REASON_PHRASES: Record<number, string> = {
578
616
  304: "Not Modified", 307: "Temporary Redirect", 308: "Permanent Redirect",
579
617
  400: "Bad Request", 401: "Unauthorized", 403: "Forbidden",
580
618
  404: "Not Found", 405: "Method Not Allowed", 406: "Not Acceptable",
581
- 409: "Conflict", 410: "Gone", 413: "Content Too Large",
619
+ 408: "Request Timeout", 409: "Conflict", 410: "Gone", 413: "Content Too Large",
582
620
  415: "Unsupported Media Type", 422: "Unprocessable Content",
583
- 429: "Too Many Requests",
621
+ 429: "Too Many Requests", 431: "Request Header Fields Too Large",
584
622
  500: "Internal Server Error", 501: "Not Implemented",
585
623
  502: "Bad Gateway", 503: "Service Unavailable", 504: "Gateway Timeout",
586
624
  };
@@ -628,6 +666,9 @@ export function resolveTemplate(pathname: string, templatesDir: string): string
628
666
  // Skip underscore-prefixed files even within pages/ — they're private
629
667
  // by Hugo/Jekyll convention (helpers, fragments) and shouldn't auto-serve.
630
668
  if (cleanPath.split("/").some((seg) => seg.startsWith("_"))) return null;
669
+ // ADR-0082: a "." / ".." segment (or a backslash) could walk out of pages/
670
+ // - the only directory that auto-routes. Refuse it outright.
671
+ if (cleanPath.includes("\\") || cleanPath.split("/").some((seg) => seg === "" || seg === "." || seg === "..")) return null;
631
672
  const pagesDir = resolve(templatesDir, TEMPLATE_PAGES_DIR);
632
673
  for (const ext of [".twig", ".html"]) {
633
674
  if (existsSync(resolve(pagesDir, cleanPath + ext))) {
@@ -1101,21 +1142,6 @@ async function runMatchedRoute(ctx: MatchedRouteContext): Promise<void> {
1101
1142
  const { req, res, match, postMatchMiddleware } = ctx;
1102
1143
  req.params = match.params as never;
1103
1144
 
1104
- // DEVADMIN-DEC-01/02: fail-closed same-origin + loopback gate on every /__dev
1105
- // write (POST/PUT/PATCH/DELETE), BEFORE the handler runs. Closes drive-by CSRF
1106
- // (a cross-origin page POSTing to /file/save then /reload) and a network-exposed
1107
- // debug box. Scoped to /__dev so /__feedback + /ai are unaffected; GET/HEAD/
1108
- // OPTIONS are safe and skip the gate. The MCP endpoints keep their own 404 gate
1109
- // (devMutationDenial skips the mcp prefixes for the loopback part).
1110
- const devMethod = (req.method ?? "GET").toUpperCase();
1111
- if (ctx.pathname.startsWith("/__dev") && !DEV_SAFE_METHODS.has(devMethod)) {
1112
- const denial = devMutationDenial(req);
1113
- if (denial) {
1114
- res.json({ ok: false, error: denial.error }, denial.status);
1115
- return;
1116
- }
1117
- }
1118
-
1119
1145
  if (await runGlobalMiddlewarePass(postMatchMiddleware, req, res)) return;
1120
1146
 
1121
1147
  // Auth enforcement lives in enforceRouteAuth (authGate.ts) so the in-process
@@ -1707,6 +1733,10 @@ async function dispatchInner(
1707
1733
  // These four close over nothing but the raw req/res (never ctx), which is
1708
1734
  // why they take no context object at all.
1709
1735
  await resetRequestCaches();
1736
+ // Installed FIRST so it is the innermost wrapper of end()/write(): whatever
1737
+ // the later interceptors do, a response carrying a header node:http refused
1738
+ // leaves as the ADR-0068 500 {"error":"Invalid response header"}.
1739
+ guardUnsafeHeaders(rawRes);
1710
1740
  headStripIntercept(rawReq, rawRes);
1711
1741
  // Feature 40 (CE-DEC-01/02): gzip + ETag + conditional-GET for every
1712
1742
  // dynamic response. Installed right after headStripIntercept so it runs
@@ -1718,6 +1748,11 @@ async function dispatchInner(
1718
1748
  // res.render() is handled natively by response.ts via Frond
1719
1749
 
1720
1750
  try {
1751
+ // Gate before middleware, matching and automatic OPTIONS handling (ADR-0082).
1752
+ if (req.path.replace(/\/+/g, "/").startsWith("/__dev")) {
1753
+ const denial = devRequestDenial(req);
1754
+ if (denial) { res.json({ ok: false, error: denial.error }, denial.status); return; }
1755
+ }
1721
1756
  // sessionAutoStart is the one prologue stage INSIDE the try. It degrades
1722
1757
  // on its own (ADR-0021), so the only thing that escapes it is a
1723
1758
  // TINA4_SESSION_STRICT refusal - and that must become a 500 through the
@@ -1740,6 +1775,16 @@ async function dispatchInner(
1740
1775
  try {
1741
1776
  await req.parseBody();
1742
1777
  } catch (err) {
1778
+ // The transport already answered (a 408 for a stalled body) and the
1779
+ // connection is going away: nothing left to say.
1780
+ if (rawRes.writableEnded) return;
1781
+ // A body over TINA4_MAX_UPLOAD_SIZE is a transport rejection (ADR-0068
1782
+ // section 4): exact body, security headers, and Connection: close, so
1783
+ // node:http does not go on reading the rest of the upload.
1784
+ if (err instanceof PayloadTooLargeError) {
1785
+ sendTransportRejection(rawRes, 413, err.message);
1786
+ return;
1787
+ }
1743
1788
  const status = (err as { statusCode?: number })?.statusCode;
1744
1789
  if (typeof status === "number" && status >= 400 && status < 500) {
1745
1790
  if (!rawRes.writableEnded) {
@@ -1910,7 +1955,7 @@ function startLoopbackSiblings(
1910
1955
  siblingHosts.map(
1911
1956
  (siblingHost) =>
1912
1957
  new Promise<ReturnType<typeof createServer> | null>((resolveSibling) => {
1913
- const sibling = createServer(dispatch);
1958
+ const sibling = createTina4HttpServer(dispatch);
1914
1959
  let settled = false;
1915
1960
  sibling.on("error", (err: NodeJS.ErrnoException) => {
1916
1961
  const expected =
@@ -2186,7 +2231,7 @@ export async function startServer(config?: Tina4Config): Promise<{
2186
2231
  // dev; the stable AI port (port+1000, created below) suppresses reload/toolbar so an
2187
2232
  // AI tool can drive it without its own edits triggering refreshes. The tina4 client
2188
2233
  // posts /__dev/api/reload to the MAIN port. Matches Python (master).
2189
- const server = createServer(dispatch);
2234
+ const server = createTina4HttpServer(dispatch);
2190
2235
 
2191
2236
  // WebSocket upgrade handling on the MAIN port. Two responsibilities:
2192
2237
  //
@@ -2217,6 +2262,11 @@ export async function startServer(config?: Tina4Config): Promise<{
2217
2262
  const upPath = (req.url ?? "/").split("?")[0];
2218
2263
  // Dev-reload channel (debug only).
2219
2264
  if (isDevMode() && upPath === "/__dev_reload") {
2265
+ // ADR-0082: the reload socket answers only a loopback / TINA4_HOST Host.
2266
+ if (!devHostAllowed(req.headers.host)) {
2267
+ try { socket.write("HTTP/1.1 403 Forbidden\r\n\r\n"); socket.destroy(); } catch { /* gone */ }
2268
+ return;
2269
+ }
2220
2270
  devReloadWs.handleUpgrade(req, socket, head);
2221
2271
  return;
2222
2272
  }
@@ -2295,7 +2345,7 @@ export async function startServer(config?: Tina4Config): Promise<{
2295
2345
 
2296
2346
  if (isDebug && !noAiPort && aiPortInRange) {
2297
2347
  // Stable AI port (port+1000): tag requests so /__dev_reload + toolbar are suppressed.
2298
- aiServer = createServer(async (req, res) => {
2348
+ aiServer = createTina4HttpServer(async (req, res) => {
2299
2349
  (req as any)._tina4AiPort = true;
2300
2350
  await dispatch(req, res);
2301
2351
  });
@@ -2352,8 +2402,7 @@ ${reset}
2352
2402
  Debug: ${isDebug ? "ON" : "OFF"} (Log level: ${logLevel})${dualPortLines}
2353
2403
  `);
2354
2404
  }
2355
- const noBrowser = isTruthy(process.env.TINA4_NO_BROWSER);
2356
- if (!noBrowser) {
2405
+ if (shouldOpenBrowser(isDebug, config?.noBrowser === true)) {
2357
2406
  // Open the browser on the MAIN port — that's the hot-reload port.
2358
2407
  openBrowser(`http://${displayHost}:${port}`);
2359
2408
  }
@@ -1,3 +1,11 @@
1
+ /*
2
+ Copyright (c) 2026 Code Infinity
3
+ SPDX-License-Identifier: MPL-2.0
4
+ This Source Code Form is subject to the terms of the Mozilla Public
5
+ License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
+ */
8
+
1
9
  /**
2
10
  * Service Runner — in-process background services using Node.js timers.
3
11
  * Zero dependencies. Supports cron timing, simple intervals, and daemon mode.
@@ -1,3 +1,11 @@
1
+ /*
2
+ Copyright (c) 2026 Code Infinity
3
+ SPDX-License-Identifier: MPL-2.0
4
+ This Source Code Form is subject to the terms of the Mozilla Public
5
+ License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
+ */
8
+
1
9
  /**
2
10
  * Tina4 Session — Pluggable session backends, zero core dependencies.
3
11
  *
@@ -1,3 +1,11 @@
1
+ /*
2
+ Copyright (c) 2026 Code Infinity
3
+ SPDX-License-Identifier: MPL-2.0
4
+ This Source Code Form is subject to the terms of the Mozilla Public
5
+ License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
+ */
8
+
1
9
  /**
2
10
  * Tina4 session handlers — turn a failed `execFileSync` child into a readable cause.
3
11
  *
@@ -1,3 +1,11 @@
1
+ /*
2
+ Copyright (c) 2026 Code Infinity
3
+ SPDX-License-Identifier: MPL-2.0
4
+ This Source Code Form is subject to the terms of the Mozilla Public
5
+ License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
+ */
8
+
1
9
  /**
2
10
  * Tina4 Database Session Handler — sessions in a `tina4_session` table on ANY
3
11
  * engine the ORM Database layer supports: sqlite, postgres, mysql, mssql,
@@ -1,3 +1,11 @@
1
+ /*
2
+ Copyright (c) 2026 Code Infinity
3
+ SPDX-License-Identifier: MPL-2.0
4
+ This Source Code Form is subject to the terms of the Mozilla Public
5
+ License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
+ */
8
+
1
9
  /**
2
10
  * Tina4 Memcached Session Handler — zero-dependency text protocol over TCP.
3
11
  *
@@ -1,3 +1,11 @@
1
+ /*
2
+ Copyright (c) 2026 Code Infinity
3
+ SPDX-License-Identifier: MPL-2.0
4
+ This Source Code Form is subject to the terms of the Mozilla Public
5
+ License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
+ */
8
+
1
9
  /**
2
10
  * Tina4 synchronous MongoDB transport — ONE persistent client per target.
3
11
  *
@@ -1,3 +1,11 @@
1
+ /*
2
+ Copyright (c) 2026 Code Infinity
3
+ SPDX-License-Identifier: MPL-2.0
4
+ This Source Code Form is subject to the terms of the Mozilla Public
5
+ License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
+ */
8
+
1
9
  /**
2
10
  * Tina4 MongoDB Session Handler — MongoDB wire protocol via raw TCP, zero dependencies.
3
11
  *
@@ -1,3 +1,11 @@
1
+ /*
2
+ Copyright (c) 2026 Code Infinity
3
+ SPDX-License-Identifier: MPL-2.0
4
+ This Source Code Form is subject to the terms of the Mozilla Public
5
+ License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
+ */
8
+
1
9
  /**
2
10
  * Tina4 synchronous RESP transport — shared by every Redis/Valkey session handler.
3
11
  *
@@ -1,3 +1,11 @@
1
+ /*
2
+ Copyright (c) 2026 Code Infinity
3
+ SPDX-License-Identifier: MPL-2.0
4
+ This Source Code Form is subject to the terms of the Mozilla Public
5
+ License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
+ */
8
+
1
9
  /**
2
10
  * Tina4 synchronous SQL transport for the database session backend.
3
11
  *
@@ -1,3 +1,11 @@
1
+ /*
2
+ Copyright (c) 2026 Code Infinity
3
+ SPDX-License-Identifier: MPL-2.0
4
+ This Source Code Form is subject to the terms of the Mozilla Public
5
+ License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
+ */
8
+
1
9
  /**
2
10
  * Tina4 sync-over-async bridge — call an ASYNC worker from SYNCHRONOUS code.
3
11
  *
@@ -1,3 +1,11 @@
1
+ /*
2
+ Copyright (c) 2026 Code Infinity
3
+ SPDX-License-Identifier: MPL-2.0
4
+ This Source Code Form is subject to the terms of the Mozilla Public
5
+ License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
+ */
8
+
1
9
  /**
2
10
  * Tina4 synchronous socket transport — ONE persistent connection per target.
3
11
  *
@@ -1,3 +1,11 @@
1
+ /*
2
+ Copyright (c) 2026 Code Infinity
3
+ SPDX-License-Identifier: MPL-2.0
4
+ This Source Code Form is subject to the terms of the Mozilla Public
5
+ License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
+ */
8
+
1
9
  /**
2
10
  * Tina4 Valkey Session Handler — Valkey (Redis-compatible) via raw TCP, zero dependencies.
3
11
  *
@@ -1,3 +1,11 @@
1
+ /*
2
+ Copyright (c) 2026 Code Infinity
3
+ SPDX-License-Identifier: MPL-2.0
4
+ This Source Code Form is subject to the terms of the Mozilla Public
5
+ License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
+ */
8
+
1
9
  /** Provider-neutral, configuration-first OpenID Connect SSO. */
2
10
  import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
3
11
  import type { Router } from "./router.js";
@@ -1,3 +1,11 @@
1
+ /*
2
+ Copyright (c) 2026 Code Infinity
3
+ SPDX-License-Identifier: MPL-2.0
4
+ This Source Code Form is subject to the terms of the Mozilla Public
5
+ License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
+ */
8
+
1
9
  import { readFileSync, realpathSync, statSync, type Stats } from "node:fs";
2
10
  import { join, extname, sep } from "node:path";
3
11
  import { gzipSync } from "node:zlib";
@@ -1,3 +1,11 @@
1
+ /*
2
+ Copyright (c) 2026 Code Infinity
3
+ SPDX-License-Identifier: MPL-2.0
4
+ This Source Code Form is subject to the terms of the Mozilla Public
5
+ License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
+ */
8
+
1
9
  /**
2
10
  * Tina4 — The Intelligent Native Application 4ramework
3
11
  * Copyright 2007 - current Tina4
@@ -1,3 +1,11 @@
1
+ /*
2
+ Copyright (c) 2026 Code Infinity
3
+ SPDX-License-Identifier: MPL-2.0
4
+ This Source Code Form is subject to the terms of the Mozilla Public
5
+ License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
+ */
8
+
1
9
  /**
2
10
  * Tina4 Test Client — Test routes without starting a server.
3
11
  *
@@ -1,3 +1,11 @@
1
+ /*
2
+ Copyright (c) 2026 Code Infinity
3
+ SPDX-License-Identifier: MPL-2.0
4
+ This Source Code Form is subject to the terms of the Mozilla Public
5
+ License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
+ */
8
+
1
9
  /**
2
10
  * Tina4 Node.js — Inline testing framework.
3
11
  *