tina4-nodejs 3.13.137 → 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 (242) 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 +19466 -18048
  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 +19458 -18043
  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 +8 -0
  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 +8125 -6708
  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 +8 -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/background.d.ts +0 -16
  202. package/types/core/src/cache.d.ts +6 -0
  203. package/types/core/src/devAdmin.d.ts +18 -12
  204. package/types/core/src/docs.d.ts +0 -17
  205. package/types/core/src/errorOverlay.d.ts +0 -24
  206. package/types/core/src/events.d.ts +0 -12
  207. package/types/core/src/feedback.d.ts +0 -23
  208. package/types/core/src/graphql.d.ts +0 -21
  209. package/types/core/src/htmlElement.d.ts +0 -15
  210. package/types/core/src/messenger.d.ts +12 -1
  211. package/types/core/src/metrics.d.ts +2 -0
  212. package/types/core/src/middleware.d.ts +45 -1
  213. package/types/core/src/mqtt.d.ts +0 -33
  214. package/types/core/src/optionalPackage.d.ts +25 -0
  215. package/types/core/src/plan.d.ts +0 -10
  216. package/types/core/src/projectIndex.d.ts +0 -10
  217. package/types/core/src/queueBackends/mongoBackend.d.ts +2 -0
  218. package/types/core/src/request.d.ts +12 -0
  219. package/types/core/src/response.d.ts +13 -0
  220. package/types/core/src/server.d.ts +19 -0
  221. package/types/core/src/sessionHandlers/childError.d.ts +0 -15
  222. package/types/core/src/transport.d.ts +28 -0
  223. package/types/core/src/trustedProxy.d.ts +0 -16
  224. package/types/core/src/types.d.ts +5 -0
  225. package/types/core/src/websocketBackplane.d.ts +1 -0
  226. package/types/core/src/wsdl.d.ts +8 -22
  227. package/types/frond/src/engine.d.ts +7 -1
  228. package/types/orm/src/adapters/firebird.d.ts +12 -0
  229. package/types/orm/src/adapters/mssql.d.ts +11 -0
  230. package/types/orm/src/adapters/mysql.d.ts +2 -0
  231. package/types/orm/src/adapters/postgres.d.ts +11 -0
  232. package/types/orm/src/adapters/sqlDialect.d.ts +25 -0
  233. package/types/orm/src/adapters/sqlite.d.ts +7 -0
  234. package/types/orm/src/baseModel.d.ts +5 -0
  235. package/types/orm/src/cachedDatabase.d.ts +27 -0
  236. package/types/orm/src/database.d.ts +46 -7
  237. package/types/orm/src/graph/graphUrl.d.ts +0 -8
  238. package/types/orm/src/index.d.ts +1 -1
  239. package/types/orm/src/query.d.ts +48 -2
  240. package/types/orm/src/realtime/storage.d.ts +2 -1
  241. package/types/orm/src/sqlTranslator.d.ts +70 -18
  242. package/types/orm/src/types.d.ts +6 -0
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
@@ -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
  (function(){"use strict";(()=>{try{const t=window.location.pathname||"";return t.startsWith("/__dev")||t.startsWith("/__feedback")}catch{return!1}})()?console.info("tina4-feedback-widget: skipping on developer path"):window.__tina4FeedbackLoaded?console.warn("tina4-feedback-widget already loaded; skipping"):(window.__tina4FeedbackLoaded=!0,b());function b(){const c=(getComputedStyle(document.documentElement).getPropertyValue("--primary")||"").trim()||"#3b82f6";h(c);const l=m();document.body.appendChild(l);let e=null,u;const r=[];l.addEventListener("click",()=>{if(e){e.remove(),e=null,l.style.display="";return}e=g(),document.body.appendChild(e),l.style.display="none",setTimeout(()=>e?.querySelector("textarea")?.focus(),0)});function g(){const o=document.createElement("div");o.className="tina4-fb-modal",o.innerHTML=`
2
10
  <div class="tina4-fb-head">
3
11
  <span class="tina4-fb-title">Tell us what's not working</span>
@@ -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
  * Last-resort finder for `@tina4/core/<subpath>` under Node's ESM resolver.
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 AI — Install AI coding assistant context files.
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
  /** Zero-dependency app-facing AI client (ADR-0053 + ADR-0060). */
2
10
  import http, { type IncomingMessage } from "node:http";
3
11
  import https from "node:https";
@@ -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 API Client — HTTP client using Node.js built-in modules only.
3
11
  *
@@ -667,7 +675,7 @@ export class Api {
667
675
  url += (url.includes("?") ? "&" : "?") + qs;
668
676
  }
669
677
 
670
- const { headers, data } = this.buildRequest("GET", "application/json", undefined);
678
+ const { headers, data } = this.buildRequest("GET", "application/json", undefined, undefined, url);
671
679
 
672
680
  // An injected transport can't stream (it returns a buffered result), so
673
681
  // write its body out; only the real network path streams chunk-by-chunk.
@@ -760,7 +768,7 @@ export class Api {
760
768
  const url = this.buildUrl(path);
761
769
  const method = (opts.method ?? "GET").toUpperCase();
762
770
  const contentType = opts.contentType ?? "application/json";
763
- const { headers, data } = this.buildRequest(method, contentType, opts.body, opts.headers);
771
+ const { headers, data } = this.buildRequest(method, contentType, opts.body, opts.headers, url);
764
772
  const totalSec = this.streamSeconds(opts.timeout, "TINA4_API_TIMEOUT", this.timeout);
765
773
  const connectSec = this.streamSeconds(opts.connectTimeout, "TINA4_API_CONNECT_TIMEOUT", 10);
766
774
  const opened = await this.openStreamRequest(method, url, headers, data, connectSec);
@@ -904,6 +912,7 @@ export class Api {
904
912
  contentType: string,
905
913
  body: unknown,
906
914
  extraHeaders?: Record<string, string>,
915
+ targetUrl?: string,
907
916
  ): { headers: Record<string, string>; data: Buffer | undefined } {
908
917
  const headers: Record<string, string> = { "User-Agent": `Tina4/${TINA4_VERSION}`, ...this.headers };
909
918
  if (this.authHeader) {
@@ -943,6 +952,9 @@ export class Api {
943
952
  Object.assign(headers, extraHeaders);
944
953
  }
945
954
 
955
+ if (targetUrl !== undefined && !sameOrigin(targetUrl, this.baseUrl)) {
956
+ for (const name of STRIP_ON_CROSS_ORIGIN) deleteHeaderCaseInsensitive(headers, name);
957
+ }
946
958
  return { headers, data };
947
959
  }
948
960
 
@@ -985,7 +997,7 @@ export class Api {
985
997
  contentType: string = "application/json",
986
998
  extraHeaders?: Record<string, string>,
987
999
  ): Promise<ApiResult> {
988
- const { headers, data } = this.buildRequest(method, contentType, body, extraHeaders);
1000
+ const { headers, data } = this.buildRequest(method, contentType, body, extraHeaders, url);
989
1001
 
990
1002
  // A user-injected transport fully replaces the network call.
991
1003
  if (this.transportFn) {
@@ -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 Auth — Zero-dependency JWT, password hashing, and auth middleware.
3
11
  *
@@ -12,7 +20,7 @@
12
20
  * checkPassword("secret123", hash); // true
13
21
  */
14
22
  import { createHmac, createSign, createVerify, pbkdf2Sync, randomBytes, timingSafeEqual } from "node:crypto";
15
- import { appendFileSync, existsSync, readFileSync } from "node:fs";
23
+ import { appendFileSync, existsSync, readFileSync, openSync, closeSync, fstatSync, fchmodSync, constants } from "node:fs";
16
24
  import { join } from "node:path";
17
25
  import type { Middleware, Tina4Request, Tina4Response } from "./types.js";
18
26
  import { isTruthy } from "./dotenv.js";
@@ -107,14 +115,19 @@ export function ensureDevSecret(cwd?: string): string | null {
107
115
  const baseDir = cwd ?? process.cwd();
108
116
  const envLocalPath = join(baseDir, ".env.local");
109
117
  try {
110
- // If the file exists and its content doesn't end in a newline, prepend one
111
- // so the new key lands on its own line.
112
- let prefix = "";
113
- if (existsSync(envLocalPath)) {
114
- const existing = readFileSync(envLocalPath, "utf-8");
115
- if (existing.length > 0 && !existing.endsWith("\n")) prefix = "\n";
118
+ // Read and append through one descriptor so replacing a pathname cannot
119
+ // redirect either operation to an unrelated file.
120
+ const fd = openSync(envLocalPath, constants.O_RDWR | constants.O_APPEND | constants.O_CREAT | (constants.O_NOFOLLOW ?? 0) | (constants.O_NONBLOCK ?? 0), 0o600);
121
+ try {
122
+ const info = fstatSync(fd);
123
+ if (!info.isFile() || info.nlink !== 1) throw new Error("Refusing a non-regular or multiply-linked configuration file");
124
+ fchmodSync(fd, 0o600);
125
+ const existing = readFileSync(fd, "utf-8");
126
+ const prefix = existing.length > 0 && !existing.endsWith("\n") ? "\n" : "";
127
+ appendFileSync(fd, `${prefix}TINA4_SECRET=${newSecret}\n`);
128
+ } finally {
129
+ closeSync(fd);
116
130
  }
117
- appendFileSync(envLocalPath, `${prefix}TINA4_SECRET=${newSecret}\n`);
118
131
  void _logInfo("Auth: generated a development secret, saved to .env.local (gitignored)");
119
132
  } catch {
120
133
  // Keep the in-memory secret for this run; warn but never crash boot.
@@ -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
  * Secure-by-default route auth gate — shared by the live server dispatch and the
3
11
  * in-process TestClient so the test surface enforces the IDENTICAL gate as
@@ -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
  * Background tasks — periodic callbacks that run alongside the HTTP 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
  * Multi-backend response cache for GET requests.
3
11
  *
@@ -56,6 +64,7 @@ import * as fs from "node:fs";
56
64
  import * as path from "node:path";
57
65
  import * as crypto from "node:crypto";
58
66
  import * as net from "node:net";
67
+ import { optionalPackageMissing } from "./optionalPackage.js";
59
68
 
60
69
  // ── Credential parsing (WHATWG URL or TINA4_CACHE_USERNAME / _PASSWORD) ──
61
70
 
@@ -181,6 +190,12 @@ interface CacheBackend {
181
190
  /** One-time async connect/probe. Resolves once the backend has decided
182
191
  * availability; createBackend() awaits this before falling back to file. */
183
192
  ready?(): Promise<void>;
193
+ /**
194
+ * When unavailable because the app has not installed the backend's driver
195
+ * (an optional peer, ADR-0067): the actionable install message, appended to
196
+ * the fallback warning. null for every other cause.
197
+ */
198
+ missingDriver?(): string | null;
184
199
  }
185
200
 
186
201
  // ── Memory backend ────────────────────────────────────────────────
@@ -1141,6 +1156,7 @@ class MongoBackend implements CacheBackend {
1141
1156
  private misses = 0;
1142
1157
  private maxEntries: number;
1143
1158
  private available = false;
1159
+ private missingDriverMessage: string | null = null;
1144
1160
  private readyPromise: Promise<void>;
1145
1161
  // The mongodb driver types aren't depended on at compile time (optional dep).
1146
1162
  private client: any = null;
@@ -1178,8 +1194,15 @@ class MongoBackend implements CacheBackend {
1178
1194
  try {
1179
1195
  // Dynamic import so @tina4/core has no hard dependency on `mongodb` and an
1180
1196
  // absent driver degrades to file-fallback (never an import-time crash).
1181
- const mod: any = await import("mongodb").catch(() => null);
1182
- if (!mod || !mod.MongoClient) { this.available = false; return; }
1197
+ let importError: any = null;
1198
+ const mod: any = await import("mongodb").catch((error) => { importError = error; return null; });
1199
+ if (!mod || !mod.MongoClient) {
1200
+ this.available = false;
1201
+ if (importError?.code === "ERR_MODULE_NOT_FOUND") {
1202
+ this.missingDriverMessage = optionalPackageMissing("the mongodb cache backend", ["mongodb"]).message;
1203
+ }
1204
+ return;
1205
+ }
1183
1206
  const client = new mod.MongoClient(this.url, { serverSelectionTimeoutMS: 4000 });
1184
1207
  await client.connect();
1185
1208
  await client.db(this.dbName).command({ ping: 1 });
@@ -1200,6 +1223,10 @@ class MongoBackend implements CacheBackend {
1200
1223
  return this.readyPromise;
1201
1224
  }
1202
1225
 
1226
+ missingDriver(): string | null {
1227
+ return this.missingDriverMessage;
1228
+ }
1229
+
1203
1230
  async isAvailable(): Promise<boolean> {
1204
1231
  await this.readyPromise;
1205
1232
  return this.available;
@@ -1291,6 +1318,7 @@ class DatabaseBackend implements CacheBackend {
1291
1318
  private misses = 0;
1292
1319
  private maxEntries: number;
1293
1320
  private available = false;
1321
+ private missingDriverMessage: string | null = null;
1294
1322
  private readyPromise: Promise<void>;
1295
1323
  // @tina4/orm Database instance (optional dep, loaded dynamically).
1296
1324
  private db: any = null;
@@ -1324,8 +1352,13 @@ class DatabaseBackend implements CacheBackend {
1324
1352
  try { db.commit(); } catch { /* sqlite autocommits DDL */ }
1325
1353
  this.db = db;
1326
1354
  this.available = true;
1327
- } catch {
1355
+ } catch (error) {
1328
1356
  this.available = false;
1357
+ // The ORM adapters already phrase a missing driver as the install
1358
+ // command; carry THAT through, and nothing else (a connect error can
1359
+ // name the host and user).
1360
+ const message = error instanceof Error ? error.message : String(error);
1361
+ if (/npm install \S/.test(message)) this.missingDriverMessage = message;
1329
1362
  } finally {
1330
1363
  if (prevAuto === undefined) delete process.env.TINA4_AUTO_CACHING; else process.env.TINA4_AUTO_CACHING = prevAuto;
1331
1364
  if (prevDb === undefined) delete process.env.TINA4_DB_CACHE; else process.env.TINA4_DB_CACHE = prevDb;
@@ -1336,6 +1369,10 @@ class DatabaseBackend implements CacheBackend {
1336
1369
  return this.readyPromise;
1337
1370
  }
1338
1371
 
1372
+ missingDriver(): string | null {
1373
+ return this.missingDriverMessage;
1374
+ }
1375
+
1339
1376
  async isAvailable(): Promise<boolean> {
1340
1377
  await this.readyPromise;
1341
1378
  return this.available;
@@ -1531,9 +1568,11 @@ export async function createBackend(config?: {
1531
1568
  // degrading to a no-op cache. Mirrors the Python master.
1532
1569
  if (typeof backend.isAvailable === "function" && !(await backend.isAvailable())) {
1533
1570
  // eslint-disable-next-line no-console
1571
+ const installHint = backend.missingDriver?.() ?? null;
1534
1572
  console.warn(
1535
1573
  `[tina4] Cache backend '${backendName}' is unavailable ` +
1536
- `(driver missing or service unreachable) — falling back to 'file'.`,
1574
+ `(driver missing or service unreachable) — falling back to 'file'.` +
1575
+ (installHint ? ` ${installHint}` : ""),
1537
1576
  );
1538
1577
  return new FileBackend(cacheDir(), maxEntries);
1539
1578
  }
@@ -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 Constants — HTTP status codes and content types.
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
  * Lightweight dependency injection container.
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
  // Tina4 Node.js
2
10
  //
3
11
  // Text folding + chunking for the Context subsystem.
@@ -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
  // Tina4 Node.js
2
10
  //
3
11
  // Context — a native, zero-dependency code/doc grounding index.