gina 0.6.23 → 0.6.24

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 (595) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +12 -15
  3. package/ROADMAP.md +1 -0
  4. package/framework/v0.6.24/VERSION +1 -0
  5. package/framework/{v0.6.23 → v0.6.24}/core/connectors/couchbase/index.js +81 -41
  6. package/framework/{v0.6.23 → v0.6.24}/core/connectors/couchbase/lib/connector.v3.js +6 -2
  7. package/framework/{v0.6.23 → v0.6.24}/core/connectors/couchbase/lib/connector.v4.js +6 -2
  8. package/framework/{v0.6.23 → v0.6.24}/package.json +1 -1
  9. package/gna.js +4 -4
  10. package/llms.txt +3 -3
  11. package/package.json +3 -3
  12. package/framework/v0.6.23/VERSION +0 -1
  13. /package/framework/{v0.6.23 → v0.6.24}/AUTHORS +0 -0
  14. /package/framework/{v0.6.23 → v0.6.24}/LICENSE +0 -0
  15. /package/framework/{v0.6.23 → v0.6.24}/core/asset/html/nolayout.html +0 -0
  16. /package/framework/{v0.6.23 → v0.6.24}/core/asset/html/static.html +0 -0
  17. /package/framework/{v0.6.23 → v0.6.24}/core/asset/img/android-chrome-192x192.png +0 -0
  18. /package/framework/{v0.6.23 → v0.6.24}/core/asset/img/android-chrome-512x512.png +0 -0
  19. /package/framework/{v0.6.23 → v0.6.24}/core/asset/img/apple-touch-icon.png +0 -0
  20. /package/framework/{v0.6.23 → v0.6.24}/core/asset/img/favicon-16x16.png +0 -0
  21. /package/framework/{v0.6.23 → v0.6.24}/core/asset/img/favicon-32x32.png +0 -0
  22. /package/framework/{v0.6.23 → v0.6.24}/core/asset/img/favicon.ico +0 -0
  23. /package/framework/{v0.6.23 → v0.6.24}/core/asset/plugin/README.md +0 -0
  24. /package/framework/{v0.6.23 → v0.6.24}/core/asset/plugin/dist/vendor/gina/beemaster/beemaster.css +0 -0
  25. /package/framework/{v0.6.23 → v0.6.24}/core/asset/plugin/dist/vendor/gina/beemaster/beemaster.js +0 -0
  26. /package/framework/{v0.6.23 → v0.6.24}/core/asset/plugin/dist/vendor/gina/beemaster/index.html +0 -0
  27. /package/framework/{v0.6.23 → v0.6.24}/core/asset/plugin/dist/vendor/gina/css/gina.min.css +0 -0
  28. /package/framework/{v0.6.23 → v0.6.24}/core/asset/plugin/dist/vendor/gina/css/gina.min.css.br +0 -0
  29. /package/framework/{v0.6.23 → v0.6.24}/core/asset/plugin/dist/vendor/gina/css/gina.min.css.gz +0 -0
  30. /package/framework/{v0.6.23 → v0.6.24}/core/asset/plugin/dist/vendor/gina/html/statusbar.html +0 -0
  31. /package/framework/{v0.6.23 → v0.6.24}/core/asset/plugin/dist/vendor/gina/html/statusbar.html.br +0 -0
  32. /package/framework/{v0.6.23 → v0.6.24}/core/asset/plugin/dist/vendor/gina/html/statusbar.html.gz +0 -0
  33. /package/framework/{v0.6.23 → v0.6.24}/core/asset/plugin/dist/vendor/gina/inspector/have_heart_one-webfont.woff2 +0 -0
  34. /package/framework/{v0.6.23 → v0.6.24}/core/asset/plugin/dist/vendor/gina/inspector/index.html +0 -0
  35. /package/framework/{v0.6.23 → v0.6.24}/core/asset/plugin/dist/vendor/gina/inspector/inspector.css +0 -0
  36. /package/framework/{v0.6.23 → v0.6.24}/core/asset/plugin/dist/vendor/gina/inspector/inspector.js +0 -0
  37. /package/framework/{v0.6.23 → v0.6.24}/core/asset/plugin/dist/vendor/gina/inspector/logo.svg +0 -0
  38. /package/framework/{v0.6.23 → v0.6.24}/core/asset/plugin/dist/vendor/gina/js/gina.js +0 -0
  39. /package/framework/{v0.6.23 → v0.6.24}/core/asset/plugin/dist/vendor/gina/js/gina.min.js +0 -0
  40. /package/framework/{v0.6.23 → v0.6.24}/core/asset/plugin/dist/vendor/gina/js/gina.min.js.br +0 -0
  41. /package/framework/{v0.6.23 → v0.6.24}/core/asset/plugin/dist/vendor/gina/js/gina.min.js.gz +0 -0
  42. /package/framework/{v0.6.23 → v0.6.24}/core/asset/plugin/dist/vendor/gina/js/gina.onload.min.js +0 -0
  43. /package/framework/{v0.6.23 → v0.6.24}/core/asset/plugin/dist/vendor/gina/js/gina.onload.min.js.br +0 -0
  44. /package/framework/{v0.6.23 → v0.6.24}/core/asset/plugin/dist/vendor/gina/js/gina.onload.min.js.gz +0 -0
  45. /package/framework/{v0.6.23 → v0.6.24}/core/config.js +0 -0
  46. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/ai/index.js +0 -0
  47. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/ai/lib/connector.js +0 -0
  48. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/couchbase/lib/connector.js +0 -0
  49. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/couchbase/lib/n1ql.js +0 -0
  50. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/couchbase/lib/session-store.js +0 -0
  51. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/couchbase/lib/session-store.v3.js +0 -0
  52. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/couchbase/lib/session-store.v4.js +0 -0
  53. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/couchbase/lib/storage-store.js +0 -0
  54. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/duckdb/index.js +0 -0
  55. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/duckdb/lib/connector.js +0 -0
  56. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/mongodb/index.js +0 -0
  57. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/mongodb/lib/connector.js +0 -0
  58. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/mongodb/lib/job-store.js +0 -0
  59. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/mongodb/lib/pipeline-loader.js +0 -0
  60. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/mongodb/lib/session-store.js +0 -0
  61. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/mysql/index.js +0 -0
  62. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/mysql/lib/connector.js +0 -0
  63. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/param-redact.js +0 -0
  64. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/postgresql/index.js +0 -0
  65. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/postgresql/lib/connector.js +0 -0
  66. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/redis/index.js +0 -0
  67. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/redis/lib/connector.js +0 -0
  68. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/redis/lib/job-store.js +0 -0
  69. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/redis/lib/kv-store.js +0 -0
  70. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/redis/lib/render-cache-store.js +0 -0
  71. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/redis/lib/session-store.js +0 -0
  72. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/scylladb/index.js +0 -0
  73. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/scylladb/lib/connector.js +0 -0
  74. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/scylladb/lib/session-store.js +0 -0
  75. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/settle-once.js +0 -0
  76. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/sql-parser.js +0 -0
  77. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/sqlite/index.js +0 -0
  78. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/sqlite/lib/connector.js +0 -0
  79. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/sqlite/lib/job-store.js +0 -0
  80. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/sqlite/lib/kv-store.js +0 -0
  81. /package/framework/{v0.6.23 → v0.6.24}/core/connectors/sqlite/lib/session-store.js +0 -0
  82. /package/framework/{v0.6.23 → v0.6.24}/core/content.encoding +0 -0
  83. /package/framework/{v0.6.23 → v0.6.24}/core/controller/controller.framework.js +0 -0
  84. /package/framework/{v0.6.23 → v0.6.24}/core/controller/controller.js +0 -0
  85. /package/framework/{v0.6.23 → v0.6.24}/core/controller/controller.render-json.js +0 -0
  86. /package/framework/{v0.6.23 → v0.6.24}/core/controller/controller.render-nunjucks-async.js +0 -0
  87. /package/framework/{v0.6.23 → v0.6.24}/core/controller/controller.render-nunjucks.js +0 -0
  88. /package/framework/{v0.6.23 → v0.6.24}/core/controller/controller.render-stream.js +0 -0
  89. /package/framework/{v0.6.23 → v0.6.24}/core/controller/controller.render-swig-async.js +0 -0
  90. /package/framework/{v0.6.23 → v0.6.24}/core/controller/controller.render-swig.js +0 -0
  91. /package/framework/{v0.6.23 → v0.6.24}/core/controller/controller.render-v1.js +0 -0
  92. /package/framework/{v0.6.23 → v0.6.24}/core/controller/index.js +0 -0
  93. /package/framework/{v0.6.23 → v0.6.24}/core/controller/inline-script.js +0 -0
  94. /package/framework/{v0.6.23 → v0.6.24}/core/controller/inspector-window-emit.js +0 -0
  95. /package/framework/{v0.6.23 → v0.6.24}/core/controller/release-banner.js +0 -0
  96. /package/framework/{v0.6.23 → v0.6.24}/core/dev/index.js +0 -0
  97. /package/framework/{v0.6.23 → v0.6.24}/core/dev/lib/class.js +0 -0
  98. /package/framework/{v0.6.23 → v0.6.24}/core/dev/lib/factory.js +0 -0
  99. /package/framework/{v0.6.23 → v0.6.24}/core/dev/lib/tools.js +0 -0
  100. /package/framework/{v0.6.23 → v0.6.24}/core/gna.js +0 -0
  101. /package/framework/{v0.6.23 → v0.6.24}/core/locales/README.md +0 -0
  102. /package/framework/{v0.6.23 → v0.6.24}/core/locales/currency.json +0 -0
  103. /package/framework/{v0.6.23 → v0.6.24}/core/locales/dist/language/en.json +0 -0
  104. /package/framework/{v0.6.23 → v0.6.24}/core/locales/dist/language/fr.json +0 -0
  105. /package/framework/{v0.6.23 → v0.6.24}/core/locales/dist/region/en.json +0 -0
  106. /package/framework/{v0.6.23 → v0.6.24}/core/locales/dist/region/fr.json +0 -0
  107. /package/framework/{v0.6.23 → v0.6.24}/core/locales/index.js +0 -0
  108. /package/framework/{v0.6.23 → v0.6.24}/core/mime.types +0 -0
  109. /package/framework/{v0.6.23 → v0.6.24}/core/model/entity.js +0 -0
  110. /package/framework/{v0.6.23 → v0.6.24}/core/model/index.js +0 -0
  111. /package/framework/{v0.6.23 → v0.6.24}/core/model/template/entityFactory.js +0 -0
  112. /package/framework/{v0.6.23 → v0.6.24}/core/model/template/index.js +0 -0
  113. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/README.md +0 -0
  114. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/index.js +0 -0
  115. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/csrf/README.md +0 -0
  116. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/csrf/package.json +0 -0
  117. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/csrf/src/main.js +0 -0
  118. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/README.md +0 -0
  119. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/coep/README.md +0 -0
  120. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/coep/package.json +0 -0
  121. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/coep/src/main.js +0 -0
  122. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/coop/README.md +0 -0
  123. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/coop/package.json +0 -0
  124. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/coop/src/main.js +0 -0
  125. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/corp/README.md +0 -0
  126. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/corp/package.json +0 -0
  127. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/corp/src/main.js +0 -0
  128. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/csp/README.md +0 -0
  129. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/csp/package.json +0 -0
  130. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/csp/src/main.js +0 -0
  131. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/hide-powered-by/README.md +0 -0
  132. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/hide-powered-by/package.json +0 -0
  133. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/hide-powered-by/src/main.js +0 -0
  134. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/hsts/README.md +0 -0
  135. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/hsts/package.json +0 -0
  136. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/hsts/src/main.js +0 -0
  137. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/origin-agent-cluster/README.md +0 -0
  138. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/origin-agent-cluster/package.json +0 -0
  139. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/origin-agent-cluster/src/main.js +0 -0
  140. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/package.json +0 -0
  141. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/referrer-policy/README.md +0 -0
  142. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/referrer-policy/package.json +0 -0
  143. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/referrer-policy/src/main.js +0 -0
  144. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/src/main.js +0 -0
  145. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/x-content-type-options/README.md +0 -0
  146. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/x-content-type-options/package.json +0 -0
  147. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/x-content-type-options/src/main.js +0 -0
  148. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/x-dns-prefetch-control/README.md +0 -0
  149. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/x-dns-prefetch-control/package.json +0 -0
  150. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/x-dns-prefetch-control/src/main.js +0 -0
  151. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/x-download-options/README.md +0 -0
  152. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/x-download-options/package.json +0 -0
  153. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/x-download-options/src/main.js +0 -0
  154. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/x-frame-options/README.md +0 -0
  155. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/x-frame-options/package.json +0 -0
  156. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/x-frame-options/src/main.js +0 -0
  157. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/x-permitted-cross-domain-policies/README.md +0 -0
  158. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/x-permitted-cross-domain-policies/package.json +0 -0
  159. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/x-permitted-cross-domain-policies/src/main.js +0 -0
  160. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/x-xss-protection/README.md +0 -0
  161. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/x-xss-protection/package.json +0 -0
  162. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/security-headers/x-xss-protection/src/main.js +0 -0
  163. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/session/README.md +0 -0
  164. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/session/package.json +0 -0
  165. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/session/src/main.js +0 -0
  166. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/storage/README.md +0 -0
  167. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/storage/build.json +0 -0
  168. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/storage/package.json +0 -0
  169. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/storage/src/main.js +0 -0
  170. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/validator/README.md +0 -0
  171. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/validator/build.json +0 -0
  172. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/validator/package.json +0 -0
  173. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/validator/src/form-validator.js +0 -0
  174. /package/framework/{v0.6.23 → v0.6.24}/core/plugins/lib/validator/src/main.js +0 -0
  175. /package/framework/{v0.6.23 → v0.6.24}/core/router.js +0 -0
  176. /package/framework/{v0.6.23 → v0.6.24}/core/server.express.js +0 -0
  177. /package/framework/{v0.6.23 → v0.6.24}/core/server.isaac.js +0 -0
  178. /package/framework/{v0.6.23 → v0.6.24}/core/server.js +0 -0
  179. /package/framework/{v0.6.23 → v0.6.24}/core/status.codes +0 -0
  180. /package/framework/{v0.6.23 → v0.6.24}/core/template/_gitignore +0 -0
  181. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle/config/app.json +0 -0
  182. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle/config/connectors.json +0 -0
  183. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle/config/routing.json +0 -0
  184. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle/config/settings.json +0 -0
  185. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle/config/settings.server.json +0 -0
  186. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle/config/templates.json +0 -0
  187. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle/config/watchers.json +0 -0
  188. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle/controllers/controller.content.js +0 -0
  189. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle/controllers/controller.js +0 -0
  190. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle/controllers/setup.js +0 -0
  191. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle/index.js +0 -0
  192. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle/locales/en.json +0 -0
  193. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle_namespace/controllers/controller.js +0 -0
  194. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle_public/css/default.css +0 -0
  195. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle_public/css/home.css +0 -0
  196. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle_public/css/vendor/readme.md +0 -0
  197. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle_public/favicon.ico +0 -0
  198. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle_public/js/components/x-checklist.js +0 -0
  199. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle_public/js/vendor/readme.md +0 -0
  200. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle_public/manifest.webmanifest +0 -0
  201. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle_public/readme.md +0 -0
  202. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle_public/sw.js +0 -0
  203. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle_templates/handlers/main.js +0 -0
  204. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle_templates/html/content/homepage.html +0 -0
  205. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle_templates/html/includes/error-msg-noscript.html +0 -0
  206. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle_templates/html/includes/error-msg-outdated-browser.html +0 -0
  207. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle_templates/html/includes/x-checklist.html +0 -0
  208. /package/framework/{v0.6.23 → v0.6.24}/core/template/boilerplate/bundle_templates/html/layouts/main.html +0 -0
  209. /package/framework/{v0.6.23 → v0.6.24}/core/template/command/gina.bat.tpl +0 -0
  210. /package/framework/{v0.6.23 → v0.6.24}/core/template/command/gina.tpl +0 -0
  211. /package/framework/{v0.6.23 → v0.6.24}/core/template/conf/env.json +0 -0
  212. /package/framework/{v0.6.23 → v0.6.24}/core/template/conf/manifest.json +0 -0
  213. /package/framework/{v0.6.23 → v0.6.24}/core/template/conf/package.json +0 -0
  214. /package/framework/{v0.6.23 → v0.6.24}/core/template/conf/settings.json +0 -0
  215. /package/framework/{v0.6.23 → v0.6.24}/core/template/conf/statics.json +0 -0
  216. /package/framework/{v0.6.23 → v0.6.24}/core/template/conf/templates.json +0 -0
  217. /package/framework/{v0.6.23 → v0.6.24}/core/template/error/client/json/401.json +0 -0
  218. /package/framework/{v0.6.23 → v0.6.24}/core/template/error/client/json/403.json +0 -0
  219. /package/framework/{v0.6.23 → v0.6.24}/core/template/error/client/json/404.json +0 -0
  220. /package/framework/{v0.6.23 → v0.6.24}/core/template/error/server/html/50x.html +0 -0
  221. /package/framework/{v0.6.23 → v0.6.24}/core/template/error/server/json/500.json +0 -0
  222. /package/framework/{v0.6.23 → v0.6.24}/core/template/error/server/json/503.json +0 -0
  223. /package/framework/{v0.6.23 → v0.6.24}/core/template/extensions/logger/config.json +0 -0
  224. /package/framework/{v0.6.23 → v0.6.24}/helpers/console.js +0 -0
  225. /package/framework/{v0.6.23 → v0.6.24}/helpers/context.js +0 -0
  226. /package/framework/{v0.6.23 → v0.6.24}/helpers/data/LICENSE +0 -0
  227. /package/framework/{v0.6.23 → v0.6.24}/helpers/data/README.md +0 -0
  228. /package/framework/{v0.6.23 → v0.6.24}/helpers/data/package.json +0 -0
  229. /package/framework/{v0.6.23 → v0.6.24}/helpers/data/src/main.js +0 -0
  230. /package/framework/{v0.6.23 → v0.6.24}/helpers/dateFormat.js +0 -0
  231. /package/framework/{v0.6.23 → v0.6.24}/helpers/index.js +0 -0
  232. /package/framework/{v0.6.23 → v0.6.24}/helpers/json/LICENSE +0 -0
  233. /package/framework/{v0.6.23 → v0.6.24}/helpers/json/README.md +0 -0
  234. /package/framework/{v0.6.23 → v0.6.24}/helpers/json/package.json +0 -0
  235. /package/framework/{v0.6.23 → v0.6.24}/helpers/json/src/main.js +0 -0
  236. /package/framework/{v0.6.23 → v0.6.24}/helpers/path.js +0 -0
  237. /package/framework/{v0.6.23 → v0.6.24}/helpers/plugins/README.md +0 -0
  238. /package/framework/{v0.6.23 → v0.6.24}/helpers/plugins/package.json +0 -0
  239. /package/framework/{v0.6.23 → v0.6.24}/helpers/plugins/src/api-error.js +0 -0
  240. /package/framework/{v0.6.23 → v0.6.24}/helpers/plugins/src/main.js +0 -0
  241. /package/framework/{v0.6.23 → v0.6.24}/helpers/prototypes.js +0 -0
  242. /package/framework/{v0.6.23 → v0.6.24}/helpers/task.js +0 -0
  243. /package/framework/{v0.6.23 → v0.6.24}/helpers/text.js +0 -0
  244. /package/framework/{v0.6.23 → v0.6.24}/lib/admin/package.json +0 -0
  245. /package/framework/{v0.6.23 → v0.6.24}/lib/admin/src/main.js +0 -0
  246. /package/framework/{v0.6.23 → v0.6.24}/lib/archiver/README.md +0 -0
  247. /package/framework/{v0.6.23 → v0.6.24}/lib/archiver/build.json +0 -0
  248. /package/framework/{v0.6.23 → v0.6.24}/lib/archiver/package.json +0 -0
  249. /package/framework/{v0.6.23 → v0.6.24}/lib/archiver/src/dep/jszip.min.js +0 -0
  250. /package/framework/{v0.6.23 → v0.6.24}/lib/archiver/src/main.js +0 -0
  251. /package/framework/{v0.6.23 → v0.6.24}/lib/async/package.json +0 -0
  252. /package/framework/{v0.6.23 → v0.6.24}/lib/async/src/main.js +0 -0
  253. /package/framework/{v0.6.23 → v0.6.24}/lib/audit/package.json +0 -0
  254. /package/framework/{v0.6.23 → v0.6.24}/lib/audit/src/main.js +0 -0
  255. /package/framework/{v0.6.23 → v0.6.24}/lib/audit-store.js +0 -0
  256. /package/framework/{v0.6.23 → v0.6.24}/lib/authn/package.json +0 -0
  257. /package/framework/{v0.6.23 → v0.6.24}/lib/authn/src/lockout.js +0 -0
  258. /package/framework/{v0.6.23 → v0.6.24}/lib/authn/src/main.js +0 -0
  259. /package/framework/{v0.6.23 → v0.6.24}/lib/authn/src/totp.js +0 -0
  260. /package/framework/{v0.6.23 → v0.6.24}/lib/authz-gate/package.json +0 -0
  261. /package/framework/{v0.6.23 → v0.6.24}/lib/authz-gate/src/main.js +0 -0
  262. /package/framework/{v0.6.23 → v0.6.24}/lib/cache/README.md +0 -0
  263. /package/framework/{v0.6.23 → v0.6.24}/lib/cache/build.json +0 -0
  264. /package/framework/{v0.6.23 → v0.6.24}/lib/cache/package.json +0 -0
  265. /package/framework/{v0.6.23 → v0.6.24}/lib/cache/src/main.js +0 -0
  266. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/aliases.json +0 -0
  267. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/audit/arguments.json +0 -0
  268. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/audit/help.txt +0 -0
  269. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/audit/verify.js +0 -0
  270. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/bundle/add.js +0 -0
  271. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/bundle/arguments.json +0 -0
  272. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/bundle/build.js +0 -0
  273. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/bundle/copy.js +0 -0
  274. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/bundle/cp.js +0 -0
  275. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/bundle/help.js +0 -0
  276. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/bundle/help.txt +0 -0
  277. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/bundle/inc/name-rewrite.js +0 -0
  278. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/bundle/list.js +0 -0
  279. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/bundle/man.js +0 -0
  280. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/bundle/mcp-start.js +0 -0
  281. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/bundle/mcp.js +0 -0
  282. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/bundle/oas.js +0 -0
  283. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/bundle/openapi.js +0 -0
  284. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/bundle/remove.js +0 -0
  285. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/bundle/rename.js +0 -0
  286. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/bundle/restart.js +0 -0
  287. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/bundle/rm.js +0 -0
  288. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/bundle/start.js +0 -0
  289. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/bundle/status.js +0 -0
  290. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/bundle/stop.js +0 -0
  291. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/bundle/types.js +0 -0
  292. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/cache/arguments.json +0 -0
  293. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/cache/clear.js +0 -0
  294. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/cache/help.txt +0 -0
  295. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/cache/stats.js +0 -0
  296. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/connector/add.js +0 -0
  297. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/connector/arguments.json +0 -0
  298. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/connector/help.js +0 -0
  299. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/connector/help.txt +0 -0
  300. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/connector/infer.js +0 -0
  301. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/connector/list.js +0 -0
  302. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/connector/migrate.js +0 -0
  303. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/connector/models.js +0 -0
  304. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/connector/remove.js +0 -0
  305. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/connector/rm.js +0 -0
  306. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/connector/test.js +0 -0
  307. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/container/arguments.json +0 -0
  308. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/container/help.js +0 -0
  309. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/container/help.txt +0 -0
  310. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/container/man.js +0 -0
  311. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/container/ps.js +0 -0
  312. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/container/stop.js +0 -0
  313. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/controller/add.js +0 -0
  314. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/controller/arguments.json +0 -0
  315. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/controller/help.txt +0 -0
  316. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/controller/inc/args.js +0 -0
  317. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/controller/inc/namespace.js +0 -0
  318. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/controller/inc/reference-rewrite.js +0 -0
  319. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/controller/inc/reference-scan.js +0 -0
  320. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/controller/inc/scaffold.js +0 -0
  321. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/controller/remove.js +0 -0
  322. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/controller/rename.js +0 -0
  323. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/controller/rm.js +0 -0
  324. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/env/add.js +0 -0
  325. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/env/get.js +0 -0
  326. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/env/help.js +0 -0
  327. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/env/help.txt +0 -0
  328. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/env/link-dev.js +0 -0
  329. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/env/list.js +0 -0
  330. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/env/remove.js +0 -0
  331. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/env/rm.js +0 -0
  332. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/env/set.js +0 -0
  333. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/env/unset.js +0 -0
  334. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/env/use.js +0 -0
  335. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/framework/add.js +0 -0
  336. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/framework/arguments.json +0 -0
  337. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/framework/build.js +0 -0
  338. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/framework/dot.js +0 -0
  339. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/framework/get.js +0 -0
  340. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/framework/help.js +0 -0
  341. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/framework/help.txt +0 -0
  342. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/framework/init.js +0 -0
  343. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/framework/link-node-modules.js +0 -0
  344. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/framework/link.js +0 -0
  345. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/framework/list.js +0 -0
  346. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/framework/man.js +0 -0
  347. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/framework/msg.json +0 -0
  348. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/framework/open.js +0 -0
  349. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/framework/remove.js +0 -0
  350. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/framework/reset.js +0 -0
  351. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/framework/restart.js +0 -0
  352. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/framework/set.js +0 -0
  353. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/framework/start.js +0 -0
  354. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/framework/status.js +0 -0
  355. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/framework/stop.js +0 -0
  356. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/framework/tail.js +0 -0
  357. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/framework/update.js +0 -0
  358. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/framework/version.js +0 -0
  359. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/gina-dev.1.md +0 -0
  360. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/gina-framework.1.md +0 -0
  361. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/gina.1.md +0 -0
  362. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/helper.js +0 -0
  363. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/i18n/add.js +0 -0
  364. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/i18n/arguments.json +0 -0
  365. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/i18n/export.js +0 -0
  366. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/i18n/help.js +0 -0
  367. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/i18n/help.txt +0 -0
  368. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/i18n/import.js +0 -0
  369. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/i18n/scan.js +0 -0
  370. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/image/_host.js +0 -0
  371. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/image/arguments.json +0 -0
  372. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/image/build.js +0 -0
  373. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/image/help.js +0 -0
  374. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/image/help.txt +0 -0
  375. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/image/list.js +0 -0
  376. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/image/man.js +0 -0
  377. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/image/rm.js +0 -0
  378. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/image/run.js +0 -0
  379. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/index.js +0 -0
  380. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/inspector/help.js +0 -0
  381. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/inspector/help.txt +0 -0
  382. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/inspector/open.js +0 -0
  383. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/man-render.js +0 -0
  384. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/minion/arguments.json +0 -0
  385. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/minion/help.js +0 -0
  386. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/minion/help.txt +0 -0
  387. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/minion/kill.js +0 -0
  388. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/minion/list.js +0 -0
  389. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/msg.json +0 -0
  390. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/port/help.js +0 -0
  391. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/port/help.txt +0 -0
  392. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/port/inc/scan.js +0 -0
  393. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/port/list.js +0 -0
  394. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/port/reset.js +0 -0
  395. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/port/set.js +0 -0
  396. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/project/add.js +0 -0
  397. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/project/arguments.json +0 -0
  398. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/project/backup.js +0 -0
  399. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/project/build.js +0 -0
  400. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/project/help.js +0 -0
  401. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/project/help.txt +0 -0
  402. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/project/import.js +0 -0
  403. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/project/list.js +0 -0
  404. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/project/man.js +0 -0
  405. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/project/move.js +0 -0
  406. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/project/remove.js +0 -0
  407. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/project/rename.js +0 -0
  408. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/project/restart.js +0 -0
  409. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/project/restore.js +0 -0
  410. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/project/rm.js +0 -0
  411. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/project/start.js +0 -0
  412. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/project/status.js +0 -0
  413. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/project/stop.js +0 -0
  414. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/protocol/arguments.json +0 -0
  415. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/protocol/help.js +0 -0
  416. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/protocol/help.txt +0 -0
  417. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/protocol/list.js +0 -0
  418. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/protocol/remove.js +0 -0
  419. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/protocol/set.js +0 -0
  420. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/scope/add.js +0 -0
  421. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/scope/help.js +0 -0
  422. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/scope/help.txt +0 -0
  423. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/scope/link-local.js +0 -0
  424. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/scope/link-production.js +0 -0
  425. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/scope/list.js +0 -0
  426. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/scope/remove.js +0 -0
  427. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/scope/rm.js +0 -0
  428. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/scope/use.js +0 -0
  429. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/secrets/arguments.json +0 -0
  430. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/secrets/check.js +0 -0
  431. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/secrets/help.js +0 -0
  432. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/secrets/help.txt +0 -0
  433. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/secrets/scan.js +0 -0
  434. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/service/help.js +0 -0
  435. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/service/help.txt +0 -0
  436. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/service/list.js +0 -0
  437. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/service/man.js +0 -0
  438. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/service/start.js +0 -0
  439. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/storage/arguments.json +0 -0
  440. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/storage/gc.js +0 -0
  441. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/storage/help.txt +0 -0
  442. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/storage/stats.js +0 -0
  443. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/storage/verify.js +0 -0
  444. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd/view/add.js +0 -0
  445. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd-status-format/package.json +0 -0
  446. /package/framework/{v0.6.23 → v0.6.24}/lib/cmd-status-format/src/main.js +0 -0
  447. /package/framework/{v0.6.23 → v0.6.24}/lib/collection/README.md +0 -0
  448. /package/framework/{v0.6.23 → v0.6.24}/lib/collection/build.json +0 -0
  449. /package/framework/{v0.6.23 → v0.6.24}/lib/collection/package.json +0 -0
  450. /package/framework/{v0.6.23 → v0.6.24}/lib/collection/src/main.js +0 -0
  451. /package/framework/{v0.6.23 → v0.6.24}/lib/config.js +0 -0
  452. /package/framework/{v0.6.23 → v0.6.24}/lib/connector-config/package.json +0 -0
  453. /package/framework/{v0.6.23 → v0.6.24}/lib/connector-config/src/main.js +0 -0
  454. /package/framework/{v0.6.23 → v0.6.24}/lib/connector-error/package.json +0 -0
  455. /package/framework/{v0.6.23 → v0.6.24}/lib/connector-error/src/main.js +0 -0
  456. /package/framework/{v0.6.23 → v0.6.24}/lib/connector-registry/package.json +0 -0
  457. /package/framework/{v0.6.23 → v0.6.24}/lib/connector-registry/src/main.js +0 -0
  458. /package/framework/{v0.6.23 → v0.6.24}/lib/cron/README.md +0 -0
  459. /package/framework/{v0.6.23 → v0.6.24}/lib/cron/package.json +0 -0
  460. /package/framework/{v0.6.23 → v0.6.24}/lib/cron/src/main.js +0 -0
  461. /package/framework/{v0.6.23 → v0.6.24}/lib/domain/LICENSE +0 -0
  462. /package/framework/{v0.6.23 → v0.6.24}/lib/domain/README.md +0 -0
  463. /package/framework/{v0.6.23 → v0.6.24}/lib/domain/package.json +0 -0
  464. /package/framework/{v0.6.23 → v0.6.24}/lib/domain/src/main.js +0 -0
  465. /package/framework/{v0.6.23 → v0.6.24}/lib/dto/package.json +0 -0
  466. /package/framework/{v0.6.23 → v0.6.24}/lib/dto/src/main.js +0 -0
  467. /package/framework/{v0.6.23 → v0.6.24}/lib/dto-pipe/package.json +0 -0
  468. /package/framework/{v0.6.23 → v0.6.24}/lib/dto-pipe/src/main.js +0 -0
  469. /package/framework/{v0.6.23 → v0.6.24}/lib/dto-types/package.json +0 -0
  470. /package/framework/{v0.6.23 → v0.6.24}/lib/dto-types/src/main.js +0 -0
  471. /package/framework/{v0.6.23 → v0.6.24}/lib/generator/index.js +0 -0
  472. /package/framework/{v0.6.23 → v0.6.24}/lib/i18n/package.json +0 -0
  473. /package/framework/{v0.6.23 → v0.6.24}/lib/i18n/src/main.js +0 -0
  474. /package/framework/{v0.6.23 → v0.6.24}/lib/image-build/package.json +0 -0
  475. /package/framework/{v0.6.23 → v0.6.24}/lib/image-build/src/main.js +0 -0
  476. /package/framework/{v0.6.23 → v0.6.24}/lib/index.js +0 -0
  477. /package/framework/{v0.6.23 → v0.6.24}/lib/inherits/LICENSE +0 -0
  478. /package/framework/{v0.6.23 → v0.6.24}/lib/inherits/README.md +0 -0
  479. /package/framework/{v0.6.23 → v0.6.24}/lib/inherits/package.json +0 -0
  480. /package/framework/{v0.6.23 → v0.6.24}/lib/inherits/src/main.js +0 -0
  481. /package/framework/{v0.6.23 → v0.6.24}/lib/inspector-events/package.json +0 -0
  482. /package/framework/{v0.6.23 → v0.6.24}/lib/inspector-events/src/main.js +0 -0
  483. /package/framework/{v0.6.23 → v0.6.24}/lib/inspector-redact/package.json +0 -0
  484. /package/framework/{v0.6.23 → v0.6.24}/lib/inspector-redact/src/main.js +0 -0
  485. /package/framework/{v0.6.23 → v0.6.24}/lib/instrument/package.json +0 -0
  486. /package/framework/{v0.6.23 → v0.6.24}/lib/instrument/src/main.js +0 -0
  487. /package/framework/{v0.6.23 → v0.6.24}/lib/job/package.json +0 -0
  488. /package/framework/{v0.6.23 → v0.6.24}/lib/job/src/main.js +0 -0
  489. /package/framework/{v0.6.23 → v0.6.24}/lib/job-store.js +0 -0
  490. /package/framework/{v0.6.23 → v0.6.24}/lib/json-config-header/package.json +0 -0
  491. /package/framework/{v0.6.23 → v0.6.24}/lib/json-config-header/src/main.js +0 -0
  492. /package/framework/{v0.6.23 → v0.6.24}/lib/kv/package.json +0 -0
  493. /package/framework/{v0.6.23 → v0.6.24}/lib/kv/src/main.js +0 -0
  494. /package/framework/{v0.6.23 → v0.6.24}/lib/kv-store.js +0 -0
  495. /package/framework/{v0.6.23 → v0.6.24}/lib/loading-state/package.json +0 -0
  496. /package/framework/{v0.6.23 → v0.6.24}/lib/loading-state/src/main.js +0 -0
  497. /package/framework/{v0.6.23 → v0.6.24}/lib/logger/README.md +0 -0
  498. /package/framework/{v0.6.23 → v0.6.24}/lib/logger/package.json +0 -0
  499. /package/framework/{v0.6.23 → v0.6.24}/lib/logger/src/containers/default/index.js +0 -0
  500. /package/framework/{v0.6.23 → v0.6.24}/lib/logger/src/containers/file/index.js +0 -0
  501. /package/framework/{v0.6.23 → v0.6.24}/lib/logger/src/containers/file/lib/logrotator/README.md +0 -0
  502. /package/framework/{v0.6.23 → v0.6.24}/lib/logger/src/containers/file/lib/logrotator/index.js +0 -0
  503. /package/framework/{v0.6.23 → v0.6.24}/lib/logger/src/containers/mq/index.js +0 -0
  504. /package/framework/{v0.6.23 → v0.6.24}/lib/logger/src/containers/mq/listener.js +0 -0
  505. /package/framework/{v0.6.23 → v0.6.24}/lib/logger/src/containers/mq/speaker.js +0 -0
  506. /package/framework/{v0.6.23 → v0.6.24}/lib/logger/src/helper.js +0 -0
  507. /package/framework/{v0.6.23 → v0.6.24}/lib/logger/src/main.js +0 -0
  508. /package/framework/{v0.6.23 → v0.6.24}/lib/logger/src/redact.js +0 -0
  509. /package/framework/{v0.6.23 → v0.6.24}/lib/maintenance/package.json +0 -0
  510. /package/framework/{v0.6.23 → v0.6.24}/lib/maintenance/src/main.js +0 -0
  511. /package/framework/{v0.6.23 → v0.6.24}/lib/math/index.js +0 -0
  512. /package/framework/{v0.6.23 → v0.6.24}/lib/mcp-dispatch/package.json +0 -0
  513. /package/framework/{v0.6.23 → v0.6.24}/lib/mcp-dispatch/src/main.js +0 -0
  514. /package/framework/{v0.6.23 → v0.6.24}/lib/mcp-http/package.json +0 -0
  515. /package/framework/{v0.6.23 → v0.6.24}/lib/mcp-http/src/main.js +0 -0
  516. /package/framework/{v0.6.23 → v0.6.24}/lib/mcp-server/package.json +0 -0
  517. /package/framework/{v0.6.23 → v0.6.24}/lib/mcp-server/src/main.js +0 -0
  518. /package/framework/{v0.6.23 → v0.6.24}/lib/merge/README.md +0 -0
  519. /package/framework/{v0.6.23 → v0.6.24}/lib/merge/package.json +0 -0
  520. /package/framework/{v0.6.23 → v0.6.24}/lib/merge/src/main.js +0 -0
  521. /package/framework/{v0.6.23 → v0.6.24}/lib/metrics/package.json +0 -0
  522. /package/framework/{v0.6.23 → v0.6.24}/lib/metrics/src/main.js +0 -0
  523. /package/framework/{v0.6.23 → v0.6.24}/lib/model.js +0 -0
  524. /package/framework/{v0.6.23 → v0.6.24}/lib/net-locality/package.json +0 -0
  525. /package/framework/{v0.6.23 → v0.6.24}/lib/net-locality/src/main.js +0 -0
  526. /package/framework/{v0.6.23 → v0.6.24}/lib/nunjucks-filters/README.md +0 -0
  527. /package/framework/{v0.6.23 → v0.6.24}/lib/nunjucks-filters/package.json +0 -0
  528. /package/framework/{v0.6.23 → v0.6.24}/lib/nunjucks-filters/src/main.js +0 -0
  529. /package/framework/{v0.6.23 → v0.6.24}/lib/nunjucks-resolver/package.json +0 -0
  530. /package/framework/{v0.6.23 → v0.6.24}/lib/nunjucks-resolver/src/main.js +0 -0
  531. /package/framework/{v0.6.23 → v0.6.24}/lib/proc.js +0 -0
  532. /package/framework/{v0.6.23 → v0.6.24}/lib/push/package.json +0 -0
  533. /package/framework/{v0.6.23 → v0.6.24}/lib/push/src/main.js +0 -0
  534. /package/framework/{v0.6.23 → v0.6.24}/lib/rate-limit/package.json +0 -0
  535. /package/framework/{v0.6.23 → v0.6.24}/lib/rate-limit/src/main.js +0 -0
  536. /package/framework/{v0.6.23 → v0.6.24}/lib/release-watch/package.json +0 -0
  537. /package/framework/{v0.6.23 → v0.6.24}/lib/release-watch/src/main.js +0 -0
  538. /package/framework/{v0.6.23 → v0.6.24}/lib/render-cache/package.json +0 -0
  539. /package/framework/{v0.6.23 → v0.6.24}/lib/render-cache/src/main.js +0 -0
  540. /package/framework/{v0.6.23 → v0.6.24}/lib/render-cache-store.js +0 -0
  541. /package/framework/{v0.6.23 → v0.6.24}/lib/routing/README.md +0 -0
  542. /package/framework/{v0.6.23 → v0.6.24}/lib/routing/build.json +0 -0
  543. /package/framework/{v0.6.23 → v0.6.24}/lib/routing/package.json +0 -0
  544. /package/framework/{v0.6.23 → v0.6.24}/lib/routing/src/main.js +0 -0
  545. /package/framework/{v0.6.23 → v0.6.24}/lib/routing/src/radix.js +0 -0
  546. /package/framework/{v0.6.23 → v0.6.24}/lib/routing-introspect/package.json +0 -0
  547. /package/framework/{v0.6.23 → v0.6.24}/lib/routing-introspect/src/main.js +0 -0
  548. /package/framework/{v0.6.23 → v0.6.24}/lib/secrets/package.json +0 -0
  549. /package/framework/{v0.6.23 → v0.6.24}/lib/secrets/src/backends/env.js +0 -0
  550. /package/framework/{v0.6.23 → v0.6.24}/lib/secrets/src/backends/exec.js +0 -0
  551. /package/framework/{v0.6.23 → v0.6.24}/lib/secrets/src/backends/file.js +0 -0
  552. /package/framework/{v0.6.23 → v0.6.24}/lib/secrets/src/declaration.js +0 -0
  553. /package/framework/{v0.6.23 → v0.6.24}/lib/secrets/src/env-file.js +0 -0
  554. /package/framework/{v0.6.23 → v0.6.24}/lib/secrets/src/main.js +0 -0
  555. /package/framework/{v0.6.23 → v0.6.24}/lib/secrets/src/sources.js +0 -0
  556. /package/framework/{v0.6.23 → v0.6.24}/lib/security-headers-emitter/package.json +0 -0
  557. /package/framework/{v0.6.23 → v0.6.24}/lib/security-headers-emitter/src/main.js +0 -0
  558. /package/framework/{v0.6.23 → v0.6.24}/lib/session-store.js +0 -0
  559. /package/framework/{v0.6.23 → v0.6.24}/lib/shell.js +0 -0
  560. /package/framework/{v0.6.23 → v0.6.24}/lib/sqlite-driver.js +0 -0
  561. /package/framework/{v0.6.23 → v0.6.24}/lib/sri/package.json +0 -0
  562. /package/framework/{v0.6.23 → v0.6.24}/lib/sri/src/main.js +0 -0
  563. /package/framework/{v0.6.23 → v0.6.24}/lib/state.js +0 -0
  564. /package/framework/{v0.6.23 → v0.6.24}/lib/storage/package.json +0 -0
  565. /package/framework/{v0.6.23 → v0.6.24}/lib/storage/src/local-cas.js +0 -0
  566. /package/framework/{v0.6.23 → v0.6.24}/lib/storage/src/local-stream.js +0 -0
  567. /package/framework/{v0.6.23 → v0.6.24}/lib/storage/src/local.js +0 -0
  568. /package/framework/{v0.6.23 → v0.6.24}/lib/storage/src/main.js +0 -0
  569. /package/framework/{v0.6.23 → v0.6.24}/lib/storage/src/meta-store.js +0 -0
  570. /package/framework/{v0.6.23 → v0.6.24}/lib/storage/src/s3.js +0 -0
  571. /package/framework/{v0.6.23 → v0.6.24}/lib/storage/src/util.js +0 -0
  572. /package/framework/{v0.6.23 → v0.6.24}/lib/storage-store.js +0 -0
  573. /package/framework/{v0.6.23 → v0.6.24}/lib/swig-filters/README.md +0 -0
  574. /package/framework/{v0.6.23 → v0.6.24}/lib/swig-filters/package.json +0 -0
  575. /package/framework/{v0.6.23 → v0.6.24}/lib/swig-filters/src/main.js +0 -0
  576. /package/framework/{v0.6.23 → v0.6.24}/lib/swig-resolver/package.json +0 -0
  577. /package/framework/{v0.6.23 → v0.6.24}/lib/swig-resolver/src/main.js +0 -0
  578. /package/framework/{v0.6.23 → v0.6.24}/lib/template-loaders/package.json +0 -0
  579. /package/framework/{v0.6.23 → v0.6.24}/lib/template-loaders/src/loaders/http.js +0 -0
  580. /package/framework/{v0.6.23 → v0.6.24}/lib/template-loaders/src/loaders/memory.js +0 -0
  581. /package/framework/{v0.6.23 → v0.6.24}/lib/template-loaders/src/main.js +0 -0
  582. /package/framework/{v0.6.23 → v0.6.24}/lib/url/README.md +0 -0
  583. /package/framework/{v0.6.23 → v0.6.24}/lib/url/index.js +0 -0
  584. /package/framework/{v0.6.23 → v0.6.24}/lib/url/routing.json +0 -0
  585. /package/framework/{v0.6.23 → v0.6.24}/lib/uuid/package.json +0 -0
  586. /package/framework/{v0.6.23 → v0.6.24}/lib/uuid/src/main.js +0 -0
  587. /package/framework/{v0.6.23 → v0.6.24}/lib/validator.js +0 -0
  588. /package/framework/{v0.6.23 → v0.6.24}/lib/watcher/package.json +0 -0
  589. /package/framework/{v0.6.23 → v0.6.24}/lib/watcher/src/main.js +0 -0
  590. /package/framework/{v0.6.23 → v0.6.24}/lib/ws-framing/package.json +0 -0
  591. /package/framework/{v0.6.23 → v0.6.24}/lib/ws-framing/src/main.js +0 -0
  592. /package/framework/{v0.6.23 → v0.6.24}/lib/ws-query/package.json +0 -0
  593. /package/framework/{v0.6.23 → v0.6.24}/lib/ws-query/src/main.js +0 -0
  594. /package/framework/{v0.6.23 → v0.6.24}/lib/ws-session/package.json +0 -0
  595. /package/framework/{v0.6.23 → v0.6.24}/lib/ws-session/src/main.js +0 -0
package/CHANGELOG.md CHANGED
@@ -6,6 +6,12 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
6
6
  and is generated by [Changie](https://github.com/miniscruff/changie).
7
7
 
8
8
 
9
+ ## 0.6.24 - 2026-09-02
10
+ ### Fixed
11
+ * Couchbase `bulkInsert` no longer returns `undefined` when its own prologue throws. Its outer `try` wraps the method body, so a synchronous failure — a connection that cannot be resolved, or either of the two deliberate `rec` validations — was caught, logged to `console.error` and then swallowed, and the method fell off the end. Both documented call shapes broke on that path: the `await` form (the first `@example` in its own docblock) resolved with `undefined`, so a caller treating "did not throw" as success recorded an insert that never happened, and the `.onComplete(cb)` form threw a TypeError on `undefined`. In both, the error existed only in the log and was unreachable to the caller. The promise, its one-shot resolver and the `.onComplete` shim are now built before the `try`, so the outer catch settles this call instead: `.onComplete(cb)` receives `(err)` and the promise rejects. The `_settled` latch means a late throw cannot double-settle, and the happy path is unchanged. Note that a fire-and-forget call that ignores the return will now surface an unhandled rejection where it previously failed silently. **Scope, and it matters if you documented the old behaviour:** this changes what `bulkInsert` RETURNS, not what its promise RESOLVES WITH. A rows-less success still settles as `null`, so a non-rejection is still not proof that rows were inserted — keep any rows-based success check you have, and re-read any comment or guard whose premise was the old return-`undefined` behaviour: the premise goes stale while the conclusion usually stays correct. (#B460)
12
+ * A Couchbase entity that fails to register now says so, naming itself. `readSource()` guards the whole entity-class construction and `.sql`-derived method attachment under one try, and its catch emitted only a bare stack — while none of its three call sites captures a result or takes an error argument. A throw there therefore left the entity partially built, or absent, with nothing in the log identifying which entity or which `.sql` file was responsible; the first symptom was a missing method at request time, arbitrarily far from the cause. The catch now emits a named diagnostic carrying the entity, the source file, the method being attached and the underlying cause, and still emits the original stack. Boot behaviour is deliberately unchanged: registration failures remain non-fatal, since making an unbuildable entity fatal would stop projects that boot through a swallowed error today. (#B461)
13
+ * The Couchbase reconnect classifier no longer throws under every supported SDK. `gina.onError`'s handler tested `err instanceof couchbase.Error`, but no supported couchnode (3.x/4.x) exports a bare `Error` class — verified against a real 4.1.3 `dist/errors.js`, where `Error` is undefined while `CouchbaseError` and 81 sibling classes are present — so the check raised `TypeError: Right-hand side of 'instanceof' is not an object` the moment the handler ran, and because that operand is evaluated first, the shutdown-bucket message arm (which needs no SDK class) was unreachable too. On the Express engine this replaced the real error with the TypeError in subsequent handling; on Isaac the listener is never dispatched at all (middlewares are invoked 3-arg, so the error branch that emits never fires). Each `instanceof` is now guarded on the class existing, in both `connector.v3.js` and `connector.v4.js`. Deliberately NOT an activation: modern SDK errors carry no numeric `.code`, so the guarded arms stay inert, and the SDK-2 shutdown-bucket message greps zero in the 4.1.3 dist. The real error now reaches the handler's designed terminal path instead of being replaced. (#B204)
14
+
9
15
  ## 0.6.23 - 2026-09-02
10
16
  ### Added
11
17
  * Security headers are now emitted by the framework itself, on both engines, via `settings.json > server.securityHeaders` (OWASP A02). This closes a gap that made the existing `#HDR` plugins unreachable for most projects: they are Express middleware, and the default `isaac` engine never runs the Express middleware chain for HTTP responses, so mounting the `SecurityHeaders()` orchestrator emitted nothing at all there. Seven headers are on by default, chosen because none can break a working application — `x-content-type-options`, `x-download-options`, `x-permitted-cross-domain-policies`, `x-xss-protection`, `referrer-policy`, `x-dns-prefetch-control` and `origin-agent-cluster`. Four are opt-in behind a single key each, because each breaks a legitimate deployment: `xFrameOptions` (cross-origin embedding), `coop` (severs `window.opener`, so OAuth and payment popups), `corp` (cross-origin asset loading) and `hsts` (a 180-day HTTPS commitment, emitted over plain HTTP too). Precedence is first-writer-wins, so a mounted plugin, an `env.json > server.response.header` entry or an upstream proxy always wins. `coop` and `corp` are never applied to `/_gina/*`, which is deliberately cross-origin. Set `server.securityHeaders.enabled` to `false` to restore the previous behaviour (#OW1)
package/README.md CHANGED
@@ -62,26 +62,23 @@ open https://localhost:3100
62
62
 
63
63
  > **npm 12+** blocks install scripts by default, and gina's post-install bootstraps `~/.gina` and the framework dependencies. Install with `npm install -g gina@latest --allow-scripts=gina`, or allow it once for all global installs with `npm config set allow-scripts=gina --location=user`. (Not needed on npm ≤ 11.)
64
64
 
65
- ## What's in 0.6.23
65
+ ## What's in 0.6.24
66
66
 
67
- > **Restart your bundles AND rebuild them.** This release changes the browser
68
- > bundle: the merge hardening ships in `gina.min.js`. A restart alone updates
69
- > the server half only — each bundle bakes its own copy of the client assets,
70
- > so a restart without `gina bundle:build` leaves the browser running the old
71
- > code.
67
+ > **Restart your bundles — no rebuild needed.** This release does not change the
68
+ > browser bundle: all three fixes are server-side, inside the Couchbase
69
+ > connector. A `gina bundle:restart` is enough, and `gina bundle:build` is not
70
+ > required. Projects on other connectors are unaffected.
72
71
 
73
- > **No settings reset.** `0.6.23` is a patch — the `shortVersion` stays `0.6`,
72
+ > **No settings reset.** `0.6.24` is a patch — the `shortVersion` stays `0.6`,
74
73
  > so your `~/.gina/0.6/settings.json` is untouched. (`0.6.0` was the reset.)
75
74
 
76
- **The OWASP Top 10 response release.** The framework now emits security headers
77
- itself, bounds request bodies, and can stamp integrity hashes on the asset tags
78
- it builds — plus a hardened inline-script escape and a merge crash fix.
75
+ **A Couchbase connector reliability release.** Three failure paths that reported
76
+ nothing usable to the caller — one of them silently — now surface the real
77
+ error. Full detail in [CHANGELOG.md](./CHANGELOG.md).
79
78
 
80
- - **Security — hardened inline-script escaping (#B451).** The previous guard for server data serialised into inline `<script>` blocks matched only the literal `</script>` and `<!--` sequences, but the HTML5 script-data end tag also accepts a tab, newline, form feed, space or `/` after the tag name — so `</script >` and `</script/>` closed the block and the remainder of a stored value was parsed as HTML. Values are now escaped by neutralising `<` itself, which no terminator spelling can work around, applied by one shared helper at every site that serialises server data into an inline script. U+2028 and U+2029 are escaped as well. The escaped output parses back to an identical value, so no data shape changes. Server-side only.
81
- - **Added — the framework now emits security headers itself (#OW1).** On both engines, via `settings.json > server.securityHeaders`. This closes the gap that made the `#HDR` plugins unreachable for most projects: they are Express middleware, and the default `isaac` engine never runs the Express middleware chain for HTTP responses, so mounting the `SecurityHeaders()` orchestrator emitted nothing there. Seven headers are on by default — chosen because none can break a working application; four more (`xFrameOptions`, `coop`, `corp`, `hsts`) are opt-in behind one key each, each with a named breakage. Precedence is first-writer-wins: a mounted plugin, an `env.json` header entry or an upstream proxy always beats the framework default, and `coop`/`corp` are never applied to the deliberately cross-origin `/_gina/*`. `server.hidePoweredBy` now defaults to `true` — a version banner is free reconnaissance. `server.securityHeaders.enabled: false` restores the previous behaviour.
82
- - **Added — request bodies are bounded (#OW2).** `server.maxBodySize` (default `64MB`) caps non-multipart request bodies, which previously accumulated with no ceiling at all: a body past the limit is answered 413 and the stream is destroyed. A companion `server.maxBodySizeWarn` (default `2MB`) only logs, so you can measure your real distribution before choosing a stricter ceiling. Multipart uploads stay under the `upload.*` caps. `server.timeout` is now configurable too, and stays `0` (unlimited) by default on purpose — a finite whole-request clock would kill SSE and WebSocket connections.
83
- - **Added — opt-in Subresource Integrity (#OW3).** Set `"sriEnabled": true` in `templates.json > "_common"` and every same-origin `<script>` and `<link rel="stylesheet">` whose file resolves on disk gains `integrity="sha384-..."` plus `crossorigin="anonymous"`, so a tampered or truncated asset is refused by the browser instead of executed. Fail-open by design: external URLs, unresolvable paths and unreadable files simply get no attribute. Hashes are re-validated by mtime and size on every render, so a rebuilt asset gets a fresh hash with no restart; flush the render/output cache after rebuilding assets, since already-cached pages keep the hash they were rendered with.
84
- - **Fixed — merge crash on shadowed `constructor` keys (#B450).** A JSON body carrying a nested object whose own `constructor` key holds a primitive, null, array or plain object no longer crashes the merge on the PUT path: the plain-object check read `.prototype` off the shadowed value eagerly and threw. The check now computes lazily with the read guarded; the guarded key is still dropped per the 0.6.22 disclosure, and sibling fields survive.
79
+ - **Fixed — `bulkInsert` reports a failed prologue instead of returning `undefined` (#B460).** Its outer `try` wraps the method's own body, so a synchronous failure raised before the insert was dispatched — a connection that cannot be resolved, or either of the two `rec` validations — was caught, written to `console.error` and then swallowed, and the method fell off the end. Both documented call shapes broke on that path in opposite ways: the `await` form resolved with `undefined`, so a caller treating "did not throw" as success recorded an insert that never happened, and `.onComplete(cb)` threw a `TypeError` at the call site. In both, the error existed only in the log. The promise, its one-shot resolver and the `.onComplete` shim are now built before the `try`, so the outer catch settles the call. **Behaviour change:** a fire-and-forget call that ignores the return now surfaces an `unhandledRejection` where it previously failed silently. **Scope:** this changes what `bulkInsert` RETURNS, not what its promise RESOLVES WITH — a rows-less success still resolves `null`, so keep any rows-based success check you have.
80
+ - **Fixed — a Couchbase entity that fails to register now names itself (#B461).** The catch guarding entity-class construction and `.sql`-derived method attachment emitted only a bare stack, and none of its three call sites captures a result or takes an error argument — so a throw left the entity partially built, or absent, with nothing in the log identifying which entity or which `.sql` file was responsible. The first symptom was a missing method at request time, arbitrarily far from the cause. The diagnostic now carries the entity, the source file, the method being attached and the underlying cause. Boot behaviour is deliberately unchanged: registration failures remain non-fatal.
81
+ - **Fixed — the reconnect classifier no longer throws under every supported SDK (#B204).** `gina.onError`'s handler tested `err instanceof couchbase.Error`, but no supported couchnode exports a bare `Error` class, so the check raised `TypeError: Right-hand side of 'instanceof' is not an object` the moment the handler ran — and because that operand is evaluated first, the shutdown-bucket message arm was unreachable too. On the Express engine this replaced the real error with the `TypeError`; on the default `isaac` engine the listener is never dispatched at all, so there is no behaviour change there. Each `instanceof` is now guarded on the class existing. Deliberately a guard, not an activation: the arms it protects stay inert on modern SDKs, and the real error now reaches the handler's designed terminal path.
85
82
 
86
83
  ## Documentation
87
84
 
package/ROADMAP.md CHANGED
@@ -75,6 +75,7 @@ This roadmap covers planned features, architectural improvements, new connectors
75
75
  | **Q4 2026** | `0.6.21` ✅ | **Fixed**: an outbound `route.request()` now settles its callback on every outcome — the request object was discarded, so nothing could attach an `error` listener, and a dial failure either never invoked the callback at all (a permanent stall for anything serialized, with nothing logged) or reached `uncaughtException` and terminated the bundle; a response stream dying mid-body waited on an `end` event it would never emit. `options.timeout` was accepted but inert — Node only emits a `timeout` event and never destroys the socket — and is now honoured, so a value set in the belief that it capped the call will begin aborting requests at that budget. **Fixed**: `merge()` no longer throws `TypeError: Cannot read properties of null` on an id-keyed array carrying a `null` element, on either operand at any index — the read-side counterpart of the write-side fix that shipped in `0.6.20`. **Fixed**: on Safari, modifier chords (paste, select-all, copy, cut, undo) work again in live-checked fields carrying `autocomplete="off"` — the form-level keydown proxy cancelled the native keydown before the typing interception could decide anything, and `preventDefault` on a native keydown suppresses the browser's editing command itself, so no `paste` event was dispatched anywhere; Chromium-family browsers were never affected. Restart **and** rebuild your bundles (the browser bundle changed — all three fixes ship in `gina.min.js`). |
76
76
  | **Q4 2026** | `0.6.22` ✅ | **Security**: prototype pollution on the request path — client-supplied bracket-notation field names (`__proto__[x]`, `constructor[prototype][x]`, and their percent-encoded forms) reached an unguarded property assignment in the data helper's key-path nesting and wrote to `Object.prototype` silently (the parsed body came back empty, so nothing in the request looked wrong), and `merge()` copied an **own** `__proto__` key — the shape `JSON.parse` produces — through its `for...in` loops. Reachable from query strings, urlencoded and JSON request bodies, `request.query.inheritedData` and multipart text-field names; a polluted prototype could then influence code reading a property it expects to be absent — outbound request options (host, port, auth, the TLS certificate check) and the safe-method and exemption checks. Both sources now reject the same three key names — rejecting the key name is what closes this, since an own `__proto__` (the shape `JSON.parse` produces) satisfies an own-property check. **Fixed**: a form submit that fails at the TRANSPORT layer (network down, connection refused, server restarting) settled with no HTTP status and dispatched neither `error.<formId>` nor `error.<formId>.hform`, so a handler declared with `data-gina-form-event-on-submit-error` never ran while the form released its submit trigger and reported nothing to the visitor; both events now fire with `status: 408` and `transportError: true`, the latter distinguishing it from a genuine request timeout, and handlers matching on `status >= 400` keep working unchanged. Restart **and** rebuild your bundles (the browser bundle changed — both fixes ship in `gina.min.js`). |
77
77
  | **Q4 2026** | `0.6.23` ✅ | **Security**: hardened inline-script escaping — the previous guard matched only the literal `</script>` and `<!--`, but the HTML5 script-data end tag also accepts a tab, newline, form feed, space or `/` after the tag name, so `</script >` closed the block and the remainder of a stored value parsed as HTML; serialised values now neutralise `<` itself at every site, with U+2028/U+2029 escaped too, and escaped output parses back to an identical value. **Added**: the framework itself now emits seven security headers by default on both engines (`server.securityHeaders`; four more opt-in — `xFrameOptions` / `coop` / `corp` / `hsts`), first-writer-wins so mounted plugins, `env.json` headers and proxies keep winning, with `/_gina/*` exempt from the cross-origin-isolating pair; `server.hidePoweredBy` now defaults to `true`. **Added**: `server.maxBodySize` (default 64MB, 413 + stream destroyed) bounds non-multipart request bodies, with warn-only `server.maxBodySizeWarn` (2MB) and a configurable `server.timeout` that stays `0` on purpose (SSE/WebSocket). **Added**: opt-in Subresource Integrity — `templates.json > "sriEnabled": true` adds `integrity` + `crossorigin` to same-origin script and stylesheet tags that resolve on disk; fail-open, hashes stat-validated per render. **Fixed**: a JSON body whose nested object shadows `constructor` with a primitive, null, array or plain object no longer crashes the merge on the PUT path. Restart **and** rebuild your bundles (the browser bundle changed — the merge fix ships in `gina.min.js`). |
78
+ | **Q4 2026** | `0.6.24` ✅ | **Fixed**: Couchbase `bulkInsert` no longer returns `undefined` when its own prologue throws — the outer `try` wraps the method body, so a synchronous failure (an unresolvable connection, or either `rec` validation) was caught, logged and swallowed, and the method fell off the end: the `await` form resolved with `undefined`, so a caller treating "did not throw" as success recorded an insert that never happened, and `.onComplete(cb)` threw a `TypeError` at the call site. The promise, its one-shot resolver and the `.onComplete` shim are now built before the `try`, so the outer catch settles the call. A fire-and-forget call now surfaces an `unhandledRejection` where it previously failed silently, and the fix moves what `bulkInsert` RETURNS, not what its promise RESOLVES WITH — a rows-less success still resolves `null`. **Fixed**: a Couchbase entity that fails to register now names itself, its source file, the method being attached and the underlying cause, instead of emitting a bare stack that left a partially-built entity and a missing method surfacing arbitrarily far from the cause; registration stays non-fatal. **Fixed**: the reconnect classifier no longer throws under every supported SDK — `err instanceof couchbase.Error` raised a `TypeError` because no supported couchnode exports a bare `Error` class, and since that operand is evaluated first the message arm was unreachable too, so the classifier could not classify by any route; each `instanceof` is now guarded on the class existing (deliberately a guard, not an activation — on the default `isaac` engine the listener is never dispatched at all). Restart your bundles — the browser bundle is unchanged, so no rebuild is needed. |
78
79
  | **Q1 2027** | `0.6.x` | HTTP/2 priorities (blocked on Node scheduler hooks) · Beemaster admin + visual translation editor |
79
80
  | **2027** | `0.7.0` | Performance — remaining measure-gated candidates: multipart & WebSocket fast paths, render/log cleanups, SIMD scanner (the render-path deep-clone & id-mint reduction shipped early in `0.6.2` with a measured 4.4× render-throughput gain; the profiling baseline itself also shipped in `0.6.2`) |
80
81
  | **2027** | `0.8.0` | Financial-messaging foundations — XML request/response handling · pluggable message-schema validation · IBAN/BIC validation rules · money & ISO 4217 minor-unit utilities · idempotency keys · sequence primitive · OAuth2 client-credentials egress |
@@ -0,0 +1 @@
1
+ 0.6.24
@@ -1364,6 +1364,25 @@ function Couchbase(conn, infos) {
1364
1364
  }
1365
1365
 
1366
1366
  } catch (err) {
1367
+ // #B461 — say WHICH entity failed to register, and from which file.
1368
+ // This catch guards the whole entity-class construction and .sql method
1369
+ // attachment above it (~770 lines: inherits(), the prototype stamping,
1370
+ // the per-method attachment). None of readSource()'s three call sites
1371
+ // captures a result or takes an error argument, so a throw here used to
1372
+ // leave the entity partially built — or absent — with nothing but a bare
1373
+ // stack in the log: the first symptom a consumer saw was a missing method
1374
+ // at request time, arbitrarily far from the cause.
1375
+ //
1376
+ // Boot deliberately still CONTINUES. Whether an unbuildable entity should
1377
+ // be fatal is a separate, consumer-visible decision (a project booting
1378
+ // today through a swallowed error would start failing to boot), so this
1379
+ // change is diagnostic only and does not alter control flow.
1380
+ console.error('[couchbase] entity `' + entityName + '` failed to register from `'
1381
+ + source + '`'
1382
+ + ( name ? ' while attaching method `' + name + '`' : '' )
1383
+ + ' — it may be missing that method or be incompletely built, and the first '
1384
+ + 'symptom is usually a missing method at request time. Cause: '
1385
+ + ( err && err.message ? err.message : String(err) ));
1367
1386
  console.error(err.stack);
1368
1387
  }
1369
1388
  }
@@ -1406,6 +1425,57 @@ function Couchbase(conn, infos) {
1406
1425
  */
1407
1426
  var bulkInsert = function(rec, options) {
1408
1427
 
1428
+ // #B460 — the promise, its one-shot resolver and the .onComplete shim are
1429
+ // built BEFORE the try, not inside it. The try below wraps this function's OWN
1430
+ // body, so a synchronous throw in the prologue (a failed getConnection(), or
1431
+ // either of the two deliberate `rec` validations) lands in the outer catch. When
1432
+ // the plumbing lived inside the try, that catch ran with _promise/_settle/the
1433
+ // shim still hoisted-but-unassigned, so the function fell off the end and
1434
+ // returned `undefined`: `.onComplete(cb)` threw on undefined and the documented
1435
+ // `await` form resolved with undefined, hiding the error from the caller
1436
+ // entirely. Built here, they exist unconditionally and the catch can settle.
1437
+ // #B429 — bulkInsert settles per call, exactly once, like the query path.
1438
+ // The Promise below used to be created AFTER the dispatch and woken by
1439
+ // `self.once(trigger)` on the shared entity singleton, so two concurrent
1440
+ // bulkInsert calls on one entity both received whichever finished first
1441
+ // (measured). The resolver is hoisted here so the handlers can settle THIS
1442
+ // call directly; the trigger is still emitted, purely for observability.
1443
+ var _resolve, _reject, _internalData, _internalMeta;
1444
+ var _promise = new Promise(function(resolve, reject) {
1445
+ _resolve = resolve;
1446
+ _reject = reject;
1447
+ });
1448
+ var _settled = false;
1449
+ /**
1450
+ * Settle THIS bulkInsert call's promise, at most once.
1451
+ *
1452
+ * @inner
1453
+ * @param {Error|boolean} err - the error, or `false` on success.
1454
+ * @param {Array} data - the RETURNING rows.
1455
+ * @param {object} [meta] - the driver's result metadata.
1456
+ * @returns {void}
1457
+ */
1458
+ var _settle = function(err, data, meta) {
1459
+ if (_settled) {
1460
+ return;
1461
+ }
1462
+ _settled = true;
1463
+ if (err) {
1464
+ _reject(err);
1465
+ } else {
1466
+ _internalData = data;
1467
+ _internalMeta = meta;
1468
+ _resolve(data);
1469
+ }
1470
+ };
1471
+ _promise.onComplete = function(cb) {
1472
+ _promise.then(
1473
+ function() { cb(null, _internalData, _internalMeta); },
1474
+ function(err) { cb(err); }
1475
+ );
1476
+ return _promise;
1477
+ };
1478
+
1409
1479
  try {
1410
1480
  var conn = this.getConnection();
1411
1481
  // retrieve & return the collection
@@ -1503,40 +1573,8 @@ function Couchbase(conn, infos) {
1503
1573
 
1504
1574
  var self = this;
1505
1575
 
1506
- // #B429 — bulkInsert settles per call, exactly once, like the query path.
1507
- // The Promise below used to be created AFTER the dispatch and woken by
1508
- // `self.once(trigger)` on the shared entity singleton, so two concurrent
1509
- // bulkInsert calls on one entity both received whichever finished first
1510
- // (measured). The resolver is hoisted here so the handlers can settle THIS
1511
- // call directly; the trigger is still emitted, purely for observability.
1512
- var _resolve, _reject, _internalData, _internalMeta;
1513
- var _promise = new Promise(function(resolve, reject) {
1514
- _resolve = resolve;
1515
- _reject = reject;
1516
- });
1517
- var _settled = false;
1518
- /**
1519
- * Settle THIS bulkInsert call's promise, at most once.
1520
- *
1521
- * @inner
1522
- * @param {Error|boolean} err - the error, or `false` on success.
1523
- * @param {Array} data - the RETURNING rows.
1524
- * @param {object} [meta] - the driver's result metadata.
1525
- * @returns {void}
1526
- */
1527
- var _settle = function(err, data, meta) {
1528
- if (_settled) {
1529
- return;
1530
- }
1531
- _settled = true;
1532
- if (err) {
1533
- _reject(err);
1534
- } else {
1535
- _internalData = data;
1536
- _internalMeta = meta;
1537
- _resolve(data);
1538
- }
1539
- };
1576
+ // #B460 — the resolver/_settle pair moved ABOVE the try (see the top of this
1577
+ // function); the #B429 per-call settlement contract they implement is unchanged.
1540
1578
 
1541
1579
  var err = false;
1542
1580
  // cluster resolved via the shared dual-shape helper (was a bare
@@ -1666,13 +1704,8 @@ function Couchbase(conn, infos) {
1666
1704
  // therefore only half-true as written: bulkInsert did adopt Option B's
1667
1705
  // Promise + .onComplete() shape, but kept the shared `once` as the thing that
1668
1706
  // settled it — which is exactly the defect the query path carried.
1669
- _promise.onComplete = function(cb) {
1670
- _promise.then(
1671
- function() { cb(null, _internalData, _internalMeta); },
1672
- function(err) { cb(err); }
1673
- );
1674
- return _promise;
1675
- };
1707
+ // #B460 — the .onComplete shim is attached above the try now, so a prologue
1708
+ // throw still returns a promise that carries it. Contract unchanged.
1676
1709
 
1677
1710
  if (envIsDev) {
1678
1711
  _promise.then(
@@ -1685,6 +1718,13 @@ function Couchbase(conn, infos) {
1685
1718
 
1686
1719
  } catch (err) {
1687
1720
  console.error(err.stack);
1721
+ // #B460 — settle THIS call's promise instead of falling off the end. _settle's
1722
+ // `_settled` latch makes this a no-op when the dispatch already settled, so a
1723
+ // late throw cannot double-settle. Returning _promise keeps both documented
1724
+ // shapes working on the failure path: .onComplete(cb) delivers (err), and the
1725
+ // `await` form rejects rather than resolving with undefined.
1726
+ _settle(err);
1727
+ return _promise;
1688
1728
  }
1689
1729
  }
1690
1730
 
@@ -166,7 +166,11 @@ function Connector(dbString) {
166
166
  }
167
167
 
168
168
  if (
169
- err instanceof couchbase.Error && err.code == 16 && !self.reconnected
169
+ // #B204 — no supported SDK (3.x/4.x) exports a bare `Error` class, so the
170
+ // un-guarded instanceof threw TypeError and, being evaluated first, made
171
+ // the message arm below unreachable too. Guarded: the arm is inert on
172
+ // modern SDKs (their errors carry no numeric .code), never a throw.
173
+ typeof(couchbase.Error) == 'function' && err instanceof couchbase.Error && err.code == 16 && !self.reconnected
170
174
  //|| err instanceof couchbase.Error && err.code == 23 && !self.reconnecting
171
175
  || /cannot perform operations on a shutdown bucket/.test(err.message ) && !self.reconnecting && !self.reconnected
172
176
  ) {
@@ -188,7 +192,7 @@ function Connector(dbString) {
188
192
  }
189
193
  }, _backoffDelay)
190
194
 
191
- } else if (err instanceof couchbase.Error && err.code == 23 && !self.reconnecting) {
195
+ } else if (typeof(couchbase.Error) == 'function' && err instanceof couchbase.Error && err.code == 23 && !self.reconnecting) { // #B204 — guarded, same reason as above
192
196
  self.instance.disconnect();
193
197
  // express js patch
194
198
  if (typeof(next) != 'undefined') {
@@ -180,7 +180,11 @@ function Connector(dbString) {
180
180
  }
181
181
 
182
182
  if (
183
- err instanceof couchbase.Error && err.code == 16 && !self.reconnected
183
+ // #B204 — no supported SDK (3.x/4.x) exports a bare `Error` class, so the
184
+ // un-guarded instanceof threw TypeError and, being evaluated first, made
185
+ // the message arm below unreachable too. Guarded: the arm is inert on
186
+ // modern SDKs (their errors carry no numeric .code), never a throw.
187
+ typeof(couchbase.Error) == 'function' && err instanceof couchbase.Error && err.code == 16 && !self.reconnected
184
188
  //|| err instanceof couchbase.Error && err.code == 23 && !self.reconnecting
185
189
  || /cannot perform operations on a shutdown bucket/.test(err.message ) && !self.reconnecting && !self.reconnected
186
190
  ) {
@@ -202,7 +206,7 @@ function Connector(dbString) {
202
206
  }
203
207
  }, _backoffDelay)
204
208
 
205
- } else if (err instanceof couchbase.Error && err.code == 23 && !self.reconnecting) {
209
+ } else if (typeof(couchbase.Error) == 'function' && err instanceof couchbase.Error && err.code == 23 && !self.reconnecting) { // #B204 — guarded, same reason as above
206
210
  self.instance.disconnect();
207
211
  // express js patch
208
212
  if (typeof(next) != 'undefined') {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gina-framework",
3
- "version": "0.6.23",
3
+ "version": "0.6.24",
4
4
  "dependencies": {
5
5
  "@rhinostone/busboy": "^1.6.1",
6
6
  "@rhinostone/swig": "^2.7.2",
package/gna.js CHANGED
@@ -15,14 +15,14 @@
15
15
  'use strict';
16
16
 
17
17
  // Framework core — the main gna module (lifecycle hooks, lib, etc.)
18
- var _gna = require('./framework/v0.6.23/core/gna');
18
+ var _gna = require('./framework/v0.6.24/core/gna');
19
19
 
20
20
  // SuperController and EntitySuper — loaded from their source modules
21
- var SuperController = require('./framework/v0.6.23/core/controller');
22
- var EntitySuper = require('./framework/v0.6.23/core/model/entity');
21
+ var SuperController = require('./framework/v0.6.24/core/controller');
22
+ var EntitySuper = require('./framework/v0.6.24/core/model/entity');
23
23
 
24
24
  // uuid — from the lib registry
25
- var uuid = require('./framework/v0.6.23/lib/uuid');
25
+ var uuid = require('./framework/v0.6.24/lib/uuid');
26
26
 
27
27
  module.exports = {
28
28
 
package/llms.txt CHANGED
@@ -886,7 +886,7 @@ Dev-mode query instrumentation captures every database query tied to the current
886
886
 
887
887
  176. **Inspector & `/_gina/*` built-in endpoints — in-process architecture, admin IP-allowlist, agent-stream auth, live index coverage** (replaces individual entries #31, #32, #38, #111, #134, #138) — the dev Inspector (formerly Beemaster) is a built-in SPA served at `/_gina/inspector/` inside the bundle's own process: no project registration, no separate port, no auto-start spawn; dev-mode only (production bundles never expose it), and same-origin with the monitored bundle so `window.opener.__ginaData` always works. Every `/_gina/*` route (healthcheck, assets, cache/stats, info, inspector, logs, agent, indexes, reveal, instrument, metrics) is a handler in the same HTTP server process; the Isaac engine is the source of truth and may carry fast-paths, but base functionality belongs in the engine-agnostic dispatcher so Express bundles get the same endpoints. Admin-grade endpoints exposing process/cache internals (`/_gina/info` — memory/uptime/version/HTTP-2 session counters; `/_gina/cache/stats` — full cache contents) are IP-allowlisted via the `admin.allowFrom` block in `app.json`: the client IP is read from the socket only (the spoofable `X-Forwarded-For` is never trusted), `::ffff:`-mapped IPv4 is normalised, the list defaults to loopback (`127.0.0.1`, `::1`) when omitted, an empty list denies everyone, and denied callers get a 403 JSON error; `/_gina/health/check` stays deliberately open for liveness probes, and `/_gina/metrics` keeps its own separate `metrics.allowFrom` axis. The `/_gina/agent` stream (combined data + log events) is dev-only by default but can be enabled outside dev behind an API key (`settings.json > inspector.agent.{enabled, key}`, `${secret:KEY}`-capable, constant-time compared, fail-closed when no key is configured); browsers pass `?key=` as a query param because `EventSource` and WebSocket handshakes cannot set custom headers — and any `$`-anchored endpoint gate regex must become `(?:\?|$)` the moment its endpoint accepts a query param, or the handler silently stops matching the query'd URL. A time-boxed, separately-keyed production instrumentation window (`POST /_gina/instrument`, hard-capped at one hour) can stream per-request query + flow capture over that authenticated channel — channel AUTH, not redaction, is what protects raw query text (redaction masks only secret-NAMED fields, never the statement or its positional params). The Query tab computes live index coverage client-side, so bundles WITHOUT an `indexes.sql` get a correct "no index for filter" badge on the first render too (cached live-index descriptors are cloned per query before stamping coverage — the cache is shared across queries that filter different columns). The live-index refetch's success re-render lands in `#tree-query` — the container the tab renderer owns and silently bails on when missing — never the scroll wrapper around it (#B222: replacing the wrapper's children destroyed `#tree-query`, so after the first render carrying an `indexes: null` query every later payload — navigation, XHR, the refresh button — froze the Query pane and badge until the Inspector window itself was reloaded; the ⟳ button re-armed the freeze via its forced refetch). Inspector toolbar CSS: native macOS `<select>` ignores `line-height` — use explicit vertical padding, and keep `select` (sans font) and `input` (mono font) on separate CSS rules. **SPA + statusbar hardening (folds former #165/#190/#191/#196):** every per-bundle `/_gina/*` consumer in the SPA derives its base URL via the shared 3-fallback `resolveBundleBase()` (`?target=` → opener pathname → path strip) — a bare `window.location.pathname` strip misroutes to the proxy's default bundle in reverse-proxy multi-bundle setups. The Inspector binds to its opener tab via a per-tab `BroadcastChannel` (`?ch=<tabId>`): pages sending COOP `same-origin` sever `window.opener` for the popup, and the bundle-global fallbacks (the shared localStorage slot + the worker-wide agent SSE) reflect whichever render last touched them — a diagnostic channel that must track ONE page needs a per-tab transport (the statusbar publishes that tab's data at its existing write points and answers a request/reply handshake; no `?ch=` keeps the prior behaviour, and `?target=` agent mode keeps priority). Structured-localStorage reads need a SHAPE check on top of the try/catch parse (a tampered key holding a JSON primitive otherwise breaks the un-guarded consumer), and every value interpolated into `innerHTML` goes through an HTML-escape helper — untrusted model/app text renders via `.textContent` instead. Dev inline-script splices before `</body>` use FUNCTION replacers: `String.replace(/re/, str)` expands `$`-sequences in a STRING replacement (`` $` ``/`$'`/`$&`), so dynamic content carrying a stray dollar-sequence spliced the whole document into the statusbar `<script>` (SyntaxError → statusbar and launch link vanish) on content-heavy pages while a near-empty smoke page stayed falsely green — any `String.replace(re, dynamicX)` with dynamic content must use a function replacer or escape `$`. Inspector SPA files are copied VERBATIM to dist (no minification) — an inspector-only edit rebuilds only those dist files, never the main bundle artifacts. Bound-window data fidelity (#B225): a preload-consumed popin open sets the dev toolbar's XHR overlay on BOTH consume branches exactly like a cold click (dev-gated `updateToolbar(body)` immediately before each dispatch — in consumePreload, never in the shared dispatcher, which would double-fire the cold path); the statusbar-bound Inspector window's refresh button never reopens the passive `/_gina/agent` stream (`source !== 'broadcast'` on the reopen gate — bound mode takes page-scoped data from the statusbar publisher, and a leaked stream applied bundle-wide payloads over it, blinking the Query badge at every XHR overlay); and every Query-pane re-render (filter/search/show-all plus the live-index refetch success path) derives from the live payload via renderTab('query')'s own preference (reveal swap included) instead of the module query cache, which the empty render path never clears and which survives overlay eras ending while the Query tab is inactive — a refresh no longer resurrects a closed popin's badge count. A `?ch=`-less embedded Inspector (direct URL, bookmark, a window predating bound mode) no longer silently runs those bundle-global channels (#B231): every dev page's statusbar advertises its per-tab channel id in localStorage (`__gina_last_tab_ch`) on each publish, a `?ch=`-less Inspector adopts the most-recently-published tab's channel at boot behind a liveness handshake (the bind's request must be answered by a data frame within 1.5 s — a stale advert from a closed tab tears the bound mode down and falls back to the legacy acquisition, closing the bound-mode `/_gina/logs` stream so log entries are not double-delivered once the passive agent stream attaches), and a footer badge names the active data-source mode (`bound` / `agent` / warn-tinted `global` with a tooltip pointing at the statusbar link) so a degraded bundle-global mode is visible instead of silent. That badge renders from `updateSourceModeBadge()`, which init must call on BOTH acquisition branches (#B306): it previously ran only on the non-agent branch and from `pollData()`, and since the poll timer is deliberately never scheduled under `?target=` (agent data is SSE-pushed), a URL-entered standalone Inspector kept the element's shipped `hidden` attribute and named no mode at all — while the identical `agent` mode DID render when reached through the connect form, whose timer is already ticking when `source` flips. Badging depended on how the window was opened rather than on the mode itself, which is exactly what the badge exists to prevent. The timer stays unscheduled in agent mode on purpose, and a future reader must not "reconcile" that guard to the comment that once claimed otherwise: `pollData()` is NOT a no-op under `source === 'agent'` — it repaints the active tab from cache before returning — so putting it on a timer would repaint every `pollDataMs` and fight scroll position, expanded folds and text selection; the refresh button calls `pollData()` directly and needs no timer at all. The footer memory gauge sits its unfilled track on `--bg3` with a theme-scoped inset groove shadow (#B237) — the track previously shared `.bm-footer`'s own `--bg2` background token, so the empty portion rendered invisible in both themes and a low fill read as a floating green dot; a gauge track must contrast the surface it sits on, and an inset box-shadow paints under the fill child, so the groove shades only the empty region. The Forms tab shows the page's DOM forms enriched with runtime validation state (the statusbar merge writes `u.forms[<id>]` per form), while the whole-bundle forms catalog the server seeds into `user.forms` (`page.forms` = the walked `<bundle>/forms/` directory groups — `rules`, `mocks`, `validators`, open-ended) renders as one collapsed, muted "Bundle catalog" card at the bottom (#B343): catalog keys are recognized by their presence in the pristine `gina.forms` half of the payload (which runtime merges never write), so app-custom group directories demote too, departed runtime forms (a closed popin's form) keep their own card, and a payload with no gina half falls back to the legacy per-key rendering — nothing is ever hidden. **The page whisper excludes `mocks` (#B344, every env):** `page.environment.forms` — the RFC5987-encoded export the client loader parses into `gina.forms` — ships a SHALLOW COPY of the catalog minus the `mocks` group in every environment (dev fixture data has zero client consumers: the client bundle reads `gina.forms.rules` and `gina.forms.validators` only), trimming page weight and keeping the client contract uniform across envs; server-side `conf.forms`/`page.forms` — and therefore this catalog card — keep the full set, and the shared catalog object is never mutated. **The localStorage fallback channel is re-synced by the late-bind patch (#B386, fixed 2026-08-16, shipped in 0.6.11).** `statusbar.html` mirrors `window.__ginaData` into `localStorage.__ginaData` at statusbar-execution time, which is BEFORE the render delegates append their late-bind patch script above `</body>` — and that patch mutates the IN-MEMORY object only. Without a re-sync the mirror keeps the EMIT-TIME payload forever: `metrics.weightBytes` null (null at emit by construction, since the body length is unknown until the render finishes) and the late flow entries absent. Measured live on a dev bundle: mirror `{serverMs:2339, weightBytes:null}` with 17 flow entries against an in-page `{serverMs:2860, weightBytes:628192}` with 21 — the four missing being `swig-compile`, `swig-execute`, `response-write`, `total`. Two visible symptoms, and the asymmetry between them IS the diagnostic: the View tab drops its weight badge (both weight legs falsy) while the load badge survives, because `serverMs` IS set at emit and `weightBytes` is not — so a fallback-channel Inspector shows 2 badges instead of 3, and only until something else re-syncs; and the Flow tab loses its template-compile/execute/response-write/total bars. All three patch sites (render-swig cache-hit and cache-miss, render-nunjucks) now end their patch script by refreshing BOTH channels the Inspector can read, placed AFTER the metrics assignments — ordering is load-bearing, since syncing first would re-mirror the stale payload. **localStorage alone was NOT enough, and that was the first fix's mistake:** it is only the FALLBACK channel, while a statusbar-launched Inspector runs in BOUND mode on a per-tab `BroadcastChannel`. Measured: all SEVEN `_ginaPublish()` call sites sit BEFORE the patch (`publishesAfterPatch: 0`), and a surrogate bound listener held across a real navigation received exactly ONE frame carrying `weightBytes: null` with `serverMs` set — the 2-badges-instead-of-3 symptom, reproduced on the transport itself. The patch now also republishes there, keying the channel from `sessionStorage.__gina_tab_id` (per-tab, race-free) and NEVER from the `__gina_last_tab_ch` localStorage advert, which is last-writer-wins across tabs. The subscriber applies it immediately (`setupBoundChannel`'s `onmessage` → `_bcLatest = payload; pollData()`). ⚠️ The convention `'gina-inspector-' + tabId` now spans FOUR files (statusbar publisher, SPA subscriber, both delegates) and is pinned by a test, since a rename in one strands the Inspector on a channel nobody publishes to — silently, with no error. **Generalisable: verifying the PRODUCER and inferring the CONSUMER is not verification** — the page data measured correct on all four reported URLs while the bug was fully present. The nunjucks site was also converted to a FUNCTION replacer, which both swig sites already used. **Cross-origin WRITE guard (#B384, fixed 2026-08-16 — a CSRF that was live in every release up to 0.6.9).** The admin endpoints authenticate with an AMBIENT credential (the client IP via `lib.admin.isClientAllowed`), which a browser attaches automatically, so an operator browsing from an allowlisted address — loopback by DEFAULT, i.e. the machine running the bundle — could be lured to a page that silently wrote to `/_gina/storage/gc`, `/_gina/cache/clear`, `/_gina/release/rebuild` or `/_gina/maintenance`. The first three read their whole input from the QUERY STRING and no body, so the attack needed no `fetch` and no CORS reasoning at all: an auto-submitting `<form>` sufficed. `lib.admin.isCrossOriginWrite(req)` now fronts the WHOLE family from ONE site per engine, placed above every `/_gina/*` handler so current and future handlers inherit it — the body reader `_readInstrumentBody` was the WRONG seam (it fronts only 2 of the family), and folding the check into `isClientAllowed` would have silently widened a function whose name promises an IP check. Signals, in order: `Sec-Fetch-Site` (browser-computed, a forbidden header name so page script cannot forge it, and independent of a proxy rewriting `Host`) — `same-origin`/`none` pass, `same-site`/`cross-site` refused; else `Origin` vs `:authority`/`Host`, built NEVER from `X-Forwarded-*` (#B367), with `Origin: null` refused (#CSRF3). NO browser signal ⇒ ALLOWED, since curl / the gina CLI / a deploy script carry no ambient credential. SAFE methods (GET/HEAD/OPTIONS/TRACE) are untouched, so the Inspector's deliberately cross-origin GET/SSE channels keep working — measured: the plugin source issues ZERO POSTs to `/_gina/*`, control firing at 23 hits on `/_gina/agent`. `/_gina/instrument` was NOT the worst of the family as first filed: it is key-gated (`_instrumentKeyValid`), so an attacker without the key cannot invoke it; its `access-control-allow-origin: *` is set BEFORE the key check, making only the 401 cross-origin readable. Verified live: 5 attack arms (incl. the query-param form vector and an `X-Forwarded-Host` spoof) all 403 with state never flipping, 5 control arms all allowed incl. a real browser's `no-cors` POST refused where it previously flipped the toggle. Residual, pinned: a browser sending NEITHER signal on a POST would pass — legacy-only, and narrower than the IP allowlist already fronting these endpoints.
888
888
 
889
- 177. **Couchbase connector — install-derived SDK resolution (v2 removed), `connectors.json` semantics, `getCluster()`, dev-mode index reporting** (replaces individual entries #29, #40, #41, #57, #136, #153) — connectors are keyed in `schema/connectors.json` by LOGICAL name (`primary`, `sessionStore`, `cache`, …) with the driver selected by the `connector` enum field (`couchbase`/`mysql`/`postgresql`/`sqlite`/`redis`/`ai`/…) — never introduce a separate `driver` field; the optional `version` field carries a semver range used by `connector:add --driver-version=…` for the npm-install hint. The Couchbase SDK major is derived from the project's INSTALLED `couchbase` npm version — the leading major of `dependencies.couchbase` selects `connector.v<major>.js`, which stamps `conn.sdk = { version: N }` — never from a config key, so migrating SDK majors is a driver bump (`npm install couchbase@^4`), not a config edit. SDK v2 is REMOVED as of 0.4.0: the resolver now throws a clear "SDK v2 is no longer supported — upgrade couchbase@^3/^4" error when the installed major is ≤ 2 or the connector file is missing (previously a silent fallback that crashed later with an opaque MODULE_NOT_FOUND); the v3-vs-v4 split remains for param shaping. Generalises: when a connector's behavior-version derives from an installed dependency rather than config, fail fast once the installed major drops below the supported floor. Couchbase entities expose a public `getCluster()` (on both the model-entity and N1QL-entity prototypes) returning the underlying SDK `Cluster` handle for features the ORM doesn't wrap — chiefly multi-document ACID transactions (`cluster.transactions().run(...)`, needs SDK 3.2+/4.x) — without touching private `_*` internals; it throws a coded `GINA_COUCHBASE_CLUSTER_UNRESOLVED` error when neither connection shape resolves. Dev-mode index reporting: the SDK v4 C++ binding never populates `meta.profile` despite `profile: 'timings'` being sent (confirmed on v4.6.0), so an async `EXPLAIN <statement>` fallback with a per-process per-statement cache supplies the plan instead (the first request for a new statement may show N/A; subsequent requests hit the cache), and `USE KEYS` plans surface as "KV lookup" via `ExpressionScan`/`KeyScan` operator detection. Three historical traps locked by tests: `conn._cluster.query()` must receive the full `queryOptions` object, not the raw params array (the raw form silently dropped `profile`/`scanConsistency`/`adhoc` from every query); of the connector's two `register()` dispatch paths, Option B (`!_isRegisteredFromProto`) is the ALWAYS-active one — instrumentation or logging added to Option A never executes; and (#B193, 0.6.3) the plan walker must visit the NESTED scan containers, not just `~child`/`~children` — the multi-index operators (`IntersectScan`/`UnionScan`/`OrderedIntersectScan`) put their child `IndexScan3` nodes under a `scans` array and `DistinctScan` under a singular `scan`, so before the fix any plan the planner served with more than one index extracted `[]` and the Inspector rendered the red "no index — full bucket scan" badge/banner for a fully-indexed query — a false negative inviting a pointless (write-amplifying) index build. Both extraction paths (SDK `meta.profile` and the EXPLAIN fallback) share the walker, so one fix covers both; index names still dedupe, and the Query tab already renders one chip per index so multi-index plans display correctly with no client change. A consumer-runnable SDK soak harness ships at `script/soak/couchbase-soak.js` (#CN12): it scaffolds a fully isolated throwaway project, installs a candidate `couchbase` SDK into it (`--sdk=<version>` / `--sdk-path=<dir>` — the install IS the version selector, since the connector resolves the SDK from the project node_modules and derives v3/v4 dispatch from its dependency pin), builds + boots prod, and drives N1QL (incl. a `request_plus` arm) + entity-handle KV (promise AND 4-arg callback forms) + the couchbase session store under sustained concurrent load for `--duration`, FAILING on premature process exit (a clean exit 0 counts as failure — the silent-death class it screens for), unbounded RSS growth, error-rate drift, or a dead arm. A screen, not proof: run it as the first filter on an SDK-bump candidate, ahead of a workload-shaped soak. Pure parts (arg parsing, RSS slope, verdict) are unit-tested in `test/lib/couchbase-soak-evaluator.test.js`; the live harness needs a real cluster and never runs in CI. Named scopes/collections stance (2026-08-02): document-field partitioning (`_scope`/`_collection` fields, one bucket, default collection) IS the data model; the `useScopeAndCollections` option (+ `scope`/`collection` defaults) is accepted but INERT — declared and merged, consumed by nothing — and `schema/connectors.json` says so honestly; named-collection KV is reachable per call via `entity.getConnection(scope, collection)`; native scope/collection routing is deliberately not built (demand-gated). #B203 (2026-08-02): both SDK-major resolver twins derive the major as the dependency pin's FIRST integer — the former caret-only strip mangled range pins (`~4.5.0` → `~4`, `>=4.5` → `>=4`), which slipped the v2 floor (parseInt NaN) into a misdirecting existsSync "supported majors are 3 and 4" error; a digit-less pin (`*`, `latest`) now refuses naming the pin, a package.json without a `dependencies` key no longer TypeErrors, and the v2 floor fires for range v2 pins too (`~2.5.0`). #B243 (2026-08-04): a query parameter the SDK cannot serialize — a bare `undefined`, a function, or a Symbol — was PROCESS-FATAL rather than throwable: the SDK maps `JSON.stringify` over the parameter list, those three types yield no string at all, the native binding coerces that to `""`, and the C++ core's JSON parse of `""` throws on an internal thread reaching `std::terminate()`/`abort()` — uncatchable by `try/catch`, `uncaughtException` or `unhandledRejection`, so the whole bundle died instead of the request 500-ing (measured against a live cluster on SDK 4.1.3 AND 4.7.1; 4.2.0+ maps a bare `undefined` to null but still aborts on functions and Symbols). Reachable with NO misuse of the driver: the cursor-style assembly branch (queries matching `\w+\.($|%)`) fills `queryParams[i]` for every `i < params.length` while guarding only `undefined`, so a call one argument SHORT with a trailing callback puts the CALLBACK into a parameter slot — the arity check cannot catch that shape because it only fires when the last argument is not a function. `getUnserializableParamError()` now gates the single `queryOptions.parameters` assignment (so both assembly branches and any future one are covered) and surfaces a `TypeError` coded `GINA_COUCHBASE_UNSERIALIZABLE_PARAM` naming the offending position, routed through the query callback when there is one and thrown otherwise. Serializable values are untouched: `null`, `0`, `''`, `false` and objects carrying `undefined` PROPERTIES still reach the SDK. An object whose own `toJSON()` returns undefined is deliberately left unguarded — detecting it costs a full `JSON.stringify` per parameter on every query for a shape no realistic call site produces. **`.sql` `@options` annotation — the exact contract, and the consistency gate that silently dropped keys (former #282, #B155; warns since 0.5.26):** the parser accepts ONLY `@options { … }` — a brace-delimited JS-object-literal after exactly ONE space (unquoted keys fine: a key-quoting normalisation runs before `JSON.parse`; a malformed body warns and is skipped). The historical docs-taught brace-less form (`@options consistency=request_plus`) and a double-space-before-brace both MISS the parse regex entirely. The passthrough into the SDK's query options is GATED on the `consistency` key: any other key (`adhoc`, `timeout`, `profile`, …) applies ONLY when `consistency` is present alongside it — alone it is parsed then dropped. Since 0.5.26 BOTH failure shapes warn (was silent): an unparseable `@options` mention warns with the exact working form; a gate-shut drop warns naming the ignored keys + the `"consistency": "not_bounded"` remedy; an empty `@options {}` drops nothing and stays quiet. An UNKNOWN consistency VALUE warns and falls back to `not_bounded` but STILL opens the gate — the gate keys on presence, not validity. Query-path defaults: `adhoc: false` (statement plans cached — `true` disables that) + `not_bounded`; user keys WIN over framework values (direct assignment — including dev-mode's `profile: 'timings'`). `bulkInsert` is a SEPARATE surface: a JS `options` argument, UNGATED, merged caller-wins-on-conflict / defaults-fill-missing (its default is `adhoc: true`). The gate itself deliberately stays: un-gating would make historically-inert options suddenly live for every consumer, and a bare un-gate CRASHES (the next statement dereferences `options.consistency`) — a restructure gated on field evidence, which the warns now collect. Tests: `test/core/couchbase-connector.test.js §09` drives the SHIPPED parse+gate bytes (unique-text-anchored slices — line numbers rot and the parse block's regex holds an unbalanced `{` that defeats brace-matching).
889
+ 177. **Couchbase connector — install-derived SDK resolution (v2 removed), `connectors.json` semantics, `getCluster()`, dev-mode index reporting** (replaces individual entries #29, #40, #41, #57, #136, #153) — connectors are keyed in `schema/connectors.json` by LOGICAL name (`primary`, `sessionStore`, `cache`, …) with the driver selected by the `connector` enum field (`couchbase`/`mysql`/`postgresql`/`sqlite`/`redis`/`ai`/…) — never introduce a separate `driver` field; the optional `version` field carries a semver range used by `connector:add --driver-version=…` for the npm-install hint. The Couchbase SDK major is derived from the project's INSTALLED `couchbase` npm version — the leading major of `dependencies.couchbase` selects `connector.v<major>.js`, which stamps `conn.sdk = { version: N }` — never from a config key, so migrating SDK majors is a driver bump (`npm install couchbase@^4`), not a config edit. SDK v2 is REMOVED as of 0.4.0: the resolver now throws a clear "SDK v2 is no longer supported — upgrade couchbase@^3/^4" error when the installed major is ≤ 2 or the connector file is missing (previously a silent fallback that crashed later with an opaque MODULE_NOT_FOUND); the v3-vs-v4 split remains for param shaping. Generalises: when a connector's behavior-version derives from an installed dependency rather than config, fail fast once the installed major drops below the supported floor. Couchbase entities expose a public `getCluster()` (on both the model-entity and N1QL-entity prototypes) returning the underlying SDK `Cluster` handle for features the ORM doesn't wrap — chiefly multi-document ACID transactions (`cluster.transactions().run(...)`, needs SDK 3.2+/4.x) — without touching private `_*` internals; it throws a coded `GINA_COUCHBASE_CLUSTER_UNRESOLVED` error when neither connection shape resolves. Dev-mode index reporting: the SDK v4 C++ binding never populates `meta.profile` despite `profile: 'timings'` being sent (confirmed on v4.6.0), so an async `EXPLAIN <statement>` fallback with a per-process per-statement cache supplies the plan instead (the first request for a new statement may show N/A; subsequent requests hit the cache), and `USE KEYS` plans surface as "KV lookup" via `ExpressionScan`/`KeyScan` operator detection. Three historical traps locked by tests: `conn._cluster.query()` must receive the full `queryOptions` object, not the raw params array (the raw form silently dropped `profile`/`scanConsistency`/`adhoc` from every query); of the connector's two `register()` dispatch paths, Option B (`!_isRegisteredFromProto`) is the ALWAYS-active one — instrumentation or logging added to Option A never executes; and (#B193, 0.6.3) the plan walker must visit the NESTED scan containers, not just `~child`/`~children` — the multi-index operators (`IntersectScan`/`UnionScan`/`OrderedIntersectScan`) put their child `IndexScan3` nodes under a `scans` array and `DistinctScan` under a singular `scan`, so before the fix any plan the planner served with more than one index extracted `[]` and the Inspector rendered the red "no index — full bucket scan" badge/banner for a fully-indexed query — a false negative inviting a pointless (write-amplifying) index build. Both extraction paths (SDK `meta.profile` and the EXPLAIN fallback) share the walker, so one fix covers both; index names still dedupe, and the Query tab already renders one chip per index so multi-index plans display correctly with no client change. A consumer-runnable SDK soak harness ships at `script/soak/couchbase-soak.js` (#CN12): it scaffolds a fully isolated throwaway project, installs a candidate `couchbase` SDK into it (`--sdk=<version>` / `--sdk-path=<dir>` — the install IS the version selector, since the connector resolves the SDK from the project node_modules and derives v3/v4 dispatch from its dependency pin), builds + boots prod, and drives N1QL (incl. a `request_plus` arm) + entity-handle KV (promise AND 4-arg callback forms) + the couchbase session store under sustained concurrent load for `--duration`, FAILING on premature process exit (a clean exit 0 counts as failure — the silent-death class it screens for), unbounded RSS growth, error-rate drift, or a dead arm. A screen, not proof: run it as the first filter on an SDK-bump candidate, ahead of a workload-shaped soak. Pure parts (arg parsing, RSS slope, verdict) are unit-tested in `test/lib/couchbase-soak-evaluator.test.js`; the live harness needs a real cluster and never runs in CI. Named scopes/collections stance (2026-08-02): document-field partitioning (`_scope`/`_collection` fields, one bucket, default collection) IS the data model; the `useScopeAndCollections` option (+ `scope`/`collection` defaults) is accepted but INERT — declared and merged, consumed by nothing — and `schema/connectors.json` says so honestly; named-collection KV is reachable per call via `entity.getConnection(scope, collection)`; native scope/collection routing is deliberately not built (demand-gated). #B203 (2026-08-02): both SDK-major resolver twins derive the major as the dependency pin's FIRST integer — the former caret-only strip mangled range pins (`~4.5.0` → `~4`, `>=4.5` → `>=4`), which slipped the v2 floor (parseInt NaN) into a misdirecting existsSync "supported majors are 3 and 4" error; a digit-less pin (`*`, `latest`) now refuses naming the pin, a package.json without a `dependencies` key no longer TypeErrors, and the v2 floor fires for range v2 pins too (`~2.5.0`). #B243 (2026-08-04): a query parameter the SDK cannot serialize — a bare `undefined`, a function, or a Symbol — was PROCESS-FATAL rather than throwable: the SDK maps `JSON.stringify` over the parameter list, those three types yield no string at all, the native binding coerces that to `""`, and the C++ core's JSON parse of `""` throws on an internal thread reaching `std::terminate()`/`abort()` — uncatchable by `try/catch`, `uncaughtException` or `unhandledRejection`, so the whole bundle died instead of the request 500-ing (measured against a live cluster on SDK 4.1.3 AND 4.7.1; 4.2.0+ maps a bare `undefined` to null but still aborts on functions and Symbols). Reachable with NO misuse of the driver: the cursor-style assembly branch (queries matching `\w+\.($|%)`) fills `queryParams[i]` for every `i < params.length` while guarding only `undefined`, so a call one argument SHORT with a trailing callback puts the CALLBACK into a parameter slot — the arity check cannot catch that shape because it only fires when the last argument is not a function. `getUnserializableParamError()` now gates the single `queryOptions.parameters` assignment (so both assembly branches and any future one are covered) and surfaces a `TypeError` coded `GINA_COUCHBASE_UNSERIALIZABLE_PARAM` naming the offending position, routed through the query callback when there is one and thrown otherwise. Serializable values are untouched: `null`, `0`, `''`, `false` and objects carrying `undefined` PROPERTIES still reach the SDK. An object whose own `toJSON()` returns undefined is deliberately left unguarded — detecting it costs a full `JSON.stringify` per parameter on every query for a shape no realistic call site produces. **`.sql` `@options` annotation — the exact contract, and the consistency gate that silently dropped keys (former #282, #B155; warns since 0.5.26):** the parser accepts ONLY `@options { … }` — a brace-delimited JS-object-literal after exactly ONE space (unquoted keys fine: a key-quoting normalisation runs before `JSON.parse`; a malformed body warns and is skipped). The historical docs-taught brace-less form (`@options consistency=request_plus`) and a double-space-before-brace both MISS the parse regex entirely. The passthrough into the SDK's query options is GATED on the `consistency` key: any other key (`adhoc`, `timeout`, `profile`, …) applies ONLY when `consistency` is present alongside it — alone it is parsed then dropped. Since 0.5.26 BOTH failure shapes warn (was silent): an unparseable `@options` mention warns with the exact working form; a gate-shut drop warns naming the ignored keys + the `"consistency": "not_bounded"` remedy; an empty `@options {}` drops nothing and stays quiet. An UNKNOWN consistency VALUE warns and falls back to `not_bounded` but STILL opens the gate — the gate keys on presence, not validity. Query-path defaults: `adhoc: false` (statement plans cached — `true` disables that) + `not_bounded`; user keys WIN over framework values (direct assignment — including dev-mode's `profile: 'timings'`). `bulkInsert` is a SEPARATE surface: a JS `options` argument, UNGATED, merged caller-wins-on-conflict / defaults-fill-missing (its default is `adhoc: true`). The gate itself deliberately stays: un-gating would make historically-inert options suddenly live for every consumer, and a bare un-gate CRASHES (the next statement dereferences `options.consistency`) — a restructure gated on field evidence, which the warns now collect. Tests: `test/core/couchbase-connector.test.js §09` drives the SHIPPED parse+gate bytes (unique-text-anchored slices — line numbers rot and the parse block's regex holds an unbalanced `{` that defeats brace-matching). **#B204 (0.6.24) — the `gina.onError` reconnect classifier is guarded; it used to THROW under every supported SDK.** `lib/connector.v3.js`/`lib/connector.v4.js` tested `err instanceof couchbase.Error`, but no supported couchnode exports a bare `Error` class (measured on a real 4.1.3 `dist/errors.js`: `Error` undefined, `CouchbaseError` + 81 siblings present, and the classifier condition executed against that surface throws `TypeError: Right-hand side of 'instanceof' is not an object`). Because that operand is evaluated FIRST, the shutdown-bucket message arm — which needs no SDK class — was unreachable too, so the classifier could not classify anything by any route. **Dispatch topology, measured:** `gina.onError` listeners fire ONLY under 4-arg (Express-engine) error-middleware invocation; Isaac's dispatchers invoke middlewares 3-arg, so the arity shim sets `error = false` and the emit branch never runs — on Isaac the listener, broken or fixed, never executes. **Fix = guard, deliberately NOT an activation:** each `instanceof` is prefixed `typeof(couchbase.Error) == 'function' &&` (4 live sites, both files). Modern SDK errors carry no numeric `.code`, so the guarded arms stay inert; the SDK-2 message string greps 0 in the 4.1.3 dist JS (`timeout` firing as control); on Express the real error now reaches the handler's designed terminal (log + JSON 500 / `next(err)`) instead of being replaced by the TypeError. ⚠️ **Do NOT "modernize" this into an active reconnect without a live-cluster gate:** gina's own `connect()` mints a NEW cluster handle per call (`couchbase.connect` at `connector.v4.js:265`) and the only `disconnect()` sits inside the code-23 arm — an activated retry loop would stack unclosed handles. Also do NOT remove the listener: `e` (`gna.js:81`) is a plain EventEmitter, and an `'error'` emit with no listener THROWS (measured), so the registration is load-bearing on Express. Tests: `§16` (both files' real condition bytes extracted and driven — no-`Error` SDK must not throw and the message arm must be evaluable, with an SDK-2-shape control green pre- and post-fix; red-first 3 red / 2 green).
890
890
 
891
891
  178. **HTTP/2 query paths must tolerate a released response — retry re-entries and late upstream responses run after terminal exits (#B33, 2026-06-12, commit `9c2d802a`).** Terminal exits release the per-request refs, and `redirect()` releases them and THEN calls next(), so an inter-bundle HTTP/2 query can outlive its own request in three measured ways, each previously an uncaughtException → SIGTERM bundle kill: (1) every retry re-entry (the 502/timeout/stream-error/preflight setTimeout paths) re-executes the header-forward prep block, which read the released request's headers — null deref from a timer callback outside all try/catch; (2) a late upstream response's success path calls isHaltedRequest → getSession, which read the released request's session from the stream end handler; (3) a parsed upstream payload claiming a 3xx status routed into the redirect intercepts, which wrote headers to the released response (the emitter-mode intercept uncaught; the callback-mode one contained only via a fragile catch chain). All sites null-guarded: forwards and intercepts no-op on a released request (the same options object travels through retries, so options.headers already carries the attempt-1 values — nothing is lost), getSession reports no session, and the emitter-mode intercept falls through to the query#complete emit so listeners still learn the outcome. Live-request behaviour is byte-identical. Runtime-verified by driving the REAL query() through a standalone controller harness against local h2c servers (six probe modes, crash reproduced pre-fix and clean post-fix per site). Sibling unguarded request-header reads exist in OTHER lifecycle functions; the §23 guard pin is block-scoped to the fixed functions for exactly that reason. **Follow-up #B35 (2026-06-13, `714d816f`+next):** the 5 directly-callable SYNCHRONOUS siblings were MEASURED (standalone harness: createTestInstance → renderTEXT() releases the triplet → call → confirmed `uncaughtException`-class crash) and guarded with top-of-function early-returns — `isPopinContext` → false, `setRequestMethod` → null, `setRequestMethodParams` → (void), `getRequestMethodParams` → the cached value, `getFormsRules` → {} (tests `controller.test.js §25`). **#B36 (`c5eaeeb7`+next):** `renderJSON()` is the same shape — its delegate reads `local.res.stream` synchronously before any `headersSent` guard, measured (standalone harness driving the real `render-json.js` delegate: CONTROL live rendered, RELEASE after `renderTEXT()` threw `reading 'stream'`) to crash a released response → SIGTERM; guarded with a top-of-function `if (local.res == null) return` (tests `render-json.test.js §03`). The render-swig / render-nunjucks delegates share the same read but are the NON-FATAL async class (measured 2026-06-13, initially NOT guarded — GUARDED as of #B45, see below): their `render()` is `async` and `this.render` returns the delegate promise un-awaited, so a released-instance read rejects → `unhandledRejection` → `gna.js:726` logs it (no SIGTERM). This is the canonical severity-axis example — a SYNCHRONOUS released read (render-json `#B36`, the `#B35` helpers) is a SIGTERM bundle-kill worth guarding; the same read in an ASYNC delegate is a logged unhandledRejection not worth editing the hot render path for. **#B45 (2026-06-14, `d9bfc5af`) reversed that for the render delegates:** production surfaced exactly the predicted `unhandledRejection` (a controller firing several parallel `self.query()` calls against a downed upstream — the first failure callback renders+releases the triplet, a later callback re-enters `render()` at `local.res === null` → render-swig.js:259 `res.stream` throws), which is the #B36 "revisit only if the log noise proves operationally costly" trigger. All four async delegates (render-swig / render-nunjucks + both async variants) now carry the same top-of-function `if (local.res == null) return` guard as render-json/render-stream — one null check at the top, byte-identical on live requests; the rarer in-flight #M1 `setResources` race (render-swig.js:613 → controller.js:896, caught + #B31-guarded) is unchanged. The severity-axis lesson still holds (sync → SIGTERM → always guard; async → unhandledRejection → guard only once the noise is shown operationally costly) — #B45 is the worked example of the async "guard-when-costly" branch firing (tests `render-swig.test.js §19` / `render-nunjucks.test.js §08` / `render-engine-dispatch.test.js §08`). `redirect` GUARDED too (**#B37**, `a03e6f84`+next): measured synchronous, so a released second-call (redirect-then-redirect, or render-error-then-redirect) crashed `reading 'originalMethod'` → SIGTERM; top-of-function `if (local.req == null) return` (tests `controller.test.js §26`). **#B38 (2026-06-13) — the #B37 "SIGTERM class CLOSED" claim was premature: an exhaustive sweep of EVERY synchronous controller surface found SIX more lethal sync residuals, each measured (CONTROL no-throw / RELEASE positive crash, then no-throw post-guard) and guarded top-of-function with the same `if (local.req|res == null) return <default>` shape:** `downloadFromLocal` (`reading 'setHeader'`), the inner `start` of `store` (`reading 'files'` — reached SYNCHRONOUSLY through the documented `store(target).onComplete(cb)` wrapper, which calls `start` OUTSIDE the async `store` body; the #B35 probe had only tried `store('t')`, which returns the wrapper WITHOUT calling `start`, so `store` was wrongly filed as async-deferred here), `renderStream` (`reading 'stream'` — its controller wrapper AND the delegate are both synchronous, and the read precedes the delegate's headersSent guard, mirroring the #B36 render-json placement), `push` (`reading 'method'`), `pauseRequest` (`reading 'url'`), `resumeRequest` (`reading 'session'`/`'method'`) — tests `controller.test.js §27` + `render-stream.test.js §11`. Genuinely document-skipped (measured NON-FATAL, by the same async-boundary reasoning — the render delegates themselves since GUARDED, see #B45 above): `downloadFromURL` (its reads sit inside an `async function`, so any throw is a rejected promise → `unhandledRejection`), and the render-path inner fns `setResources` / `getNodeRes` (sync, but invoked ONLY from the async render delegates, so a throw rejects the delegate promise — and the captured-req fix-shape was declined because the captured req is itself null in the released-response case). **Rule: lethality follows the NEAREST async boundary, not the function's own sync/async keyword — a sync read with no async function between it and the dispatcher is a SIGTERM bundle-kill (guard it); the same read reached only through an async function degrades to a logged unhandledRejection (skip it). Probe-asymmetry corollary: "no throw" is NOT proof of safety — feed inputs that actually REACH the deref (`resumeRequest({})` dodged its `req.session` read via an `&&` short-circuit + an early `throwError` return and looked safe until re-measured with a deref-reaching input).** **#B44 (2026-06-14, commit `d95ac2fe`) — closes the one throwError-OWN residual the #B38 sweep flagged, and is the worked example of the measurement-scope-gap.** `throwError` reads `res.stream` (the HTTP/2 protocol branch) and then builds the error object from `res.error`/`res.stack`/`res.fallback` (~10 reads) BEFORE its OWN #B31 guard. For the 2-arg `throwError(code, Error|string)` and 3-arg `throwError(local.res, code, msg)` shapes `res` is already the released `local.res` (null) at those reads, so a released response crashed at `res.stream` on HTTP/2 bundles and at `res.error` on EVERY bundle (HTTP/1.1 reaches it because the `res.stream` read short-circuits off-h2). The 1-arg shape is unaffected (its `res` stays the truthy errObj until reassigned just before the guard — why #B31 sufficed for ITS scenario). Fixed with an up-front `if (!res) { warn; return false; }` early guard before any deref (tests `controller.test.js §28`); severity LOW (only the async `downloadFromURL` path reaches it today → non-fatal `unhandledRejection`), but it lifts the #B38 qualification for the synchronous 2-arg/3-arg surface on both protocols. **Measurement-scope-gap lesson: the FIRST-proposed fix (guard the `res.stream` read only) was INSUFFICIENT — it does NOTHING on HTTP/1.1 (already short-circuits there; the crash is at the `res.error` build) and merely RELOCATES the HTTP/2 crash to that same build. The prior repro was VERBATIM-TRUNCATED at the first crash line (it ran through the `res.stream` read, saw the TypeError, STOPPED), so it proved "the crash exists" but never executed the NEXT deref and so couldn't see that guarding one site just moves the crash. A repro that stops at the first crash cannot validate a "falls through to the guard" claim — match the repro's SCOPE to the claim's scope (the "match the measurement's scope to the claim's scope" rule, applied to a runtime repro). A per-site `&& res` is whack-a-mole here (~10 derefs before the guard); one early guard covers them all.** **The family's origin (#B31, folds former #172):** the first two guarded entry points were `throwError` — it normalizes every 1-/2-arg call shape to `res = local.res`, then read `typeof(res.getHeaders)` off the null — and `headersSent()` (read `typeof(_res.stream)`); both were uncaughtException → SIGTERM bundle kills with no application frames. Field shape: an auth middleware that 301-redirects unauthenticated requests and lets the chain continue makes the crash deterministic on every unauthenticated hit, and the crash-respawn loop keeps every process cold — masquerading as a separate "valid sessions never authenticate" bug (each request lands on a freshly-respawned process whose session-store connector hasn't warmed). Now `headersSent()` reports a released response as already-sent (a single chokepoint — every `!headersSent()` caller no-ops) and `throwError` logs the serialized late error (naming what previously died opaque) and returns false; live-response paths are byte-identical. Reusable repro recipe: `controller.js` loads standalone — inject the framework dir into NODE_PATH + `Module._initPaths()`, require the framework helpers (injects the path/JSON globals), `setPath('gina', { core: <fw>/core })`, then `SuperController.createTestInstance({req, res, next, options})` with a minimal mock response; `renderTEXT()` is the lightest terminal exit to reproduce any released-response sequence against the real class.
892
892
 
@@ -1004,7 +1004,7 @@ Dev-mode query instrumentation captures every database query tied to the current
1004
1004
 
1005
1005
  294. **DuckDB connector (`"connector": "duckdb"`) — embedded analytical (columnar / OLAP) store with the standard entity wiring.** Config keys: `database` (names the model dir `models/<database>/` AND the default file), `file` (path or `':memory:'`; defaults to `~/.gina/{database}.duckdb`), `readOnly` (driver `access_mode: 'READ_ONLY'`), `scope`. Driver: `@duckdb/node-api`, installed in the PROJECT — a caret pin `^1.5.5` fails npm E404 because the package publishes only prerelease-suffixed versions (`1.5.5-r.2`) and a caret never matches another version's prerelease tuple; use `>=1.5.5-r.0 <2`. Entity SQL loads from `models/<database>/sql/<Entity>/*.sql` (or flat `<Entity>_<method>.sql`) with `@param` casting (number/integer, float with comma→dot, string) and `@return {object|array|boolean|number}` shaping; `?` and `$1` both bind positionally as an array. Row-returning detection is dialect-wide (`SELECT|WITH|FROM|SUMMARIZE|PIVOT|UNPIVOT|DESCRIBE|SHOW`) because a bare ^SELECT test routes CTEs to the write path, where run() reports rowsChanged 0 and the rows are silently lost (measured). Rows come from `getRowObjectsJson()` — BIGINT/HUGEINT/DECIMAL/DATE/TIMESTAMP and COUNT values arrive as STRINGS (pg parity; `@return {number}` Number()s a COUNT result); the non-Json row getters leak BigInt wrappers that would crash renderJSON. Writes return `{changes}` (no insertId analog). Locks (measured): single-writer ACROSS processes — while one process holds a file read-write, no other process can open it at all; any number of READ-ONLY processes share one file; same-process re-open is fine (merged-process bundles share cleanly). `count` is an UNUSABLE SQL-method name on EVERY gina SQL connector (mysql/postgresql/sqlite/duckdb): gina extends Object.prototype with a property-counting `count()` helper (and `functionCount`), and the shared already-defined skip-guard (`typeof prototype[name] !== 'undefined'` — a prototype-chain lookup) silently refuses to attach `count.sql`, so calls hit the global helper instead of the query; rename the file (e.g. `countRows.sql`) — since 0.6.1 that skip is warned at boot (#B173). Errors stamp PERMANENT via the connector-error classifier (embedded engine — no transient network class). QI type `DUCKDB`; live index introspection via `duckdb_indexes()` in dev. The NAPI addon loads and queries under Bun (measured on 1.2.x).
1006
1006
 
1007
- 295. **Inherited-name collisions in query-file loaders warn at boot (#B173, 0.6.1).** Six ORM connectors (mysql, postgresql, sqlite, duckdb, scylladb, mongodb) attach file-derived methods (`sql/<Entity>/<name>.sql`, `cql/…`, `pipelines/<Entity>/<name>.json`) behind `typeof entities[E].prototype[name] !== 'undefined'` — a prototype-CHAIN lookup, so a file named after an inherited member (gina's `Object.prototype` extensions `count()`/`functionCount()`, EventEmitter's `on`/`once`/`emit`, the entity base API) was silently skipped and calls fell through to the inherited member, returning a plausible value of the right type (`count.sql` → the global property counter). Since 0.6.1 the skip logs a `console.warn` through the connector's gina-logger shadow (level `warn`=4 passes the default `log_level: "info"`=6) naming the method, source file path, entity, and a rename hint (`countRows.sql`); own-property collisions still skip SILENTLY by design — user code in the entity `.js` wins over a same-named query file. The skip/attach set is byte-identical to before (the warn sits inside the already-taken branch; behavior verified unchanged live on an isolated boot with a pre-fix control). Couchbase is the deliberate exception: it attaches unconditionally, so there a colliding name SHADOWS the inherited member instead of being skipped (a file named `on.sql` would clobber EventEmitter's `on` for that entity) — and since 0.6.1 that clobber ALSO warns at boot (#B174): an own-member overwrite (a stamped entity property, a previously attached query method) or a non-`Object.prototype` inherited shadow (the EventEmitter API) logs the file path with a rename hint, while shadowing `count()`/`functionCount()` stays silent — there the query file winning is the point. Couchbase attachment behavior itself is unchanged: the warn never skips the file.
1007
+ 295. **Inherited-name collisions in query-file loaders warn at boot (#B173, 0.6.1).** Six ORM connectors (mysql, postgresql, sqlite, duckdb, scylladb, mongodb) attach file-derived methods (`sql/<Entity>/<name>.sql`, `cql/…`, `pipelines/<Entity>/<name>.json`) behind `typeof entities[E].prototype[name] !== 'undefined'` — a prototype-CHAIN lookup, so a file named after an inherited member (gina's `Object.prototype` extensions `count()`/`functionCount()`, EventEmitter's `on`/`once`/`emit`, the entity base API) was silently skipped and calls fell through to the inherited member, returning a plausible value of the right type (`count.sql` → the global property counter). Since 0.6.1 the skip logs a `console.warn` through the connector's gina-logger shadow (level `warn`=4 passes the default `log_level: "info"`=6) naming the method, source file path, entity, and a rename hint (`countRows.sql`); own-property collisions still skip SILENTLY by design — user code in the entity `.js` wins over a same-named query file. The skip/attach set is byte-identical to before (the warn sits inside the already-taken branch; behavior verified unchanged live on an isolated boot with a pre-fix control). Couchbase is the deliberate exception: it attaches unconditionally, so there a colliding name SHADOWS the inherited member instead of being skipped (a file named `on.sql` would clobber EventEmitter's `on` for that entity) — and since 0.6.1 that clobber ALSO warns at boot (#B174): an own-member overwrite (a stamped entity property, a previously attached query method) or a non-`Object.prototype` inherited shadow (the EventEmitter API) logs the file path with a rename hint, while shadowing `count()`/`functionCount()` stays silent — there the query file winning is the point. Couchbase attachment behavior itself is unchanged: the warn never skips the file. **A registration that fails OUTRIGHT now names itself too (#B461, 0.6.24).** Couchbase's `readSource()` guards the whole entity-class construction and `.sql`-derived method attachment — `inherits(EntityN1qlClass, EntitySuperClass)`, the prototype stamping (`name`/`model`/`_collection`/`getCluster`), and the per-method attachment — under a SINGLE ~770-line try whose catch was a bare `console.error(err.stack)`. None of `readSource()`'s three call sites captures a return value or takes an error argument, so nothing downstream could observe the failure either: a throw in that block (a malformed `.sql`, a bad `inherits` target, a collision the guard above does not cover) left the entity partially built — or absent — while boot continued green, and the first symptom was a missing method at REQUEST time, arbitrarily far from the cause. The catch now emits a named diagnostic first — entity, source file, the method being attached, and the underlying cause — and still emits the original stack, so observability is added, never traded. ⚠️ **Boot behaviour is deliberately UNCHANGED: a failed registration stays non-fatal.** Making an unbuildable entity fatal is defensible (fail fast) but is a consumer-visible behaviour change — a project that boots today through a swallowed error would stop booting — so it is a separate decision, not a by-product of adding a log line. Generalises: **when one `try` spans a whole construction phase and its catch neither rethrows nor signals, the catch is the ONLY place the failure exists — so it must at minimum name what failed**, and widening the diagnostic is separable from changing whether the failure is fatal. Distinct from the per-call return-contract defect in `bulkInsert` (#B460, same file, same release): that one inverts a public method's contract on every call; this one breaks registration once, at boot. Tests: `test/core/couchbase-connector.test.js §15` (5 arms — source pins over the comment-stripped catch, the real catch body EXTRACTED and EXECUTED to assert the rendered message carries entity/file/cause, a pin that the pre-existing `err.stack` line survives, and a control proving a DIFFERENT catch in the same file does not satisfy the needles; red-first 2 red / 3 green).
1008
1008
 
1009
1009
 
1010
1010
 
@@ -1024,7 +1024,7 @@ Dev-mode query instrumentation captures every database query tied to the current
1024
1024
 
1025
1025
  310. **`Collection.replace()` resolves its comparison key from BOTH sides — the stored entry AND the caller's `set` (#B393, gh issue #64, shipped in 0.6.11).** `replace(filter, set[, key])` locates each entry to overwrite by comparing a key on the stored row against the same key on `set`. That key used to be chosen by inspecting the STORED row alone: it defaulted to the internal `_uuid`, fell back to `id` only when the stored row had no `_uuid`, and threw `No comparison key defined !` only in that same stored-row-lacks-it case. So the one combination neither branch covered — **stored row HAS `_uuid`, `set` does NOT** — compared `<storedUuid> == undefined`, which is never true: nothing matched, nothing was replaced, no error was raised, and the call returned a chainable result that looked successful. A silent, lossy write. Reachability is the non-obvious part: a Collection built from fresh raw data keeps no `_uuid` on the instance rows, so the `id` fallback fires and the call works — the defect appears only once the caller has **re-loaded an array a previous chained call returned**, because chained results carry the internal `_uuid` on every row the call did not replace (and `toRaw()` KEEPS a `_uuid` the caller supplied, since the constructor stamps `_hasItsOwnUuid` on reload). That is why it presents as intermittent rather than constant, and why persisting a chained result is the trigger. Now: the key is resolved per entry from both sides, falling back to `id` when BOTH carry one, and refusing loudly when the two sides share no usable key — so the previously-silent combination is no longer the quiet one. An explicitly supplied `key` argument is honoured exactly as before (no fallback, no refusal). The resolved key is also scoped per entry instead of assigned to the shared variable, so a fallback taken for one row can no longer apply to rows examined after it. Every previously-working shape is unchanged, including `set` carrying a matching `_uuid` and the fresh-collection `id` path. **`lib/collection` IS in the browser `build.json`, so pickup is a bundle RESTART **and** a re-bake.**
1026
1026
 
1027
- 311. **Per-call identity for concurrent entity calls — the ENTITY layer pairs each emit to the call it came from by AsyncLocalStorage identity (#B440, 0.6.20 — SECURITY; it was FIFO-paired from #B394 in 0.6.11 until then), the COUCHBASE CONNECTOR layer settles per call (#B429/#B430/#B431, 0.6.19). Two different mechanisms; do not reason from one to the other.** ⚠️ The description below covers ONLY hand-written entity methods that call `self.emit('<shortName>#<method>')` — and registration is a SOURCE-TEXT scan (`entity.js` tests `entity[prop].toString()` for the literal, comments INCLUDED): a comment that merely names the trigger registers the method, passing the trigger name to a helper registers it, and removing the last occurrence un-registers it (plain function: no wrapper, no `.onComplete()`, no Promise return — a call-contract change for its callers). Methods generated from `.sql` files never reach it — `core/model/entity.js:349-351`/`:414-417` say so verbatim (the connector emits the PREFIXED `N1QL:entity#method`, the entity buffer listens on the unprefixed name), so their guarantees come from the connector, described at the end of this entry. **Entity layer (`core/model/entity.js`):** The `util.promisify` fast-path (taken when a method is called detached — `this[m]` undefined + trailing function arg) used to back its pending callback into a SCALAR slot (`entity._callbacks[shortName] = cb`) plus a per-call `.once` guarded on that slot. Two concurrent calls on the SAME method raced on the one slot: the second overwrote the first, the first-arriving result was flushed to the LAST-registered callback (cross-delivery — caller B receives caller A's record), and the displaced caller's `.once` found its guard false so its promise NEVER settled (starvation — a hung request, nothing logged; the write-path variant silently persists A's document under B's key). Option B (entity-context calls) had already been given a FIFO queue + one persistent `.on` dispatcher (#M2); the fast-path kept the scalar because its own comment claimed it "bypasses queue". Now it uses the same shape: push each invocation's callback onto `entity._callbacks[shortName]` (an array), register ONE persistent `_onFpQueueEmit` dispatcher (guarded on `listenerCount === 0`) that shifts the OLDEST callback per emit and removes itself when the queue drains. The custom `emit`'s third guard already routes an ARRAY slot straight to native emit (skips `setListener` when `!Array.isArray`), so the `.on` listener receives the emit args directly. Guarantees after #B394: no callback is ever orphaned by a SIBLING call's overwrite; cross-delivery closed for in-order completion. ⚠️ **#B394's "starvation ELIMINATED" was TOO STRONG, and its documented out-of-order residual was the smaller half of the problem — #B440 (0.6.20, SECURITY): ONE lost emit permanently desynchronised the FIFO.** Both dispatchers paired an emit to the OLDEST queued resolver with no call identity, so a call that never emitted (canonically a throw inside an un-awaited `async` callback BEFORE the emit — swallowed, only `unhandledRejection` sees it) left its resolver at the head forever: with overlapping callers every later caller of that method received the NEXT caller's record and the last one hung; sequential callers all hung; the desync survives dev hot-reload and DEEPENS by one dead resolver per lost emit (measured in a real boot on both call forms: `LOSE→B, B→C, C→D, D HUNG, LATER HUNG`). Same failure shape as #B429 — where the method reads a user-scoped record, an ownership check can pass on another principal's row — hence a Security entry. The trigger is DATA-dependent (an unexpected record shape), not load-dependent: invisible in a load test, inevitable in a long-lived process. **Fix:** every wrapped call runs inside a per-process `AsyncLocalStorage` (`process.gina._entityCallALS`, shared across hot-reload generations) carrying `{ e, r }` (trigger + this call's resolver); both dispatchers call `_dequeueByIdentity(q, e)` — store names THIS trigger ⇒ splice that call's own resolver, or DROP the emit if that call already settled (never hand a late completion to the head: the tempting forget-then-`shift()` variant measurably hands A's late record to B); no store, or another trigger's ⇒ `shift()` in arrival order plus a levelled `DISPATCH:NO_CONTEXT` debug line — the honest boundary, a completion reaching the entity outside every call's async context (e.g. a native driver invoking callbacks from a loop started at boot), measured identical to pre-fix. Resolvers `_forget` themselves on settle while the persistent listener stays, which is what makes a late duplicate emit DROP instead of being buffered into `_arguments` and poisoning the next fast-path call. The fast-path now captures `cached.apply()`'s return and chains `_fpInner.then()` — its old comment claimed an escape via `_innerResult.then()` that exists only in Option B, so a Promise-returning method was immune on Option B and NOT on the fast-path (measured; a consumer's promisify→direct-await conversion was therefore necessary, not belt-and-braces). The fast-path also runs the caller's raw callback inside the store that was active when the call was made, so an entity method that calls another entity's method with a direct callback and emits its own completion from inside it still pairs by identity (measured: without that it fell back to arrival order; `.onComplete`/`.then`/promisify chains pair by identity regardless, because promise continuations keep their context). The #B394 out-of-order residual is CLOSED as a by-product (each own on both forms; `entity-promisify-concurrency.test.js` §03 now pins each-own). **Opt-in bound `settings.json > model.emitTimeout` (ms; absent/0 = no bound, the previous liveness contract; schema + settings reference + Models guide document it):** read once per entity at wrap time via `self.getConfig(self.bundle,'settings')`, it rejects a call that never completes with an Error naming the trigger and `#B440` and logs the same line at warn; set it above the slowest legitimate bulk operation, which is why there is no default. Cost ≈ +3.6 µs/call. Test `test/core/entity-call-identity.test.js` (22 arms across both call forms — lost emit, the bound, a lone later caller, out-of-order, the fast-path Promise chain, late-duplicate drop, callback chain, no-context fallback with its debug line, config read, drain; red-first on the pre-fix bytes through its `B440_ENTITY_SRC` lever: 17 red, the 5 green are the labelled controls). ⚠️ The published Models guide's concurrency note used to promise *"no call is ever left hanging"* — false before #B440 and true only under the bound — and its `insert` example wrapped a synchronous `try/catch` around an asynchronous callback, which cannot catch a throw raised inside that callback: the trigger shape itself. Both corrected in the same release. Framework-internal `promisify` sites (`controller.js` `self.query`, `form-validator.js`) promisify a CONTROLLER method, not an entity trigger, so they never enter this branch (gated on `entity._triggers`). Server-side only — NOT browser-bundled, so pickup is a bundle RESTART, no re-bake. Test `test/core/entity-promisify-concurrency.test.js` (4 arms, bounded-settle so a regression fails rather than hangs; red-first validated against pre-fix bytes — serial control green, the three concurrency arms red; §03 tightened to each-own by #B440). **Couchbase connector layer (`core/connectors/couchbase/index.js`, #B429, 0.6.19 — SECURITY):** the completion trigger `'N1QL:'+entity+'#'+method` carries NO call identity and is emitted on the entity SINGLETON (`EntitySuper[Name].instance`, `entity.js:475-493`), so the Promise/`await`/`.onComplete()` path — which reached `self.once(trigger)` because its `_internalCb` is a function — was settled by a listener EVERY in-flight caller of that method shared. Node fires all listeners on one emit, so the first completion woke them all with ITS payload and removed them: a BROADCAST, **not** arrival-order pairing, so it cross-delivered on IN-ORDER completion too (measured `A→A, B→A`) — strictly worse than the entity-layer residual above, and the reason a confidentiality/authorization concern arises (an ownership read answered with another caller's row). The explicit trailing-callback form was always safe (it settles from `onQueryCallback`'s own closure). **Fix:** the Promise path assigns `_mainCallback = _internalCb` so BOTH forms settle through one per-call `_deliver()` guard; `register()` collapses to a single dispatch and `_isRegisteredFromProto` is retired (measured inert — reset every invocation, and `register` has no `await`, so it never actually starved a query); the early error emit is gone; ONE emit per completion remains, deliberately, because `entity.js`'s emit override forwards an `N1QL:*`-matched trigger to `lib/inspector-events` (verified live) — a side effect is that the bridge now also sees direct-callback completions it previously missed. `bulkInsert` carried the same defect independently (its own trigger + `once`) and is fixed the same way. **Siblings found while fixing it:** #B430 — the delivery `catch` re-invoked a THROWING caller callback with the same payload (ran it twice); #B431 — all three dispatches chained `.catch(onError).then(onResult)`, and a `.catch()` returning normally RESOLVES, so the trailing `.then()` ran on EVERY error and settled a second time with a bogus empty success (measured: `(Error,null,undefined)` then `(false,null,{})`, so `if (err) return next(err); render(data)` ran BOTH branches; invisible on the await path because a promise settles once, but it is why a failed query emitted 3×). Now `.then(onResult, onError)` — mutually exclusive branches — at all three sites. **Scope, PER DEFECT — the `.once(`/`.emit(` count scopes #B429 ONLY** (it requires a shared emitter; #B430/#B431 involve none, so that instrument is structurally blind to them — an over-scoped 'couchbase only' was relayed on 2026-08-27 and retracted the same day). **#B429: couchbase ONLY** — the other six ORM connectors settle on a per-call native Promise and use the trigger for debug/inspector logging only (`.once(`/`.emit(` = 0 in each, 12 in couchbase). **#B431: couchbase ONLY, verified with a PAREN-MATCHING scanner** (a character-window regex false-positived twice by spanning `});`+`return`+`else` into a different statement's `.then`) — validated against the pre-fix file as a known positive: 3 there, 0 across all nine connectors now. **#B430's class IS present elsewhere — triaged 2026-08-28 as #B432, and the count is 53, not the ~20 the first pass suggested.** A caller's callback is application code and throws for ordinary reasons (a template error, a null deref in a handler); two shapes then ran it a SECOND time with a different payload — the sync `try { cb(null, rows); } catch (e) { cb(e); }`, and the mirror `.then(function(){ cb(null, rows); }).catch(function(e){ cb(e); })`, whose trailing catch is reached when the SUCCESS handler throws. Both deliver a success and then an error for one operation (so `if (err) { return next(err); } render(data);` runs BOTH branches) and the second call reports the caller's own exception as a database failure. ⚠️ **Four instrument corrections, each of which had produced a wrong reading:** (1) a hand-written settle-name list MISSES the real callbacks — derive them per file (a param that is invoked, an `args.pop()` capture, a resolver binding); the stores settle through `fn`, and 35 sites hid behind a `0`. (2) A settle reached through a LOCAL HELPER is invisible without a fixpoint pass (`attempt`, `runQuery`, `withCollection`). (3) A lexical try/catch pair is NOT a defect when the settle sits in a nested async callback (its throw never reaches the enclosing sync catch — this alone cleared mysql, postgresql and duckdb) nor when an inner `try/catch` swallows it first, nor when the trailing settle lives in a SIBLING `else` branch. (4) A native promise resolver settles once, so a double settle through `_resolve`/`_reject` is BENIGN — 7 of 60 findings. Validate any such scanner on the pre-fix couchbase file as a known positive (it must report the #B430 site and both #B431 sites) and on the post-fix file (0). **Measured clean, both directions: mysql, postgresql, duckdb, ai** (`ai` has no callback path at all — only a native resolver). **FIXED in the entity dispatch path (0.6.19):** `core/connectors/settle-once.js` — a dependency-free sibling of `param-redact`/`sql-parser` exposing `settleOnce(label, cb, reporter)`, which returns a PER-CALL guard that delivers at most once, forwards any arity, and reports a callback throw (tagged with the query trigger) instead of replaying it. ⚠️ Build it per invocation, never at module scope — a module-scope guard would let the FIRST call suppress every later one. Wired at sqlite (`node:sqlite` is synchronous, so its callback ran inside the `try` with no microtask boundary — the most reachable instance of the whole class), mongodb (callback dispatch AND the unknown-op branch, which is reachable because `op` is validated only for falsiness, never against the recognised list) and scylladb. `couchbase/index.js` keeps its own inline `_deliver()` — the reference implementation this module generalises. **Store layers — the same shape with framework-supplied callbacks, fixed at METHOD ENTRY** by rebinding (`fn = settleOnce(label, fn, console)` immediately after the `fn = noop` normalization), so every settle path in the method — nested try/catch AND promise chain — funnels through one guard: **session stores** (couchbase v3/v4, mongodb, redis, scylladb, sqlite — 30 methods) and the **async-job stores** (mongodb, sqlite — 10 methods). ⚠️ **A LEXICAL scanner still reports these files HARMFUL, and that is CORRECT-and-expected, not a regression** — the fix REBINDS `fn` rather than renaming call sites, so the matched `fn(...)`-in-try-plus-catch shape is unchanged. A syntactic scanner's post-fix reading is evidence ONLY when the fix changed the syntax it matches; when it rebinds, the verification burden moves entirely to behavioural coverage (`connector-settle-parity.test.js` §05/§06, one arm per store over EXTRACT-AND-EXECUTED shipped bytes plus a wrap census pinning method-count == wrap-count per file). **Connector open paths (`mongodb`/`scylladb` `lib/connector.js` `onReady`) — FIXED, wrapped CONDITIONALLY** (`if (typeof fn === 'function') fn = settleOnce(…)`; measured: an unconditional wrap turns a missing callback from a loud `fn is not a function` rejection into a silent boot hang). The handler is `core/model/index.js`'s `connect` continuation; measured through the real bytes of both, a throwing continuation was re-invoked with a fabricated `Connection failed: <its own message>` AND the connector registry cache was overwritten to `err=<fabricated>, conn=null`, served to every later `connect()` for the process life — now 1 invocation, `err=null`, cache intact, the exception reported under `<connector>:connector#onReady`. The sqlite `inspector#indexes` listener is guarded for consistency (its `_ixCollector` caller has no throwing path; if it ever did, the double decrement would answer `/_gina/indexes` early with partial data). **Couchbase storage-store — CONVERTED to the shared guard** (its own local `once()` already prevented the double settle — measured on all 9 verbs with a firing subtract-control — but its JSDoc claim that the exception 'surfaces as an unhandled rejection' was FALSE on all nine: six verbs lost it silently, three (`stats`/`listZeroRefs`/`listKeys`) logged it misattributed as `<verb> failed`); now 9 wraps at verb entry (`couchbase:storage#<verb>`, reporter = the file's own global `console`), the exception reported once and never entering the CAS-retry / `withCollection` catches. The `once`→`settleOnce` swap is inert for callers: no consumer of any verb's return value exists (measured), and every strategy closure opens `if (err) return fn(err)`. **Every one of the 53 triaged sites is now guarded — the class is CLOSED** (4 entity-dispatch + 24 session-store + 10 job-store + 5 connector-open/Inspector + 10 storage-store). Test `test/core/connector-settle-parity.test.js` (one contract declared ONCE and run against every fixed connector, plus a deliberately UNGUARDED replica that must fail the discriminating arms — without it a spec every backend passes could be a spec asserting nothing; red-first measured 11 pass / 19 fail pre-fix, with every green in the code-the-fix-does-not-change bucket). Server-side only, pickup = bundle RESTART, no re-bake. Test `test/core/couchbase-concurrency.test.js` (25 arms booting the REAL connector against a controllable cluster stub so completion ORDER is chosen not raced; callback arms CAPTURE every invocation behind a grace window so a double settle is observable; red-first validated — 16 red pre-fix, and the arms that stay GREEN pre-fix are exactly the controls: serial, explicit-callback, mixed-form-no-starvation, success paths, the Inspector bridge).
1027
+ 311. **Per-call identity for concurrent entity calls — the ENTITY layer pairs each emit to the call it came from by AsyncLocalStorage identity (#B440, 0.6.20 — SECURITY; it was FIFO-paired from #B394 in 0.6.11 until then), the COUCHBASE CONNECTOR layer settles per call (#B429/#B430/#B431, 0.6.19). Two different mechanisms; do not reason from one to the other.** ⚠️ The description below covers ONLY hand-written entity methods that call `self.emit('<shortName>#<method>')` — and registration is a SOURCE-TEXT scan (`entity.js` tests `entity[prop].toString()` for the literal, comments INCLUDED): a comment that merely names the trigger registers the method, passing the trigger name to a helper registers it, and removing the last occurrence un-registers it (plain function: no wrapper, no `.onComplete()`, no Promise return — a call-contract change for its callers). Methods generated from `.sql` files never reach it — `core/model/entity.js:349-351`/`:414-417` say so verbatim (the connector emits the PREFIXED `N1QL:entity#method`, the entity buffer listens on the unprefixed name), so their guarantees come from the connector, described at the end of this entry. **Entity layer (`core/model/entity.js`):** The `util.promisify` fast-path (taken when a method is called detached — `this[m]` undefined + trailing function arg) used to back its pending callback into a SCALAR slot (`entity._callbacks[shortName] = cb`) plus a per-call `.once` guarded on that slot. Two concurrent calls on the SAME method raced on the one slot: the second overwrote the first, the first-arriving result was flushed to the LAST-registered callback (cross-delivery — caller B receives caller A's record), and the displaced caller's `.once` found its guard false so its promise NEVER settled (starvation — a hung request, nothing logged; the write-path variant silently persists A's document under B's key). Option B (entity-context calls) had already been given a FIFO queue + one persistent `.on` dispatcher (#M2); the fast-path kept the scalar because its own comment claimed it "bypasses queue". Now it uses the same shape: push each invocation's callback onto `entity._callbacks[shortName]` (an array), register ONE persistent `_onFpQueueEmit` dispatcher (guarded on `listenerCount === 0`) that shifts the OLDEST callback per emit and removes itself when the queue drains. The custom `emit`'s third guard already routes an ARRAY slot straight to native emit (skips `setListener` when `!Array.isArray`), so the `.on` listener receives the emit args directly. Guarantees after #B394: no callback is ever orphaned by a SIBLING call's overwrite; cross-delivery closed for in-order completion. ⚠️ **#B394's "starvation ELIMINATED" was TOO STRONG, and its documented out-of-order residual was the smaller half of the problem — #B440 (0.6.20, SECURITY): ONE lost emit permanently desynchronised the FIFO.** Both dispatchers paired an emit to the OLDEST queued resolver with no call identity, so a call that never emitted (canonically a throw inside an un-awaited `async` callback BEFORE the emit — swallowed, only `unhandledRejection` sees it) left its resolver at the head forever: with overlapping callers every later caller of that method received the NEXT caller's record and the last one hung; sequential callers all hung; the desync survives dev hot-reload and DEEPENS by one dead resolver per lost emit (measured in a real boot on both call forms: `LOSE→B, B→C, C→D, D HUNG, LATER HUNG`). Same failure shape as #B429 — where the method reads a user-scoped record, an ownership check can pass on another principal's row — hence a Security entry. The trigger is DATA-dependent (an unexpected record shape), not load-dependent: invisible in a load test, inevitable in a long-lived process. **Fix:** every wrapped call runs inside a per-process `AsyncLocalStorage` (`process.gina._entityCallALS`, shared across hot-reload generations) carrying `{ e, r }` (trigger + this call's resolver); both dispatchers call `_dequeueByIdentity(q, e)` — store names THIS trigger ⇒ splice that call's own resolver, or DROP the emit if that call already settled (never hand a late completion to the head: the tempting forget-then-`shift()` variant measurably hands A's late record to B); no store, or another trigger's ⇒ `shift()` in arrival order plus a levelled `DISPATCH:NO_CONTEXT` debug line — the honest boundary, a completion reaching the entity outside every call's async context (e.g. a native driver invoking callbacks from a loop started at boot), measured identical to pre-fix. Resolvers `_forget` themselves on settle while the persistent listener stays, which is what makes a late duplicate emit DROP instead of being buffered into `_arguments` and poisoning the next fast-path call. The fast-path now captures `cached.apply()`'s return and chains `_fpInner.then()` — its old comment claimed an escape via `_innerResult.then()` that exists only in Option B, so a Promise-returning method was immune on Option B and NOT on the fast-path (measured; a consumer's promisify→direct-await conversion was therefore necessary, not belt-and-braces). The fast-path also runs the caller's raw callback inside the store that was active when the call was made, so an entity method that calls another entity's method with a direct callback and emits its own completion from inside it still pairs by identity (measured: without that it fell back to arrival order; `.onComplete`/`.then`/promisify chains pair by identity regardless, because promise continuations keep their context). The #B394 out-of-order residual is CLOSED as a by-product (each own on both forms; `entity-promisify-concurrency.test.js` §03 now pins each-own). **Opt-in bound `settings.json > model.emitTimeout` (ms; absent/0 = no bound, the previous liveness contract; schema + settings reference + Models guide document it):** read once per entity at wrap time via `self.getConfig(self.bundle,'settings')`, it rejects a call that never completes with an Error naming the trigger and `#B440` and logs the same line at warn; set it above the slowest legitimate bulk operation, which is why there is no default. Cost ≈ +3.6 µs/call. Test `test/core/entity-call-identity.test.js` (22 arms across both call forms — lost emit, the bound, a lone later caller, out-of-order, the fast-path Promise chain, late-duplicate drop, callback chain, no-context fallback with its debug line, config read, drain; red-first on the pre-fix bytes through its `B440_ENTITY_SRC` lever: 17 red, the 5 green are the labelled controls). ⚠️ The published Models guide's concurrency note used to promise *"no call is ever left hanging"* — false before #B440 and true only under the bound — and its `insert` example wrapped a synchronous `try/catch` around an asynchronous callback, which cannot catch a throw raised inside that callback: the trigger shape itself. Both corrected in the same release. Framework-internal `promisify` sites (`controller.js` `self.query`, `form-validator.js`) promisify a CONTROLLER method, not an entity trigger, so they never enter this branch (gated on `entity._triggers`). Server-side only — NOT browser-bundled, so pickup is a bundle RESTART, no re-bake. Test `test/core/entity-promisify-concurrency.test.js` (4 arms, bounded-settle so a regression fails rather than hangs; red-first validated against pre-fix bytes — serial control green, the three concurrency arms red; §03 tightened to each-own by #B440). **Couchbase connector layer (`core/connectors/couchbase/index.js`, #B429, 0.6.19 — SECURITY):** the completion trigger `'N1QL:'+entity+'#'+method` carries NO call identity and is emitted on the entity SINGLETON (`EntitySuper[Name].instance`, `entity.js:475-493`), so the Promise/`await`/`.onComplete()` path — which reached `self.once(trigger)` because its `_internalCb` is a function — was settled by a listener EVERY in-flight caller of that method shared. Node fires all listeners on one emit, so the first completion woke them all with ITS payload and removed them: a BROADCAST, **not** arrival-order pairing, so it cross-delivered on IN-ORDER completion too (measured `A→A, B→A`) — strictly worse than the entity-layer residual above, and the reason a confidentiality/authorization concern arises (an ownership read answered with another caller's row). The explicit trailing-callback form was always safe (it settles from `onQueryCallback`'s own closure). **Fix:** the Promise path assigns `_mainCallback = _internalCb` so BOTH forms settle through one per-call `_deliver()` guard; `register()` collapses to a single dispatch and `_isRegisteredFromProto` is retired (measured inert — reset every invocation, and `register` has no `await`, so it never actually starved a query); the early error emit is gone; ONE emit per completion remains, deliberately, because `entity.js`'s emit override forwards an `N1QL:*`-matched trigger to `lib/inspector-events` (verified live) — a side effect is that the bridge now also sees direct-callback completions it previously missed. `bulkInsert` carried the same defect independently (its own trigger + `once`) and is fixed the same way. **`bulkInsert` also carried a SECOND, unrelated defect that #B429 did not reach — #B460 (0.6.24): its outer `try` wraps its OWN function body, so a synchronous throw in the prologue was caught, `console.error`d and swallowed, and the method fell off the end returning `undefined`.** Both documented shapes broke on that path: the `await` form (its own docblock's first `@example`) resolved with `undefined` — a caller treating "did not throw" as success recorded an insert that never happened — and `.onComplete(cb)` threw a TypeError on `undefined`; in both, the error existed only in the log and was unreachable to the caller. ⚠️ **The trigger is NOT only a cluster outage:** the prologue carries two DELIBERATE argument validations (`rec` falsy; a record without `.values`) whose errors the author wrote to reach the caller, which makes the defect reproducible with no cluster at all — `entity.bulkInsert(undefined)` is a complete repro, and that is what makes it testable without the SDK. **Fix:** the promise, its one-shot `_settle` resolver and the `.onComplete` shim are built BEFORE the try, so the catch settles this call (`_settle(err); return _promise;`) — `.onComplete(cb)` receives `(err)`, the `await` form rejects, and `_settle`'s `_settled` latch means a late throw cannot double-settle. ⚠️ **SCOPE — the fix moves the RETURN axis only, not the SETTLED-VALUE axis, and conflating them is what a consumer will do:** the success handler still runs `if (!_data || _data.length == 0) { _data = null }` and only promotes an error when `_meta.errors` is present, so a rows-less success reaches `_settle(false, null, _meta)` and RESOLVES WITH `null`. A non-rejection therefore still does NOT prove rows were inserted — a rows-based success check remains load-bearing after the fix (measured with a consumer whose guard was written against the pre-fix `undefined`). Generalises: after fixing a settlement defect, say which of the two axes moved — what the function RETURNS synchronously, vs what its promise RESOLVES WITH — because any downstream guard or comment written against the untouched axis keeps its conclusion while its stated premise goes stale. ⚠️ **Behaviour change: a fire-and-forget call that ignores the return now surfaces an `unhandledRejection`** where it previously failed silently (gna.js logs it, never responds) — deliberate, and documented in the migration guide. **The QUERY path does NOT share this shape and needed no change:** its promise is built inside `entities[entityName].prototype[name] = function(){…}`, an ATTACHED method, so the enclosing try has already exited by call time and a throw propagates to the caller normally — `bulkInsert` is the only method whose try wraps its own body. Generalises: **a `try` that wraps a whole promise-returning function body must settle in its `catch`, or the contract silently inverts on the failure path** — and the plumbing it settles through has to be constructed OUTSIDE that try, or it is still `undefined` when the catch runs. Tests: `test/core/couchbase-connector.test.js §14` (6 arms over EXTRACT-AND-EXECUTED shipped bytes — both call shapes driven through the real validation throws, plus three controls that are green pre-fix: the extraction anti-vacuity, the happy path reaching `resolveCluster().query()`, and the query-path-is-different pin; red-first measured 3 red / 3 green). **Siblings found while fixing it:** #B430 — the delivery `catch` re-invoked a THROWING caller callback with the same payload (ran it twice); #B431 — all three dispatches chained `.catch(onError).then(onResult)`, and a `.catch()` returning normally RESOLVES, so the trailing `.then()` ran on EVERY error and settled a second time with a bogus empty success (measured: `(Error,null,undefined)` then `(false,null,{})`, so `if (err) return next(err); render(data)` ran BOTH branches; invisible on the await path because a promise settles once, but it is why a failed query emitted 3×). Now `.then(onResult, onError)` — mutually exclusive branches — at all three sites. **Scope, PER DEFECT — the `.once(`/`.emit(` count scopes #B429 ONLY** (it requires a shared emitter; #B430/#B431 involve none, so that instrument is structurally blind to them — an over-scoped 'couchbase only' was relayed on 2026-08-27 and retracted the same day). **#B429: couchbase ONLY** — the other six ORM connectors settle on a per-call native Promise and use the trigger for debug/inspector logging only (`.once(`/`.emit(` = 0 in each, 12 in couchbase). **#B431: couchbase ONLY, verified with a PAREN-MATCHING scanner** (a character-window regex false-positived twice by spanning `});`+`return`+`else` into a different statement's `.then`) — validated against the pre-fix file as a known positive: 3 there, 0 across all nine connectors now. **#B430's class IS present elsewhere — triaged 2026-08-28 as #B432, and the count is 53, not the ~20 the first pass suggested.** A caller's callback is application code and throws for ordinary reasons (a template error, a null deref in a handler); two shapes then ran it a SECOND time with a different payload — the sync `try { cb(null, rows); } catch (e) { cb(e); }`, and the mirror `.then(function(){ cb(null, rows); }).catch(function(e){ cb(e); })`, whose trailing catch is reached when the SUCCESS handler throws. Both deliver a success and then an error for one operation (so `if (err) { return next(err); } render(data);` runs BOTH branches) and the second call reports the caller's own exception as a database failure. ⚠️ **Four instrument corrections, each of which had produced a wrong reading:** (1) a hand-written settle-name list MISSES the real callbacks — derive them per file (a param that is invoked, an `args.pop()` capture, a resolver binding); the stores settle through `fn`, and 35 sites hid behind a `0`. (2) A settle reached through a LOCAL HELPER is invisible without a fixpoint pass (`attempt`, `runQuery`, `withCollection`). (3) A lexical try/catch pair is NOT a defect when the settle sits in a nested async callback (its throw never reaches the enclosing sync catch — this alone cleared mysql, postgresql and duckdb) nor when an inner `try/catch` swallows it first, nor when the trailing settle lives in a SIBLING `else` branch. (4) A native promise resolver settles once, so a double settle through `_resolve`/`_reject` is BENIGN — 7 of 60 findings. Validate any such scanner on the pre-fix couchbase file as a known positive (it must report the #B430 site and both #B431 sites) and on the post-fix file (0). **Measured clean, both directions: mysql, postgresql, duckdb, ai** (`ai` has no callback path at all — only a native resolver). **FIXED in the entity dispatch path (0.6.19):** `core/connectors/settle-once.js` — a dependency-free sibling of `param-redact`/`sql-parser` exposing `settleOnce(label, cb, reporter)`, which returns a PER-CALL guard that delivers at most once, forwards any arity, and reports a callback throw (tagged with the query trigger) instead of replaying it. ⚠️ Build it per invocation, never at module scope — a module-scope guard would let the FIRST call suppress every later one. Wired at sqlite (`node:sqlite` is synchronous, so its callback ran inside the `try` with no microtask boundary — the most reachable instance of the whole class), mongodb (callback dispatch AND the unknown-op branch, which is reachable because `op` is validated only for falsiness, never against the recognised list) and scylladb. `couchbase/index.js` keeps its own inline `_deliver()` — the reference implementation this module generalises. **Store layers — the same shape with framework-supplied callbacks, fixed at METHOD ENTRY** by rebinding (`fn = settleOnce(label, fn, console)` immediately after the `fn = noop` normalization), so every settle path in the method — nested try/catch AND promise chain — funnels through one guard: **session stores** (couchbase v3/v4, mongodb, redis, scylladb, sqlite — 30 methods) and the **async-job stores** (mongodb, sqlite — 10 methods). ⚠️ **A LEXICAL scanner still reports these files HARMFUL, and that is CORRECT-and-expected, not a regression** — the fix REBINDS `fn` rather than renaming call sites, so the matched `fn(...)`-in-try-plus-catch shape is unchanged. A syntactic scanner's post-fix reading is evidence ONLY when the fix changed the syntax it matches; when it rebinds, the verification burden moves entirely to behavioural coverage (`connector-settle-parity.test.js` §05/§06, one arm per store over EXTRACT-AND-EXECUTED shipped bytes plus a wrap census pinning method-count == wrap-count per file). **Connector open paths (`mongodb`/`scylladb` `lib/connector.js` `onReady`) — FIXED, wrapped CONDITIONALLY** (`if (typeof fn === 'function') fn = settleOnce(…)`; measured: an unconditional wrap turns a missing callback from a loud `fn is not a function` rejection into a silent boot hang). The handler is `core/model/index.js`'s `connect` continuation; measured through the real bytes of both, a throwing continuation was re-invoked with a fabricated `Connection failed: <its own message>` AND the connector registry cache was overwritten to `err=<fabricated>, conn=null`, served to every later `connect()` for the process life — now 1 invocation, `err=null`, cache intact, the exception reported under `<connector>:connector#onReady`. The sqlite `inspector#indexes` listener is guarded for consistency (its `_ixCollector` caller has no throwing path; if it ever did, the double decrement would answer `/_gina/indexes` early with partial data). **Couchbase storage-store — CONVERTED to the shared guard** (its own local `once()` already prevented the double settle — measured on all 9 verbs with a firing subtract-control — but its JSDoc claim that the exception 'surfaces as an unhandled rejection' was FALSE on all nine: six verbs lost it silently, three (`stats`/`listZeroRefs`/`listKeys`) logged it misattributed as `<verb> failed`); now 9 wraps at verb entry (`couchbase:storage#<verb>`, reporter = the file's own global `console`), the exception reported once and never entering the CAS-retry / `withCollection` catches. The `once`→`settleOnce` swap is inert for callers: no consumer of any verb's return value exists (measured), and every strategy closure opens `if (err) return fn(err)`. **Every one of the 53 triaged sites is now guarded — the class is CLOSED** (4 entity-dispatch + 24 session-store + 10 job-store + 5 connector-open/Inspector + 10 storage-store). Test `test/core/connector-settle-parity.test.js` (one contract declared ONCE and run against every fixed connector, plus a deliberately UNGUARDED replica that must fail the discriminating arms — without it a spec every backend passes could be a spec asserting nothing; red-first measured 11 pass / 19 fail pre-fix, with every green in the code-the-fix-does-not-change bucket). Server-side only, pickup = bundle RESTART, no re-bake. Test `test/core/couchbase-concurrency.test.js` (25 arms booting the REAL connector against a controllable cluster stub so completion ORDER is chosen not raced; callback arms CAPTURE every invocation behind a grace window so a double settle is observable; red-first validated — 16 red pre-fix, and the arms that stay GREEN pre-fix are exactly the controls: serial, explicit-callback, mixed-form-no-starvation, success paths, the Inspector bridge).
1028
1028
 
1029
1029
  312. **Every `Collection` method that accepts a filter object refuses undefined-valued filter keys — the silent match-all is closed (#B396, gh issue #65, shipped in 0.6.12).** `find()` round-trips its filter objects through `JSON.stringify(arguments)`/`JSON.parse`, and stringify silently DROPS keys whose value is `undefined` — so `findOne({ id: source.missingId })` degraded to the match-everything `{}` filter and returned the collection's FIRST row (an arbitrary, plausible-looking wrong record), a mixed filter silently lost its undefined constraint, and `update({ id: undefined }, set)` wrote `set` onto EVERY record. The in-loop guard deeper in the matcher (message: ``filter `<key>` cannot be left undefined``) was written to refuse exactly this input but was DEAD CODE — the serialization stripped the keys before the loop could see them (JSON.parse can never produce an `undefined` value). The fix hoists the refusal to `find()`'s entry, BEFORE the round-trip; `findOne`, `or` and `update` all delegate to `find`, so the one gate covers the family. Deliberately unchanged: an explicitly EMPTY `{}` filter still means "no constraint" (match-all), `null` stays a legal needle comparing strictly against stored values (matches stored `null`), array arguments are skipped (record sets, not needles), and `notIn`'s ARRAY form (`notIn(rows, key)`) is unaffected because it skips `find()` entirely. ⚠️ Every OTHER filter-object entry point IS covered, including four this entry originally excluded by mistake: `notIn({…})` routes a filter-object argument straight into `find()` (`main.js:869`), `delete()` is a pure delegation to `notIn()` (`:1297`), and `replace()` (`:1199`) and `max()` (`:1373`) call `find()` too — so the covered family is EIGHT entry points, not four. Pre-fix consequences on the four that went undocumented were the worst of the set: `delete({ id: undefined })` returned an EMPTY collection (every record removed — it returns a filtered COPY, so the loss lands in the returned value, not in-place) and `max({ k: undefined })` aggregated over the whole collection instead of the filtered subset. Measured on the published `v0.6.11` vs `v0.6.12` trees with controls; no internal framework caller can pass undefined (two independent sweeps: zero live `notIn`/`replace`/`max` sites, and the two `delete` sites — `lib/proc.js:614`, `core/config.js:2887` — are each structurally string-valued or dominated by an identical-filter `findOne` that throws first). By-catch hardening: the FormValidator's conditional-case rules lookup (`findOne({ case: fields[caseName] })`) could silently merge the FIRST condition's rules when the case field was absent from the form — the refusal now routes that state into the lookup's own designed catch-and-skip (its warn already said "undeclared or misconfigured case"). Behaviour change for consumers relying on undefined-key-means-no-constraint: build filters conditionally (add a key only when its value is defined). ⚠️ That recipe is ONLY for the no-constraint intent — for a LOOKUP BY A POSSIBLY-ABSENT KEY (`if (!col.findOne({id: maybeAbsent}))`, `col.findOne({id: maybeAbsent}) || fallback`) it is the WRONG migration: an empty filter matches everything and returns the FIRST row, so the guard reads "found" and the fallback never runs — measured. Guard the CALL instead: `var row = (id != null) ? col.findOne({id: id}) : null;`. **`lib/collection` IS in the browser `build.json`, so pickup is a bundle RESTART **and** a re-bake.**
1030
1030