velocious 1.0.431 → 1.0.433

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 (794) hide show
  1. package/build/application.js +229 -0
  2. package/build/authorization/ability.js +329 -0
  3. package/build/authorization/base-resource.js +143 -0
  4. package/build/background-jobs/client.js +50 -0
  5. package/build/background-jobs/cron-expression.js +277 -0
  6. package/build/background-jobs/forked-runner-child.js +86 -0
  7. package/build/background-jobs/job-record.js +13 -0
  8. package/build/background-jobs/job-registry.js +92 -0
  9. package/build/background-jobs/job-runner.js +107 -0
  10. package/build/background-jobs/job.js +77 -0
  11. package/build/background-jobs/json-socket.js +78 -0
  12. package/build/background-jobs/main.js +926 -0
  13. package/build/background-jobs/normalize-error.js +26 -0
  14. package/build/background-jobs/scheduler.js +274 -0
  15. package/build/background-jobs/socket-request.js +68 -0
  16. package/build/background-jobs/status-reporter.js +101 -0
  17. package/build/background-jobs/store.js +994 -0
  18. package/build/background-jobs/types.js +70 -0
  19. package/build/background-jobs/web/authorization.js +89 -0
  20. package/build/background-jobs/web/controller.js +280 -0
  21. package/build/background-jobs/web/index.js +57 -0
  22. package/build/background-jobs/web/path-matcher.js +74 -0
  23. package/build/background-jobs/web/registry.js +49 -0
  24. package/build/background-jobs/worker.js +683 -0
  25. package/build/beacon/client.js +330 -0
  26. package/build/beacon/in-process-broker.js +71 -0
  27. package/build/beacon/in-process-client.js +139 -0
  28. package/build/beacon/server.js +148 -0
  29. package/build/beacon/types.js +55 -0
  30. package/build/cli/base-command.js +67 -0
  31. package/build/cli/browser-cli.js +45 -0
  32. package/build/cli/commands/background-jobs-main.js +7 -0
  33. package/build/cli/commands/background-jobs-runner.js +7 -0
  34. package/build/cli/commands/background-jobs-worker.js +7 -0
  35. package/build/cli/commands/beacon.js +7 -0
  36. package/build/cli/commands/console.js +12 -0
  37. package/build/cli/commands/db/base-command.js +82 -0
  38. package/build/cli/commands/db/create.js +64 -0
  39. package/build/cli/commands/db/drop.js +75 -0
  40. package/build/cli/commands/db/migrate.js +17 -0
  41. package/build/cli/commands/db/reset.js +22 -0
  42. package/build/cli/commands/db/rollback.js +15 -0
  43. package/build/cli/commands/db/schema/dump.js +12 -0
  44. package/build/cli/commands/db/schema/load.js +12 -0
  45. package/build/cli/commands/db/seed.js +12 -0
  46. package/build/cli/commands/db/tenants/check.js +38 -0
  47. package/build/cli/commands/db/tenants/create.js +33 -0
  48. package/build/cli/commands/db/tenants/migrate.js +49 -0
  49. package/build/cli/commands/destroy/migration.js +7 -0
  50. package/build/cli/commands/generate/base-models.js +7 -0
  51. package/build/cli/commands/generate/frontend-models.js +12 -0
  52. package/build/cli/commands/generate/migration.js +7 -0
  53. package/build/cli/commands/generate/model.js +7 -0
  54. package/build/cli/commands/init.js +11 -0
  55. package/build/cli/commands/routes.js +7 -0
  56. package/build/cli/commands/run-script.js +12 -0
  57. package/build/cli/commands/runner.js +12 -0
  58. package/build/cli/commands/server.js +7 -0
  59. package/build/cli/commands/test.js +9 -0
  60. package/build/cli/index.js +152 -0
  61. package/build/cli/tenant-database-command-helper.js +198 -0
  62. package/build/cli/use-browser-cli.js +30 -0
  63. package/build/configuration-resolver.js +65 -0
  64. package/build/configuration-types.js +429 -0
  65. package/build/configuration.js +2590 -0
  66. package/build/controller.js +421 -0
  67. package/build/current-configuration.js +31 -0
  68. package/build/current.js +80 -0
  69. package/build/database/annotations-async-hooks.js +47 -0
  70. package/build/database/annotations.js +40 -0
  71. package/build/database/drivers/base-column.js +182 -0
  72. package/build/database/drivers/base-columns-index.js +81 -0
  73. package/build/database/drivers/base-foreign-key.js +104 -0
  74. package/build/database/drivers/base-table.js +156 -0
  75. package/build/database/drivers/base.js +1609 -0
  76. package/build/database/drivers/mssql/column.js +74 -0
  77. package/build/database/drivers/mssql/columns-index.js +6 -0
  78. package/build/database/drivers/mssql/connect-connection.js +16 -0
  79. package/build/database/drivers/mssql/foreign-key.js +12 -0
  80. package/build/database/drivers/mssql/index.js +590 -0
  81. package/build/database/drivers/mssql/options.js +79 -0
  82. package/build/database/drivers/mssql/query-parser.js +6 -0
  83. package/build/database/drivers/mssql/sql/alter-table.js +4 -0
  84. package/build/database/drivers/mssql/sql/create-database.js +36 -0
  85. package/build/database/drivers/mssql/sql/create-index.js +4 -0
  86. package/build/database/drivers/mssql/sql/create-table.js +4 -0
  87. package/build/database/drivers/mssql/sql/delete.js +19 -0
  88. package/build/database/drivers/mssql/sql/drop-database.js +36 -0
  89. package/build/database/drivers/mssql/sql/drop-table.js +4 -0
  90. package/build/database/drivers/mssql/sql/insert.js +4 -0
  91. package/build/database/drivers/mssql/sql/update.js +31 -0
  92. package/build/database/drivers/mssql/sql/upsert.js +23 -0
  93. package/build/database/drivers/mssql/structure-sql.js +120 -0
  94. package/build/database/drivers/mssql/table.js +145 -0
  95. package/build/database/drivers/mysql/column.js +112 -0
  96. package/build/database/drivers/mysql/columns-index.js +22 -0
  97. package/build/database/drivers/mysql/foreign-key.js +12 -0
  98. package/build/database/drivers/mysql/index.js +473 -0
  99. package/build/database/drivers/mysql/options.js +34 -0
  100. package/build/database/drivers/mysql/query-parser.js +6 -0
  101. package/build/database/drivers/mysql/query.js +37 -0
  102. package/build/database/drivers/mysql/sql/alter-table.js +6 -0
  103. package/build/database/drivers/mysql/sql/create-database.js +39 -0
  104. package/build/database/drivers/mysql/sql/create-index.js +6 -0
  105. package/build/database/drivers/mysql/sql/create-table.js +6 -0
  106. package/build/database/drivers/mysql/sql/delete.js +21 -0
  107. package/build/database/drivers/mysql/sql/drop-database.js +6 -0
  108. package/build/database/drivers/mysql/sql/drop-table.js +6 -0
  109. package/build/database/drivers/mysql/sql/insert.js +6 -0
  110. package/build/database/drivers/mysql/sql/update.js +33 -0
  111. package/build/database/drivers/mysql/sql/upsert.js +13 -0
  112. package/build/database/drivers/mysql/structure-sql.js +93 -0
  113. package/build/database/drivers/mysql/table.js +121 -0
  114. package/build/database/drivers/pgsql/column.js +90 -0
  115. package/build/database/drivers/pgsql/columns-index.js +6 -0
  116. package/build/database/drivers/pgsql/foreign-key.js +12 -0
  117. package/build/database/drivers/pgsql/index.js +441 -0
  118. package/build/database/drivers/pgsql/options.js +32 -0
  119. package/build/database/drivers/pgsql/query-parser.js +6 -0
  120. package/build/database/drivers/pgsql/sql/alter-table.js +6 -0
  121. package/build/database/drivers/pgsql/sql/create-database.js +38 -0
  122. package/build/database/drivers/pgsql/sql/create-index.js +6 -0
  123. package/build/database/drivers/pgsql/sql/create-table.js +6 -0
  124. package/build/database/drivers/pgsql/sql/delete.js +21 -0
  125. package/build/database/drivers/pgsql/sql/drop-database.js +6 -0
  126. package/build/database/drivers/pgsql/sql/drop-table.js +6 -0
  127. package/build/database/drivers/pgsql/sql/insert.js +6 -0
  128. package/build/database/drivers/pgsql/sql/update.js +33 -0
  129. package/build/database/drivers/pgsql/sql/upsert.js +14 -0
  130. package/build/database/drivers/pgsql/structure-sql.js +126 -0
  131. package/build/database/drivers/pgsql/table.js +135 -0
  132. package/build/database/drivers/sqlite/base.js +509 -0
  133. package/build/database/drivers/sqlite/column.js +75 -0
  134. package/build/database/drivers/sqlite/columns-index.js +30 -0
  135. package/build/database/drivers/sqlite/connection-sql-js.js +46 -0
  136. package/build/database/drivers/sqlite/foreign-key.js +24 -0
  137. package/build/database/drivers/sqlite/index.js +394 -0
  138. package/build/database/drivers/sqlite/index.native.js +72 -0
  139. package/build/database/drivers/sqlite/index.web.js +99 -0
  140. package/build/database/drivers/sqlite/options.js +32 -0
  141. package/build/database/drivers/sqlite/query-parser.js +6 -0
  142. package/build/database/drivers/sqlite/query.js +35 -0
  143. package/build/database/drivers/sqlite/query.native.js +35 -0
  144. package/build/database/drivers/sqlite/query.web.js +49 -0
  145. package/build/database/drivers/sqlite/sql/alter-table.js +187 -0
  146. package/build/database/drivers/sqlite/sql/create-index.js +6 -0
  147. package/build/database/drivers/sqlite/sql/create-table.js +6 -0
  148. package/build/database/drivers/sqlite/sql/delete.js +26 -0
  149. package/build/database/drivers/sqlite/sql/drop-table.js +6 -0
  150. package/build/database/drivers/sqlite/sql/insert.js +6 -0
  151. package/build/database/drivers/sqlite/sql/update.js +33 -0
  152. package/build/database/drivers/sqlite/sql/upsert.js +14 -0
  153. package/build/database/drivers/sqlite/structure-sql.js +56 -0
  154. package/build/database/drivers/sqlite/table-rebuilder.js +96 -0
  155. package/build/database/drivers/sqlite/table.js +131 -0
  156. package/build/database/drivers/structure-sql/utils.js +35 -0
  157. package/build/database/handler.js +13 -0
  158. package/build/database/initializer-from-require-context.js +101 -0
  159. package/build/database/migration/index.js +438 -0
  160. package/build/database/migrator/files-finder.js +55 -0
  161. package/build/database/migrator/types.js +31 -0
  162. package/build/database/migrator.js +557 -0
  163. package/build/database/pool/async-tracked-multi-connection.js +1164 -0
  164. package/build/database/pool/base-methods-forward.js +52 -0
  165. package/build/database/pool/base.js +380 -0
  166. package/build/database/pool/single-multi-use.js +118 -0
  167. package/build/database/query/alter-table-base.js +104 -0
  168. package/build/database/query/base.js +49 -0
  169. package/build/database/query/create-database-base.js +42 -0
  170. package/build/database/query/create-index-base.js +117 -0
  171. package/build/database/query/create-table-base.js +205 -0
  172. package/build/database/query/delete-base.js +19 -0
  173. package/build/database/query/drop-database-base.js +38 -0
  174. package/build/database/query/drop-table-base.js +58 -0
  175. package/build/database/query/from-base.js +36 -0
  176. package/build/database/query/from-plain.js +16 -0
  177. package/build/database/query/from-table.js +18 -0
  178. package/build/database/query/index.js +533 -0
  179. package/build/database/query/insert-base.js +172 -0
  180. package/build/database/query/join-base.js +43 -0
  181. package/build/database/query/join-object.js +167 -0
  182. package/build/database/query/join-plain.js +18 -0
  183. package/build/database/query/join-tracker.js +93 -0
  184. package/build/database/query/model-class-query.js +1577 -0
  185. package/build/database/query/order-base.js +33 -0
  186. package/build/database/query/order-column.js +77 -0
  187. package/build/database/query/order-plain.js +28 -0
  188. package/build/database/query/preloader/belongs-to.js +267 -0
  189. package/build/database/query/preloader/ensure-model-class-initialized.js +18 -0
  190. package/build/database/query/preloader/has-many.js +316 -0
  191. package/build/database/query/preloader/has-one.js +123 -0
  192. package/build/database/query/preloader/selection.js +152 -0
  193. package/build/database/query/preloader.js +201 -0
  194. package/build/database/query/query-data.js +305 -0
  195. package/build/database/query/select-base.js +30 -0
  196. package/build/database/query/select-plain.js +18 -0
  197. package/build/database/query/select-table-and-column.js +28 -0
  198. package/build/database/query/update-base.js +41 -0
  199. package/build/database/query/upsert-base.js +103 -0
  200. package/build/database/query/where-base.js +38 -0
  201. package/build/database/query/where-combinator.js +31 -0
  202. package/build/database/query/where-hash.js +77 -0
  203. package/build/database/query/where-model-class-hash.js +505 -0
  204. package/build/database/query/where-not.js +23 -0
  205. package/build/database/query/where-plain.js +20 -0
  206. package/build/database/query/with-count.js +219 -0
  207. package/build/database/query-parser/base-query-parser.js +40 -0
  208. package/build/database/query-parser/from-parser.js +49 -0
  209. package/build/database/query-parser/group-parser.js +55 -0
  210. package/build/database/query-parser/joins-parser.js +37 -0
  211. package/build/database/query-parser/limit-parser.js +77 -0
  212. package/build/database/query-parser/options.js +94 -0
  213. package/build/database/query-parser/order-parser.js +45 -0
  214. package/build/database/query-parser/select-parser.js +67 -0
  215. package/build/database/query-parser/where-parser.js +46 -0
  216. package/build/database/record/acts-as-list.js +374 -0
  217. package/build/database/record/attachments/download.js +49 -0
  218. package/build/database/record/attachments/handle.js +188 -0
  219. package/build/database/record/attachments/normalize-input.js +213 -0
  220. package/build/database/record/attachments/storage-drivers/filesystem.js +114 -0
  221. package/build/database/record/attachments/storage-drivers/native.js +146 -0
  222. package/build/database/record/attachments/storage-drivers/s3.js +245 -0
  223. package/build/database/record/attachments/store.js +591 -0
  224. package/build/database/record/index.js +4119 -0
  225. package/build/database/record/instance-relationships/base.js +289 -0
  226. package/build/database/record/instance-relationships/belongs-to.js +84 -0
  227. package/build/database/record/instance-relationships/has-many.js +284 -0
  228. package/build/database/record/instance-relationships/has-one.js +117 -0
  229. package/build/database/record/record-not-found-error.js +3 -0
  230. package/build/database/record/relationships/base.js +195 -0
  231. package/build/database/record/relationships/belongs-to.js +57 -0
  232. package/build/database/record/relationships/has-many.js +46 -0
  233. package/build/database/record/relationships/has-one.js +46 -0
  234. package/build/database/record/state-machine.js +278 -0
  235. package/build/database/record/user-module.js +43 -0
  236. package/build/database/record/validators/base.js +27 -0
  237. package/build/database/record/validators/format.js +50 -0
  238. package/build/database/record/validators/presence.js +24 -0
  239. package/build/database/record/validators/uniqueness.js +124 -0
  240. package/build/database/table-data/index.js +241 -0
  241. package/build/database/table-data/table-column.js +416 -0
  242. package/build/database/table-data/table-foreign-key.js +69 -0
  243. package/build/database/table-data/table-index.js +46 -0
  244. package/build/database/table-data/table-reference.js +13 -0
  245. package/build/database/use-database.js +48 -0
  246. package/build/environment-handlers/base.js +561 -0
  247. package/build/environment-handlers/browser.js +338 -0
  248. package/build/environment-handlers/node/cli/commands/background-jobs-main.js +21 -0
  249. package/build/environment-handlers/node/cli/commands/background-jobs-runner.js +24 -0
  250. package/build/environment-handlers/node/cli/commands/background-jobs-worker.js +47 -0
  251. package/build/environment-handlers/node/cli/commands/beacon.js +21 -0
  252. package/build/environment-handlers/node/cli/commands/cli-command-context.js +31 -0
  253. package/build/environment-handlers/node/cli/commands/console.js +149 -0
  254. package/build/environment-handlers/node/cli/commands/db/schema/dump.js +43 -0
  255. package/build/environment-handlers/node/cli/commands/db/schema/load.js +69 -0
  256. package/build/environment-handlers/node/cli/commands/db/seed.js +79 -0
  257. package/build/environment-handlers/node/cli/commands/destroy/migration.js +47 -0
  258. package/build/environment-handlers/node/cli/commands/generate/base-models.js +396 -0
  259. package/build/environment-handlers/node/cli/commands/generate/frontend-models.js +872 -0
  260. package/build/environment-handlers/node/cli/commands/generate/migration.js +45 -0
  261. package/build/environment-handlers/node/cli/commands/generate/model.js +45 -0
  262. package/build/environment-handlers/node/cli/commands/init.js +68 -0
  263. package/build/environment-handlers/node/cli/commands/routes.js +63 -0
  264. package/build/environment-handlers/node/cli/commands/run-script.js +85 -0
  265. package/build/environment-handlers/node/cli/commands/runner.js +84 -0
  266. package/build/environment-handlers/node/cli/commands/server.js +151 -0
  267. package/build/environment-handlers/node/cli/commands/test.js +118 -0
  268. package/build/environment-handlers/node.js +887 -0
  269. package/build/error-logger.js +30 -0
  270. package/build/frontend-model-controller.js +3491 -0
  271. package/build/frontend-model-resource/base-resource.js +939 -0
  272. package/build/frontend-models/base.js +4004 -0
  273. package/build/frontend-models/clear-pending-debounced-callback.js +16 -0
  274. package/build/frontend-models/event-hook-models.js +49 -0
  275. package/build/frontend-models/model-registry.js +28 -0
  276. package/build/frontend-models/outgoing-event-buffer.js +51 -0
  277. package/build/frontend-models/preloader.js +169 -0
  278. package/build/frontend-models/query.js +2245 -0
  279. package/build/frontend-models/resource-config-validation.js +56 -0
  280. package/build/frontend-models/resource-definition.js +399 -0
  281. package/build/frontend-models/transport-serialization.js +369 -0
  282. package/build/frontend-models/use-created-event.js +21 -0
  283. package/build/frontend-models/use-destroyed-event.js +148 -0
  284. package/build/frontend-models/use-model-class-event.js +164 -0
  285. package/build/frontend-models/use-updated-event.js +152 -0
  286. package/build/frontend-models/websocket-channel.js +494 -0
  287. package/build/frontend-models/websocket-publishers.js +224 -0
  288. package/build/http-client/header.js +17 -0
  289. package/build/http-client/index.js +139 -0
  290. package/build/http-client/request.js +94 -0
  291. package/build/http-client/response.js +151 -0
  292. package/build/http-client/websocket-client.js +27 -0
  293. package/build/http-server/client/index.js +507 -0
  294. package/build/http-server/client/params-to-object.js +152 -0
  295. package/build/http-server/client/request-buffer/form-data-part.js +139 -0
  296. package/build/http-server/client/request-buffer/header.js +19 -0
  297. package/build/http-server/client/request-buffer/index.js +535 -0
  298. package/build/http-server/client/request-parser.js +195 -0
  299. package/build/http-server/client/request-runner.js +321 -0
  300. package/build/http-server/client/request-timing.js +171 -0
  301. package/build/http-server/client/request.js +114 -0
  302. package/build/http-server/client/response.js +251 -0
  303. package/build/http-server/client/uploaded-file/memory-uploaded-file.js +32 -0
  304. package/build/http-server/client/uploaded-file/temporary-uploaded-file.js +32 -0
  305. package/build/http-server/client/uploaded-file/uploaded-file.js +36 -0
  306. package/build/http-server/client/websocket-request.js +147 -0
  307. package/build/http-server/client/websocket-session.js +1755 -0
  308. package/build/http-server/cookie.js +245 -0
  309. package/build/http-server/development-reloader.js +240 -0
  310. package/build/http-server/index.js +561 -0
  311. package/build/http-server/remote-address.js +77 -0
  312. package/build/http-server/server-client.js +222 -0
  313. package/build/http-server/server-lock.js +178 -0
  314. package/build/http-server/websocket-channel-subscribers.js +110 -0
  315. package/build/http-server/websocket-channel.js +137 -0
  316. package/build/http-server/websocket-connection.js +118 -0
  317. package/build/http-server/websocket-event-log-store.js +433 -0
  318. package/build/http-server/websocket-events-host.js +170 -0
  319. package/build/http-server/websocket-events.js +50 -0
  320. package/build/http-server/worker-handler/channel-subscriber-dispatch.js +28 -0
  321. package/build/http-server/worker-handler/in-process.js +155 -0
  322. package/build/http-server/worker-handler/index.js +370 -0
  323. package/build/http-server/worker-handler/worker-script.js +6 -0
  324. package/build/http-server/worker-handler/worker-thread.js +286 -0
  325. package/build/initializer.js +39 -0
  326. package/build/jobs/mail-delivery.js +22 -0
  327. package/build/logger/base-logger.js +34 -0
  328. package/build/logger/console-logger.js +28 -0
  329. package/build/logger/file-logger.js +36 -0
  330. package/build/logger/outputs/array-output.js +50 -0
  331. package/build/logger/outputs/console-output.js +32 -0
  332. package/build/logger/outputs/file-output.js +55 -0
  333. package/build/logger/outputs/stdout-output.js +64 -0
  334. package/build/logger.js +507 -0
  335. package/build/mailer/backends/smtp.js +197 -0
  336. package/build/mailer/base.js +337 -0
  337. package/build/mailer/delivery.js +70 -0
  338. package/build/mailer/index.js +24 -0
  339. package/build/mailer.js +15 -0
  340. package/build/plugins/sqljs-wasm-route-controller.js +70 -0
  341. package/build/plugins/sqljs-wasm-route.js +71 -0
  342. package/build/record-payload-values.js +83 -0
  343. package/build/routes/app-routes.js +17 -0
  344. package/build/routes/base-route.js +133 -0
  345. package/build/routes/basic-route.js +109 -0
  346. package/build/routes/built-in/debug/controller.js +12 -0
  347. package/build/routes/built-in/errors/controller.js +7 -0
  348. package/build/routes/get-route.js +75 -0
  349. package/build/routes/hooks/frontend-model-command-route-hook.js +100 -0
  350. package/build/routes/index.js +50 -0
  351. package/build/routes/namespace-route.js +51 -0
  352. package/build/routes/plugin-routes.js +141 -0
  353. package/build/routes/post-route.js +74 -0
  354. package/build/routes/resolver.js +535 -0
  355. package/build/routes/resource-route.js +154 -0
  356. package/build/routes/root-route.js +11 -0
  357. package/build/src/application.js +187 -214
  358. package/build/src/authorization/ability.js +250 -297
  359. package/build/src/authorization/base-resource.js +120 -136
  360. package/build/src/background-jobs/client.js +43 -47
  361. package/build/src/background-jobs/cron-expression.js +127 -166
  362. package/build/src/background-jobs/forked-runner-child.js +37 -47
  363. package/build/src/background-jobs/job-record.js +8 -10
  364. package/build/src/background-jobs/job-registry.js +72 -84
  365. package/build/src/background-jobs/job-runner.js +74 -81
  366. package/build/src/background-jobs/job.js +62 -72
  367. package/build/src/background-jobs/json-socket.js +65 -70
  368. package/build/src/background-jobs/main.js +841 -900
  369. package/build/src/background-jobs/normalize-error.js +12 -11
  370. package/build/src/background-jobs/scheduler.js +205 -247
  371. package/build/src/background-jobs/socket-request.js +60 -65
  372. package/build/src/background-jobs/status-reporter.js +86 -96
  373. package/build/src/background-jobs/store.js +862 -980
  374. package/build/src/background-jobs/types.js +2 -3
  375. package/build/src/background-jobs/web/authorization.js +38 -50
  376. package/build/src/background-jobs/web/controller.js +232 -268
  377. package/build/src/background-jobs/web/index.js +36 -40
  378. package/build/src/background-jobs/web/path-matcher.js +45 -48
  379. package/build/src/background-jobs/web/registry.js +9 -14
  380. package/build/src/background-jobs/worker.js +585 -639
  381. package/build/src/beacon/client.js +264 -293
  382. package/build/src/beacon/in-process-broker.js +20 -25
  383. package/build/src/beacon/in-process-client.js +104 -116
  384. package/build/src/beacon/server.js +110 -126
  385. package/build/src/beacon/types.js +2 -8
  386. package/build/src/cli/base-command.js +49 -57
  387. package/build/src/cli/browser-cli.js +37 -42
  388. package/build/src/cli/commands/background-jobs-main.js +5 -5
  389. package/build/src/cli/commands/background-jobs-runner.js +5 -5
  390. package/build/src/cli/commands/background-jobs-worker.js +5 -5
  391. package/build/src/cli/commands/beacon.js +5 -5
  392. package/build/src/cli/commands/console.js +10 -10
  393. package/build/src/cli/commands/db/base-command.js +71 -76
  394. package/build/src/cli/commands/db/create.js +53 -61
  395. package/build/src/cli/commands/db/drop.js +62 -71
  396. package/build/src/cli/commands/db/migrate.js +13 -15
  397. package/build/src/cli/commands/db/reset.js +16 -19
  398. package/build/src/cli/commands/db/rollback.js +12 -13
  399. package/build/src/cli/commands/db/schema/dump.js +9 -9
  400. package/build/src/cli/commands/db/schema/load.js +9 -9
  401. package/build/src/cli/commands/db/seed.js +9 -9
  402. package/build/src/cli/commands/db/tenants/check.js +32 -35
  403. package/build/src/cli/commands/db/tenants/create.js +26 -29
  404. package/build/src/cli/commands/db/tenants/migrate.js +40 -44
  405. package/build/src/cli/commands/destroy/migration.js +5 -5
  406. package/build/src/cli/commands/generate/base-models.js +5 -5
  407. package/build/src/cli/commands/generate/frontend-models.js +9 -9
  408. package/build/src/cli/commands/generate/migration.js +5 -5
  409. package/build/src/cli/commands/generate/model.js +5 -5
  410. package/build/src/cli/commands/init.js +7 -9
  411. package/build/src/cli/commands/routes.js +6 -6
  412. package/build/src/cli/commands/run-script.js +9 -9
  413. package/build/src/cli/commands/runner.js +9 -9
  414. package/build/src/cli/commands/server.js +6 -6
  415. package/build/src/cli/commands/test.js +6 -7
  416. package/build/src/cli/index.js +127 -141
  417. package/build/src/cli/tenant-database-command-helper.js +154 -185
  418. package/build/src/cli/use-browser-cli.js +15 -20
  419. package/build/src/configuration-resolver.js +47 -54
  420. package/build/src/configuration-types.d.ts +5 -3
  421. package/build/src/configuration-types.d.ts.map +1 -1
  422. package/build/src/configuration-types.js +3 -54
  423. package/build/src/configuration.js +2240 -2547
  424. package/build/src/controller.js +363 -407
  425. package/build/src/current-configuration.js +9 -12
  426. package/build/src/current.js +70 -75
  427. package/build/src/database/annotations-async-hooks.js +16 -22
  428. package/build/src/database/annotations.js +12 -18
  429. package/build/src/database/drivers/base-column.js +155 -179
  430. package/build/src/database/drivers/base-columns-index.js +69 -78
  431. package/build/src/database/drivers/base-foreign-key.js +89 -101
  432. package/build/src/database/drivers/base-table.js +124 -149
  433. package/build/src/database/drivers/base.js +1306 -1489
  434. package/build/src/database/drivers/mssql/column.js +39 -50
  435. package/build/src/database/drivers/mssql/columns-index.js +2 -3
  436. package/build/src/database/drivers/mssql/connect-connection.js +11 -9
  437. package/build/src/database/drivers/mssql/foreign-key.js +8 -9
  438. package/build/src/database/drivers/mssql/index.js +507 -587
  439. package/build/src/database/drivers/mssql/options.js +68 -75
  440. package/build/src/database/drivers/mssql/query-parser.js +2 -3
  441. package/build/src/database/drivers/mssql/sql/alter-table.js +2 -2
  442. package/build/src/database/drivers/mssql/sql/create-database.js +24 -31
  443. package/build/src/database/drivers/mssql/sql/create-index.js +2 -2
  444. package/build/src/database/drivers/mssql/sql/create-table.js +2 -2
  445. package/build/src/database/drivers/mssql/sql/delete.js +14 -16
  446. package/build/src/database/drivers/mssql/sql/drop-database.js +24 -31
  447. package/build/src/database/drivers/mssql/sql/drop-table.js +2 -2
  448. package/build/src/database/drivers/mssql/sql/insert.js +2 -2
  449. package/build/src/database/drivers/mssql/sql/update.js +24 -28
  450. package/build/src/database/drivers/mssql/sql/upsert.js +18 -20
  451. package/build/src/database/drivers/mssql/structure-sql.js +102 -114
  452. package/build/src/database/drivers/mssql/table.js +81 -96
  453. package/build/src/database/drivers/mysql/column.js +75 -92
  454. package/build/src/database/drivers/mysql/columns-index.js +16 -19
  455. package/build/src/database/drivers/mysql/foreign-key.js +8 -9
  456. package/build/src/database/drivers/mysql/index.js +396 -457
  457. package/build/src/database/drivers/mysql/options.js +26 -30
  458. package/build/src/database/drivers/mysql/query-parser.js +2 -3
  459. package/build/src/database/drivers/mysql/query.js +26 -29
  460. package/build/src/database/drivers/mysql/sql/alter-table.js +2 -3
  461. package/build/src/database/drivers/mysql/sql/create-database.js +23 -28
  462. package/build/src/database/drivers/mysql/sql/create-index.js +2 -3
  463. package/build/src/database/drivers/mysql/sql/create-table.js +2 -3
  464. package/build/src/database/drivers/mysql/sql/delete.js +14 -17
  465. package/build/src/database/drivers/mysql/sql/drop-database.js +2 -3
  466. package/build/src/database/drivers/mysql/sql/drop-table.js +2 -3
  467. package/build/src/database/drivers/mysql/sql/insert.js +2 -3
  468. package/build/src/database/drivers/mysql/sql/update.js +24 -29
  469. package/build/src/database/drivers/mysql/sql/upsert.js +8 -10
  470. package/build/src/database/drivers/mysql/structure-sql.js +79 -88
  471. package/build/src/database/drivers/mysql/table.js +83 -98
  472. package/build/src/database/drivers/pgsql/column.js +56 -72
  473. package/build/src/database/drivers/pgsql/columns-index.js +2 -3
  474. package/build/src/database/drivers/pgsql/foreign-key.js +8 -9
  475. package/build/src/database/drivers/pgsql/index.js +377 -438
  476. package/build/src/database/drivers/pgsql/options.js +25 -28
  477. package/build/src/database/drivers/pgsql/query-parser.js +2 -3
  478. package/build/src/database/drivers/pgsql/sql/alter-table.js +2 -3
  479. package/build/src/database/drivers/pgsql/sql/create-database.js +19 -23
  480. package/build/src/database/drivers/pgsql/sql/create-index.js +2 -3
  481. package/build/src/database/drivers/pgsql/sql/create-table.js +2 -3
  482. package/build/src/database/drivers/pgsql/sql/delete.js +14 -17
  483. package/build/src/database/drivers/pgsql/sql/drop-database.js +2 -3
  484. package/build/src/database/drivers/pgsql/sql/drop-table.js +2 -3
  485. package/build/src/database/drivers/pgsql/sql/insert.js +2 -3
  486. package/build/src/database/drivers/pgsql/sql/update.js +24 -29
  487. package/build/src/database/drivers/pgsql/sql/upsert.js +9 -11
  488. package/build/src/database/drivers/pgsql/structure-sql.js +108 -120
  489. package/build/src/database/drivers/pgsql/table.js +60 -77
  490. package/build/src/database/drivers/sqlite/base.js +405 -478
  491. package/build/src/database/drivers/sqlite/column.js +54 -69
  492. package/build/src/database/drivers/sqlite/columns-index.js +22 -27
  493. package/build/src/database/drivers/sqlite/connection-sql-js.js +35 -42
  494. package/build/src/database/drivers/sqlite/foreign-key.js +18 -21
  495. package/build/src/database/drivers/sqlite/index.js +330 -373
  496. package/build/src/database/drivers/sqlite/index.native.js +55 -64
  497. package/build/src/database/drivers/sqlite/index.web.js +69 -87
  498. package/build/src/database/drivers/sqlite/options.js +25 -28
  499. package/build/src/database/drivers/sqlite/query-parser.js +2 -3
  500. package/build/src/database/drivers/sqlite/query.js +21 -24
  501. package/build/src/database/drivers/sqlite/query.native.js +20 -25
  502. package/build/src/database/drivers/sqlite/query.web.js +30 -37
  503. package/build/src/database/drivers/sqlite/sql/alter-table.js +159 -179
  504. package/build/src/database/drivers/sqlite/sql/create-index.js +2 -3
  505. package/build/src/database/drivers/sqlite/sql/create-table.js +2 -3
  506. package/build/src/database/drivers/sqlite/sql/delete.js +17 -22
  507. package/build/src/database/drivers/sqlite/sql/drop-table.js +2 -3
  508. package/build/src/database/drivers/sqlite/sql/insert.js +2 -3
  509. package/build/src/database/drivers/sqlite/sql/update.js +24 -29
  510. package/build/src/database/drivers/sqlite/sql/upsert.js +9 -11
  511. package/build/src/database/drivers/sqlite/structure-sql.js +49 -52
  512. package/build/src/database/drivers/sqlite/table-rebuilder.js +62 -75
  513. package/build/src/database/drivers/sqlite/table.js +102 -125
  514. package/build/src/database/drivers/structure-sql/utils.js +14 -17
  515. package/build/src/database/handler.js +9 -10
  516. package/build/src/database/initializer-from-require-context.js +76 -87
  517. package/build/src/database/migration/index.js +332 -395
  518. package/build/src/database/migrator/files-finder.js +40 -50
  519. package/build/src/database/migrator/types.js +2 -30
  520. package/build/src/database/migrator.js +454 -526
  521. package/build/src/database/pool/async-tracked-multi-connection.js +997 -1147
  522. package/build/src/database/pool/base-methods-forward.js +40 -43
  523. package/build/src/database/pool/base.js +298 -343
  524. package/build/src/database/pool/single-multi-use.js +93 -110
  525. package/build/src/database/query/alter-table-base.js +84 -99
  526. package/build/src/database/query/base.js +39 -46
  527. package/build/src/database/query/create-database-base.js +25 -30
  528. package/build/src/database/query/create-index-base.js +75 -94
  529. package/build/src/database/query/create-table-base.js +151 -193
  530. package/build/src/database/query/delete-base.js +14 -16
  531. package/build/src/database/query/drop-database-base.js +23 -28
  532. package/build/src/database/query/drop-table-base.js +42 -53
  533. package/build/src/database/query/from-base.js +30 -33
  534. package/build/src/database/query/from-plain.js +11 -13
  535. package/build/src/database/query/from-table.js +13 -15
  536. package/build/src/database/query/index.js +410 -472
  537. package/build/src/database/query/insert-base.js +143 -164
  538. package/build/src/database/query/join-base.js +35 -40
  539. package/build/src/database/query/join-object.js +128 -153
  540. package/build/src/database/query/join-plain.js +13 -15
  541. package/build/src/database/query/join-tracker.js +76 -90
  542. package/build/src/database/query/model-class-query.js +1134 -1370
  543. package/build/src/database/query/order-base.js +27 -30
  544. package/build/src/database/query/order-column.js +44 -53
  545. package/build/src/database/query/order-plain.js +20 -24
  546. package/build/src/database/query/preloader/belongs-to.js +210 -258
  547. package/build/src/database/query/preloader/ensure-model-class-initialized.js +8 -9
  548. package/build/src/database/query/preloader/has-many.js +240 -301
  549. package/build/src/database/query/preloader/has-one.js +91 -117
  550. package/build/src/database/query/preloader/selection.js +117 -129
  551. package/build/src/database/query/preloader.js +160 -185
  552. package/build/src/database/query/query-data.js +157 -201
  553. package/build/src/database/query/select-base.js +25 -27
  554. package/build/src/database/query/select-plain.js +13 -15
  555. package/build/src/database/query/select-table-and-column.js +21 -25
  556. package/build/src/database/query/update-base.js +35 -38
  557. package/build/src/database/query/upsert-base.js +93 -100
  558. package/build/src/database/query/where-base.js +32 -35
  559. package/build/src/database/query/where-combinator.js +25 -28
  560. package/build/src/database/query/where-hash.js +61 -68
  561. package/build/src/database/query/where-model-class-hash.js +414 -469
  562. package/build/src/database/query/where-not.js +18 -20
  563. package/build/src/database/query/where-plain.js +15 -17
  564. package/build/src/database/query/with-count.js +125 -159
  565. package/build/src/database/query-parser/base-query-parser.js +32 -37
  566. package/build/src/database/query-parser/from-parser.js +36 -45
  567. package/build/src/database/query-parser/group-parser.js +42 -50
  568. package/build/src/database/query-parser/joins-parser.js +28 -33
  569. package/build/src/database/query-parser/limit-parser.js +67 -70
  570. package/build/src/database/query-parser/options.js +75 -82
  571. package/build/src/database/query-parser/order-parser.js +36 -40
  572. package/build/src/database/query-parser/select-parser.js +49 -60
  573. package/build/src/database/query-parser/where-parser.js +36 -41
  574. package/build/src/database/record/acts-as-list.js +235 -273
  575. package/build/src/database/record/attachments/download.js +44 -45
  576. package/build/src/database/record/attachments/handle.js +141 -161
  577. package/build/src/database/record/attachments/normalize-input.js +128 -138
  578. package/build/src/database/record/attachments/storage-drivers/filesystem.js +77 -91
  579. package/build/src/database/record/attachments/storage-drivers/native.js +112 -121
  580. package/build/src/database/record/attachments/storage-drivers/s3.js +177 -208
  581. package/build/src/database/record/attachments/store.js +467 -539
  582. package/build/src/database/record/index.d.ts +109 -25
  583. package/build/src/database/record/index.d.ts.map +1 -1
  584. package/build/src/database/record/index.js +3502 -3898
  585. package/build/src/database/record/instance-relationships/base.js +234 -268
  586. package/build/src/database/record/instance-relationships/belongs-to.js +58 -73
  587. package/build/src/database/record/instance-relationships/has-many.js +225 -264
  588. package/build/src/database/record/instance-relationships/has-one.js +85 -105
  589. package/build/src/database/record/record-not-found-error.js +3 -2
  590. package/build/src/database/record/relationships/base.js +144 -166
  591. package/build/src/database/record/relationships/belongs-to.js +44 -51
  592. package/build/src/database/record/relationships/has-many.js +32 -40
  593. package/build/src/database/record/relationships/has-one.js +32 -40
  594. package/build/src/database/record/state-machine.js +156 -208
  595. package/build/src/database/record/user-module.js +32 -38
  596. package/build/src/database/record/validators/base.js +22 -24
  597. package/build/src/database/record/validators/format.js +36 -46
  598. package/build/src/database/record/validators/presence.js +18 -20
  599. package/build/src/database/record/validators/uniqueness.js +99 -117
  600. package/build/src/database/table-data/index.js +199 -231
  601. package/build/src/database/table-data/table-column.js +338 -382
  602. package/build/src/database/table-data/table-foreign-key.js +57 -66
  603. package/build/src/database/table-data/table-index.js +29 -36
  604. package/build/src/database/table-data/table-reference.js +10 -10
  605. package/build/src/database/use-database.js +32 -40
  606. package/build/src/environment-handlers/base.js +484 -544
  607. package/build/src/environment-handlers/browser.js +241 -294
  608. package/build/src/environment-handlers/node/cli/commands/background-jobs-main.js +16 -19
  609. package/build/src/environment-handlers/node/cli/commands/background-jobs-runner.js +18 -21
  610. package/build/src/environment-handlers/node/cli/commands/background-jobs-worker.js +22 -29
  611. package/build/src/environment-handlers/node/cli/commands/beacon.js +16 -19
  612. package/build/src/environment-handlers/node/cli/commands/cli-command-context.js +14 -15
  613. package/build/src/environment-handlers/node/cli/commands/console.js +99 -120
  614. package/build/src/environment-handlers/node/cli/commands/db/schema/dump.js +34 -39
  615. package/build/src/environment-handlers/node/cli/commands/db/schema/load.js +57 -63
  616. package/build/src/environment-handlers/node/cli/commands/db/seed.js +51 -63
  617. package/build/src/environment-handlers/node/cli/commands/destroy/migration.js +32 -40
  618. package/build/src/environment-handlers/node/cli/commands/generate/base-models.d.ts +4 -2
  619. package/build/src/environment-handlers/node/cli/commands/generate/base-models.d.ts.map +1 -1
  620. package/build/src/environment-handlers/node/cli/commands/generate/base-models.js +326 -358
  621. package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.d.ts +10 -10
  622. package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.d.ts.map +1 -1
  623. package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.js +729 -844
  624. package/build/src/environment-handlers/node/cli/commands/generate/migration.js +34 -38
  625. package/build/src/environment-handlers/node/cli/commands/generate/model.js +34 -38
  626. package/build/src/environment-handlers/node/cli/commands/init.js +56 -61
  627. package/build/src/environment-handlers/node/cli/commands/routes.js +51 -59
  628. package/build/src/environment-handlers/node/cli/commands/run-script.js +54 -68
  629. package/build/src/environment-handlers/node/cli/commands/runner.js +56 -74
  630. package/build/src/environment-handlers/node/cli/commands/server.js +93 -106
  631. package/build/src/environment-handlers/node/cli/commands/test.js +97 -113
  632. package/build/src/environment-handlers/node.js +753 -874
  633. package/build/src/error-logger.js +22 -21
  634. package/build/src/frontend-model-controller.js +2791 -3291
  635. package/build/src/frontend-model-resource/base-resource.d.ts +8 -3
  636. package/build/src/frontend-model-resource/base-resource.d.ts.map +1 -1
  637. package/build/src/frontend-model-resource/base-resource.js +770 -865
  638. package/build/src/frontend-models/base.js +3136 -3593
  639. package/build/src/frontend-models/clear-pending-debounced-callback.js +7 -8
  640. package/build/src/frontend-models/event-hook-models.js +16 -21
  641. package/build/src/frontend-models/model-registry.js +9 -11
  642. package/build/src/frontend-models/outgoing-event-buffer.js +10 -17
  643. package/build/src/frontend-models/preloader.js +131 -149
  644. package/build/src/frontend-models/query.js +1557 -1855
  645. package/build/src/frontend-models/resource-config-validation.js +27 -37
  646. package/build/src/frontend-models/resource-definition.d.ts +6 -7
  647. package/build/src/frontend-models/resource-definition.d.ts.map +1 -1
  648. package/build/src/frontend-models/resource-definition.js +237 -291
  649. package/build/src/frontend-models/transport-serialization.js +203 -266
  650. package/build/src/frontend-models/use-created-event.js +5 -7
  651. package/build/src/frontend-models/use-destroyed-event.js +80 -93
  652. package/build/src/frontend-models/use-model-class-event.js +79 -91
  653. package/build/src/frontend-models/use-updated-event.js +84 -97
  654. package/build/src/frontend-models/websocket-channel.js +381 -441
  655. package/build/src/frontend-models/websocket-publishers.js +142 -175
  656. package/build/src/http-client/header.js +13 -14
  657. package/build/src/http-client/index.js +116 -132
  658. package/build/src/http-client/request.js +71 -87
  659. package/build/src/http-client/response.js +122 -140
  660. package/build/src/http-client/websocket-client.js +15 -17
  661. package/build/src/http-server/client/index.js +409 -465
  662. package/build/src/http-server/client/params-to-object.js +124 -135
  663. package/build/src/http-server/client/request-buffer/form-data-part.js +111 -132
  664. package/build/src/http-server/client/request-buffer/header.js +15 -16
  665. package/build/src/http-server/client/request-buffer/index.js +446 -506
  666. package/build/src/http-server/client/request-parser.js +163 -186
  667. package/build/src/http-server/client/request-runner.js +226 -259
  668. package/build/src/http-server/client/request-timing.js +132 -151
  669. package/build/src/http-server/client/request.js +96 -108
  670. package/build/src/http-server/client/response.js +213 -235
  671. package/build/src/http-server/client/uploaded-file/memory-uploaded-file.js +25 -29
  672. package/build/src/http-server/client/uploaded-file/temporary-uploaded-file.js +25 -29
  673. package/build/src/http-server/client/uploaded-file/uploaded-file.js +33 -33
  674. package/build/src/http-server/client/websocket-request.js +114 -137
  675. package/build/src/http-server/client/websocket-session.js +1452 -1657
  676. package/build/src/http-server/cookie.js +216 -236
  677. package/build/src/http-server/development-reloader.js +190 -221
  678. package/build/src/http-server/index.js +451 -525
  679. package/build/src/http-server/remote-address.js +38 -50
  680. package/build/src/http-server/server-client.js +181 -208
  681. package/build/src/http-server/server-lock.js +153 -167
  682. package/build/src/http-server/websocket-channel-subscribers.js +81 -93
  683. package/build/src/http-server/websocket-channel.js +104 -117
  684. package/build/src/http-server/websocket-connection.js +96 -104
  685. package/build/src/http-server/websocket-event-log-store.js +350 -404
  686. package/build/src/http-server/websocket-events-host.js +145 -164
  687. package/build/src/http-server/websocket-events.js +47 -47
  688. package/build/src/http-server/worker-handler/channel-subscriber-dispatch.js +13 -14
  689. package/build/src/http-server/worker-handler/in-process.js +123 -141
  690. package/build/src/http-server/worker-handler/index.js +313 -349
  691. package/build/src/http-server/worker-handler/worker-script.js +4 -5
  692. package/build/src/http-server/worker-handler/worker-thread.js +240 -269
  693. package/build/src/initializer.js +31 -36
  694. package/build/src/jobs/mail-delivery.js +13 -15
  695. package/build/src/logger/base-logger.js +24 -26
  696. package/build/src/logger/console-logger.js +21 -23
  697. package/build/src/logger/file-logger.js +29 -31
  698. package/build/src/logger/outputs/array-output.js +37 -42
  699. package/build/src/logger/outputs/console-output.js +20 -24
  700. package/build/src/logger/outputs/file-output.js +43 -48
  701. package/build/src/logger/outputs/stdout-output.js +39 -48
  702. package/build/src/logger.js +338 -394
  703. package/build/src/mailer/backends/smtp.js +134 -163
  704. package/build/src/mailer/base.js +211 -251
  705. package/build/src/mailer/delivery.js +56 -64
  706. package/build/src/mailer/index.js +4 -22
  707. package/build/src/mailer.js +4 -13
  708. package/build/src/plugins/sqljs-wasm-route-controller.js +42 -52
  709. package/build/src/plugins/sqljs-wasm-route.js +28 -38
  710. package/build/src/record-payload-values.js +25 -28
  711. package/build/src/routes/app-routes.js +12 -14
  712. package/build/src/routes/base-route.js +112 -130
  713. package/build/src/routes/basic-route.js +83 -102
  714. package/build/src/routes/built-in/debug/controller.js +10 -10
  715. package/build/src/routes/built-in/errors/controller.js +5 -5
  716. package/build/src/routes/get-route.js +50 -63
  717. package/build/src/routes/hooks/frontend-model-command-route-hook.js +66 -80
  718. package/build/src/routes/index.js +36 -43
  719. package/build/src/routes/namespace-route.js +38 -47
  720. package/build/src/routes/plugin-routes.js +107 -124
  721. package/build/src/routes/post-route.js +51 -62
  722. package/build/src/routes/resolver.js +422 -494
  723. package/build/src/routes/resource-route.js +124 -143
  724. package/build/src/routes/root-route.js +7 -8
  725. package/build/src/testing/base-expect.js +13 -14
  726. package/build/src/testing/browser-frontend-model-event-hook-scenarios.js +329 -405
  727. package/build/src/testing/browser-test-app.js +23 -29
  728. package/build/src/testing/expect-to-change.js +41 -50
  729. package/build/src/testing/expect-utils.js +139 -184
  730. package/build/src/testing/expect.js +638 -731
  731. package/build/src/testing/request-client.js +70 -85
  732. package/build/src/testing/test-files-finder.js +285 -339
  733. package/build/src/testing/test-filter-parser.js +124 -155
  734. package/build/src/testing/test-runner.js +883 -1020
  735. package/build/src/testing/test-suite-splitter.js +114 -142
  736. package/build/src/testing/test.js +216 -256
  737. package/build/src/utils/backtrace-cleaner-node.js +62 -69
  738. package/build/src/utils/backtrace-cleaner.js +188 -216
  739. package/build/src/utils/ensure-error.js +7 -7
  740. package/build/src/utils/event-emitter.js +4 -6
  741. package/build/src/utils/file-exists.js +9 -10
  742. package/build/src/utils/format-value.js +67 -76
  743. package/build/src/utils/model-scope.js +27 -31
  744. package/build/src/utils/nest-callbacks.js +10 -13
  745. package/build/src/utils/plain-object.js +5 -6
  746. package/build/src/utils/ransack.js +448 -563
  747. package/build/src/utils/rest-args-error.js +5 -6
  748. package/build/src/utils/singularize-model-name.js +9 -11
  749. package/build/src/utils/split-sql-statements.js +68 -79
  750. package/build/src/utils/to-import-specifier.js +24 -30
  751. package/build/src/utils/with-tracked-stack-async-hooks.js +60 -74
  752. package/build/src/utils/with-tracked-stack.js +14 -18
  753. package/build/src/velocious-error.js +27 -30
  754. package/build/templates/configuration.js +61 -0
  755. package/build/templates/generate-migration.js +11 -0
  756. package/build/templates/generate-model.js +6 -0
  757. package/build/templates/routes.js +11 -0
  758. package/build/testing/base-expect.js +17 -0
  759. package/build/testing/browser-frontend-model-event-hook-scenarios.js +520 -0
  760. package/build/testing/browser-test-app.js +32 -0
  761. package/build/testing/expect-to-change.js +55 -0
  762. package/build/testing/expect-utils.js +269 -0
  763. package/build/testing/expect.js +763 -0
  764. package/build/testing/request-client.js +90 -0
  765. package/build/testing/test-files-finder.js +364 -0
  766. package/build/testing/test-filter-parser.js +198 -0
  767. package/build/testing/test-runner.js +1168 -0
  768. package/build/testing/test-suite-splitter.js +177 -0
  769. package/build/testing/test.js +370 -0
  770. package/build/utils/backtrace-cleaner-node.js +87 -0
  771. package/build/utils/backtrace-cleaner.js +266 -0
  772. package/build/utils/ensure-error.js +15 -0
  773. package/build/utils/event-emitter.js +8 -0
  774. package/build/utils/file-exists.js +18 -0
  775. package/build/utils/format-value.js +101 -0
  776. package/build/utils/model-scope.js +56 -0
  777. package/build/utils/nest-callbacks.js +22 -0
  778. package/build/utils/plain-object.js +14 -0
  779. package/build/utils/ransack.js +859 -0
  780. package/build/utils/rest-args-error.js +14 -0
  781. package/build/utils/singularize-model-name.js +18 -0
  782. package/build/utils/split-sql-statements.js +88 -0
  783. package/build/utils/to-import-specifier.js +53 -0
  784. package/build/utils/with-tracked-stack-async-hooks.js +103 -0
  785. package/build/utils/with-tracked-stack.js +38 -0
  786. package/build/velocious-error.js +34 -0
  787. package/package.json +3 -3
  788. package/src/configuration-types.js +1 -1
  789. package/src/database/record/index.js +174 -25
  790. package/src/environment-handlers/node/cli/commands/generate/base-models.js +50 -21
  791. package/src/environment-handlers/node/cli/commands/generate/frontend-models.js +5 -5
  792. package/src/frontend-model-resource/base-resource.js +6 -2
  793. package/src/frontend-models/resource-definition.js +3 -3
  794. package/src/frontend-models/websocket-publishers.js +6 -6
@@ -0,0 +1,872 @@
1
+ import BaseCommand from "../../../../../cli/base-command.js"
2
+ import fs from "fs/promises"
3
+ import path from "node:path"
4
+ import * as inflection from "inflection"
5
+ import {frontendModelResourceClassFromDefinition, frontendModelResourceConfigurationFromDefinition, frontendModelResourcesForBackendProject} from "../../../../../frontend-models/resource-definition.js"
6
+
7
+
8
+ /** Node CLI command that generates frontend model classes from backend project resource config. */
9
+ export default class DbGenerateFrontendModels extends BaseCommand {
10
+ /**
11
+ * Runs execute.
12
+ * @returns {Promise<void>} - Resolves when files are generated.
13
+ */
14
+ async execute() {
15
+ const configuration = this.getConfiguration()
16
+ const backendProjects = configuration.getBackendProjects()
17
+
18
+ await configuration.initializeModels()
19
+
20
+ const environmentHandler = configuration.getEnvironmentHandler()
21
+
22
+ if (typeof environmentHandler.autoDiscoverResources === "function") {
23
+ await environmentHandler.autoDiscoverResources(configuration)
24
+ }
25
+
26
+ if (!Array.isArray(backendProjects) || backendProjects.length === 0) {
27
+ throw new Error("No backend projects configured. Configure 'backendProjects' in your configuration first")
28
+ }
29
+
30
+ /**
31
+ * Ensured directories.
32
+ @type {Set<string>} */
33
+ const ensuredDirectories = new Set()
34
+ /**
35
+ * Generated model names by directory.
36
+ @type {Map<string, Set<string>>} */
37
+ const generatedModelNamesByDirectory = new Map()
38
+ /**
39
+ * Generated files by directory.
40
+ @type {Map<string, Array<{className: string, fileName: string}>>} */
41
+ const generatedFilesByDirectory = new Map()
42
+
43
+ for (const backendProject of backendProjects) {
44
+ // Canonicalize the output directory so equivalent spellings (a trailing
45
+ // slash, `.`/`..` segments, duplicate separators, relative vs absolute)
46
+ // resolve to a single key. Otherwise the per-directory maps below treat
47
+ // them as different directories, duplicate class names slip past detection,
48
+ // and the split buckets write incomplete index.js/setup.js for files that
49
+ // actually land in the same directory on disk.
50
+ const frontendModelsDir = path.resolve(this.frontendModelsDirectoryForBackendProject(backendProject))
51
+ const importPath = this.importPathForFrontendModelsDirectory(frontendModelsDir)
52
+
53
+ if (!ensuredDirectories.has(frontendModelsDir)) {
54
+ await fs.mkdir(frontendModelsDir, {recursive: true})
55
+ ensuredDirectories.add(frontendModelsDir)
56
+ }
57
+
58
+ if (!generatedFilesByDirectory.has(frontendModelsDir)) {
59
+ generatedFilesByDirectory.set(frontendModelsDir, [])
60
+ }
61
+
62
+ if (!generatedModelNamesByDirectory.has(frontendModelsDir)) {
63
+ generatedModelNamesByDirectory.set(frontendModelsDir, new Set())
64
+ }
65
+
66
+ const generatedFiles = generatedFilesByDirectory.get(frontendModelsDir)
67
+ const generatedModelNames = generatedModelNamesByDirectory.get(frontendModelsDir)
68
+
69
+ if (!generatedFiles) throw new Error(`Generated files list missing for ${frontendModelsDir}`)
70
+ if (!generatedModelNames) throw new Error(`Generated model names set missing for ${frontendModelsDir}`)
71
+ const resources = this.resourcesForBackendProject(backendProject)
72
+ const availableFrontendModelClassNames = this.availableFrontendModelClassNames(resources)
73
+
74
+ for (const modelClassName in resources) {
75
+ const modelConfig = frontendModelResourceConfigurationFromDefinition(resources[modelClassName])
76
+ const className = inflection.camelize(modelClassName.replaceAll("-", "_"))
77
+ const fileName = `${inflection.dasherize(inflection.underscore(className))}.js`
78
+ const filePath = `${frontendModelsDir}/${fileName}`
79
+
80
+ if (!modelConfig) {
81
+ throw new Error(`Invalid frontend model resource definition for '${className}'`)
82
+ }
83
+
84
+ this.validateModelConfig({availableFrontendModelClassNames, className, modelConfig, resourceClass: frontendModelResourceClassFromDefinition(resources[modelClassName])})
85
+
86
+ if (generatedModelNames.has(className)) {
87
+ throw new Error(`Duplicate frontend model definition for '${className}'`)
88
+ }
89
+
90
+ generatedModelNames.add(className)
91
+
92
+ const fileContent = this.buildModelFileContent({
93
+ className,
94
+ importPath,
95
+ modelClass: configuration.getModelClasses()[className],
96
+ modelConfig,
97
+ resourceClass: frontendModelResourceClassFromDefinition(resources[modelClassName])
98
+ })
99
+
100
+ await fs.writeFile(filePath, fileContent)
101
+ generatedFiles.push({className, fileName})
102
+
103
+ console.log(`create src/frontend-models/${fileName}`)
104
+ }
105
+ }
106
+
107
+ for (const [frontendModelsDir, generatedFiles] of generatedFilesByDirectory) {
108
+ const indexContent = this.buildIndexFileContent(generatedFiles)
109
+
110
+ await fs.writeFile(`${frontendModelsDir}/index.js`, indexContent)
111
+
112
+ console.log("create src/frontend-models/index.js")
113
+
114
+ const setupContent = this.buildSetupFileContent(generatedFiles)
115
+
116
+ await fs.writeFile(`${frontendModelsDir}/setup.js`, setupContent)
117
+
118
+ console.log("create src/frontend-models/setup.js")
119
+ }
120
+ }
121
+
122
+ /**
123
+ * Runs validate model config.
124
+ * @param {object} args - Arguments.
125
+ * @param {Set<string>} args.availableFrontendModelClassNames - Available frontend model class names in backend project.
126
+ * @param {string} args.className - Model class name.
127
+ * @param {Record<string, ?>} args.modelConfig - Model configuration.
128
+ * @param {import("../../../../../configuration-types.js").FrontendModelResourceClassType | null} [args.resourceClass]
129
+ * @returns {void} - No return value.
130
+ */
131
+ validateModelConfig({availableFrontendModelClassNames, className, modelConfig, resourceClass}) {
132
+ const abilities = modelConfig.abilities
133
+
134
+ if (!abilities || typeof abilities !== "object") {
135
+ throw new Error(`Model '${className}' is missing required 'abilities' config`)
136
+ }
137
+
138
+ const readActions = ["index", "find"]
139
+
140
+ for (const action of readActions) {
141
+ const abilityAction = abilities[action]
142
+
143
+ if (typeof abilityAction !== "string" || abilityAction.length < 1) {
144
+ throw new Error(`Model '${className}' is missing required abilities.${action} config`)
145
+ }
146
+ }
147
+
148
+ const relationships = modelConfig.relationships
149
+
150
+ if (relationships === undefined) return
151
+
152
+ const normalizedRelationships = this.relationshipsForModel({className, modelConfig, resourceClass})
153
+
154
+ for (const relationship of normalizedRelationships) {
155
+ if (!availableFrontendModelClassNames.has(relationship.targetClassName)) {
156
+ throw new Error(`Model '${className}' relationship '${relationship.relationshipName}' references '${relationship.targetClassName}', but no frontend model resource exists for that target in this backend project`)
157
+ }
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Runs resources for backend project.
163
+ * @param {import("../../../../../configuration-types.js").BackendProjectConfiguration} backendProject - Backend project config.
164
+ * @returns {Record<string, import("../../../../../configuration-types.js").FrontendModelResourceDefinition>} - Resource definitions keyed by model class name.
165
+ */
166
+ resourcesForBackendProject(backendProject) {
167
+ return frontendModelResourcesForBackendProject(backendProject)
168
+ }
169
+
170
+ /**
171
+ * Runs available frontend model class names.
172
+ * @param {Record<string, ?>} resources - Resource configuration keyed by model name.
173
+ * @returns {Set<string>} - Available frontend model class names.
174
+ */
175
+ availableFrontendModelClassNames(resources) {
176
+ /**
177
+ * Class names.
178
+ @type {Set<string>} */
179
+ const classNames = new Set()
180
+
181
+ for (const resourceModelName in resources) {
182
+ classNames.add(inflection.camelize(resourceModelName.replaceAll("-", "_")))
183
+ }
184
+
185
+ return classNames
186
+ }
187
+
188
+ /**
189
+ * Runs frontend models directory for backend project.
190
+ * @param {{frontendModelsOutputPath?: string}} backendProject - Backend project config.
191
+ * @returns {string} - Absolute frontend models output directory.
192
+ */
193
+ frontendModelsDirectoryForBackendProject(backendProject) {
194
+ const outputPath = backendProject.frontendModelsOutputPath || this.directory()
195
+
196
+ return `${outputPath}/src/frontend-models`
197
+ }
198
+
199
+ /**
200
+ * Runs import path for frontend models directory.
201
+ * @param {string} frontendModelsDir - Frontend models output directory.
202
+ * @returns {string} - Base class import path.
203
+ */
204
+ importPathForFrontendModelsDirectory(frontendModelsDir) {
205
+ const devMode = frontendModelsDir.includes("/spec/dummy/src/frontend-models")
206
+
207
+ if (devMode) {
208
+ return "../../../../src/frontend-models/base.js"
209
+ }
210
+
211
+ return "velocious/build/src/frontend-models/base.js"
212
+ }
213
+
214
+ /**
215
+ * Runs build model file content.
216
+ * @param {object} args - Method args.
217
+ * @param {string} args.className - Model class name.
218
+ * @param {string} args.importPath - Base class import path.
219
+ * @param {typeof import("../../../../../database/record/index.js").default | undefined} args.modelClass - Backend model class.
220
+ * @param {Record<string, ?>} args.modelConfig - Model configuration.
221
+ * @param {import("../../../../../configuration-types.js").FrontendModelResourceClassType | null} [args.resourceClass]
222
+ * @returns {string} - Generated file content.
223
+ */
224
+ buildModelFileContent({className, importPath, modelClass, modelConfig, resourceClass}) {
225
+ const attributes = this.attributeDefinitionsForModel({modelClass, modelConfig})
226
+ const relationships = this.relationshipsForModel({className, modelConfig, resourceClass})
227
+ const attachments = modelConfig.attachments && typeof modelConfig.attachments === "object"
228
+ ? modelConfig.attachments
229
+ : {}
230
+ const attributesTypeName = `${className}Attributes`
231
+ const attributeNames = attributes.map((attribute) => attribute.name)
232
+ const builtInCollectionCommands = {
233
+ create: modelConfig.builtInCollectionCommands.create || "create",
234
+ index: modelConfig.builtInCollectionCommands.index || "index"
235
+ }
236
+ const builtInMemberCommands = {
237
+ attach: modelConfig.builtInMemberCommands.attach || "attach",
238
+ destroy: modelConfig.builtInMemberCommands.destroy || "destroy",
239
+ download: modelConfig.builtInMemberCommands.download || "download",
240
+ find: modelConfig.builtInMemberCommands.find || "find",
241
+ update: modelConfig.builtInMemberCommands.update || "update",
242
+ url: modelConfig.builtInMemberCommands.url || "url"
243
+ }
244
+ const collectionCommands = modelConfig.collectionCommands
245
+ const memberCommands = modelConfig.memberCommands
246
+ const builtInCollectionCommandsAreDefault = builtInCollectionCommands.create === "create" && builtInCollectionCommands.index === "index"
247
+ const builtInMemberCommandsAreDefault = builtInMemberCommands.attach === "attach"
248
+ && builtInMemberCommands.destroy === "destroy"
249
+ && builtInMemberCommands.download === "download"
250
+ && builtInMemberCommands.find === "find"
251
+ && builtInMemberCommands.update === "update"
252
+ && builtInMemberCommands.url === "url"
253
+
254
+ let fileContent = ""
255
+
256
+ fileContent += `import FrontendModelBase from "${importPath}"\n`
257
+
258
+ fileContent += "\n"
259
+ fileContent += "/**\n"
260
+ fileContent += ` * Frontend model resource config.\n`
261
+ fileContent += ` * @typedef {import("${importPath}").FrontendModelResourceConfig} FrontendModelResourceConfig\n`
262
+ fileContent += " */\n"
263
+ fileContent += "\n"
264
+ fileContent += "/**\n"
265
+ fileContent += ` * ${attributesTypeName} type.\n`
266
+ fileContent += ` * @typedef {object} ${attributesTypeName}\n`
267
+ for (const attribute of attributes) {
268
+ fileContent += ` * @property {${attribute.jsDocType}} ${attribute.name} - Attribute value.\n`
269
+ }
270
+ fileContent += " */\n"
271
+ fileContent += `/** Frontend model for ${className}. */\n`
272
+ fileContent += `export default class ${className} extends FrontendModelBase {\n`
273
+ fileContent += " /** @returns {FrontendModelResourceConfig} - Resource config. */\n"
274
+ fileContent += " static resourceConfig() {\n"
275
+ fileContent += " return {\n"
276
+ fileContent += ` modelName: ${JSON.stringify(className)},\n`
277
+ if (Object.keys(attachments).length > 0) {
278
+ fileContent += " attachments: {\n"
279
+ for (const [attachmentName, attachmentConfig] of Object.entries(attachments)) {
280
+ const attachmentType = attachmentConfig && typeof attachmentConfig === "object" && attachmentConfig.type === "hasMany"
281
+ ? "hasMany"
282
+ : "hasOne"
283
+
284
+ fileContent += ` ${attachmentName}: {type: ${JSON.stringify(attachmentType)}},\n`
285
+ }
286
+ fileContent += " },\n"
287
+ }
288
+ fileContent += this.formattedArrayProperty({
289
+ indent: " ",
290
+ propertyName: "attributes",
291
+ values: attributeNames
292
+ })
293
+ if (!builtInCollectionCommandsAreDefault) {
294
+ fileContent += this.formattedObjectProperty({
295
+ filterDefaultValues: {create: "create", index: "index"},
296
+ indent: " ",
297
+ propertyName: "builtInCollectionCommands",
298
+ values: builtInCollectionCommands
299
+ })
300
+ }
301
+ if (!builtInMemberCommandsAreDefault) {
302
+ fileContent += this.formattedObjectProperty({
303
+ filterDefaultValues: {
304
+ attach: "attach",
305
+ destroy: "destroy",
306
+ download: "download",
307
+ find: "find",
308
+ update: "update",
309
+ url: "url"
310
+ },
311
+ indent: " ",
312
+ propertyName: "builtInMemberCommands",
313
+ values: builtInMemberCommands
314
+ })
315
+ }
316
+ if (Object.keys(collectionCommands).length > 0) {
317
+ fileContent += this.formattedCommandsProperty({
318
+ indent: " ",
319
+ propertyName: "collectionCommands",
320
+ values: collectionCommands
321
+ })
322
+ }
323
+ if (Object.keys(memberCommands).length > 0) {
324
+ fileContent += this.formattedCommandsProperty({
325
+ indent: " ",
326
+ propertyName: "memberCommands",
327
+ values: memberCommands
328
+ })
329
+ }
330
+ if (modelClass && modelClass.primaryKey() !== "id") {
331
+ fileContent += ` primaryKey: ${JSON.stringify(modelClass.primaryKey())},\n`
332
+ }
333
+ const nestedRelationshipNames = this.nestedRelationshipNamesForGenerator(resourceClass || null)
334
+ if (nestedRelationshipNames.length > 0) {
335
+ fileContent += " nestedAttributes: {\n"
336
+ for (const relationshipName of nestedRelationshipNames) {
337
+ fileContent += ` ${relationshipName}: {},\n`
338
+ }
339
+ fileContent += " },\n"
340
+ }
341
+ fileContent += " }\n"
342
+ fileContent += " }\n"
343
+
344
+ if (relationships.length > 0) {
345
+ fileContent += "\n"
346
+ fileContent += " /** @returns {Record<string, {type: \"belongsTo\" | \"hasOne\" | \"hasMany\", autoload?: boolean}>} - Relationship definitions. */\n"
347
+ fileContent += " static relationshipDefinitions() {\n"
348
+ fileContent += " return {\n"
349
+ for (const relationship of relationships) {
350
+ const parts = [`type: ${JSON.stringify(relationship.type)}`]
351
+
352
+ if (relationship.autoload === false) parts.push("autoload: false")
353
+
354
+ fileContent += ` ${relationship.relationshipName}: {${parts.join(", ")}},\n`
355
+ }
356
+ fileContent += " }\n"
357
+ fileContent += " }\n"
358
+
359
+ fileContent += "\n"
360
+ fileContent += " /** @returns {Record<string, string>} - Relationship model class names. */\n"
361
+ fileContent += " static relationshipModelClasses() {\n"
362
+ fileContent += " return {\n"
363
+ for (const relationship of relationships) {
364
+ fileContent += ` ${relationship.relationshipName}: ${JSON.stringify(relationship.targetClassName)},\n`
365
+ }
366
+ fileContent += " }\n"
367
+ fileContent += " }\n"
368
+ }
369
+
370
+ for (const attribute of attributes) {
371
+ const camelizedAttribute = inflection.camelize(attribute.name, true)
372
+ const camelizedAttributeUpper = inflection.camelize(attribute.name)
373
+
374
+ fileContent += "\n"
375
+ fileContent += ` /** @returns {${attributesTypeName}[${JSON.stringify(attribute.name)}]} - Attribute value. */\n`
376
+ fileContent += ` ${camelizedAttribute}() { return this.readAttribute(${JSON.stringify(attribute.name)}) }\n`
377
+
378
+ fileContent += "\n"
379
+ fileContent += " /**\n"
380
+ fileContent += ` * @param {${attributesTypeName}[${JSON.stringify(attribute.name)}]} newValue - New attribute value.\n`
381
+ fileContent += ` * @returns {${attributesTypeName}[${JSON.stringify(attribute.name)}]} - Assigned value.\n`
382
+ fileContent += " */\n"
383
+ fileContent += ` set${camelizedAttributeUpper}(newValue) { return this.setAttribute(${JSON.stringify(attribute.name)}, newValue) }\n`
384
+ }
385
+
386
+ for (const methodName of Object.keys(collectionCommands)) {
387
+ fileContent += "\n"
388
+ fileContent += " /**\n"
389
+ fileContent += ` * Runs ${methodName}.\n`
390
+ fileContent += " * @param {...?} commandArguments - Custom command arguments.\n"
391
+ fileContent += " * @returns {Promise<Record<string, ?>>} - Command response.\n"
392
+ fileContent += " */\n"
393
+ fileContent += ` static async ${methodName}(...commandArguments) {\n`
394
+ fileContent += " return await this.executeCustomCommand({\n"
395
+ fileContent += ` commandName: ${JSON.stringify(collectionCommands[methodName])},\n`
396
+ fileContent += ` commandType: ${JSON.stringify(collectionCommands[methodName])},\n`
397
+ fileContent += ` payload: ${className}.normalizeCustomCommandPayloadArguments(commandArguments),\n`
398
+ fileContent += " resourcePath: this.resourcePath()\n"
399
+ fileContent += " })\n"
400
+ fileContent += " }\n"
401
+ }
402
+
403
+ for (const methodName of Object.keys(memberCommands)) {
404
+ fileContent += "\n"
405
+ fileContent += " /**\n"
406
+ fileContent += ` * Runs ${methodName}.\n`
407
+ fileContent += " * @param {...?} commandArguments - Custom command arguments.\n"
408
+ fileContent += " * @returns {Promise<Record<string, ?>>} - Command response.\n"
409
+ fileContent += " */\n"
410
+ fileContent += ` async ${methodName}(...commandArguments) {\n`
411
+ fileContent += ` return await ${className}.executeCustomCommand({\n`
412
+ fileContent += ` commandName: ${JSON.stringify(memberCommands[methodName])},\n`
413
+ fileContent += ` commandType: ${JSON.stringify(memberCommands[methodName])},\n`
414
+ fileContent += " memberId: this.primaryKeyValue(),\n"
415
+ fileContent += ` payload: ${className}.normalizeCustomCommandPayloadArguments(commandArguments),\n`
416
+ fileContent += ` resourcePath: ${className}.resourcePath()\n`
417
+ fileContent += " })\n"
418
+ fileContent += " }\n"
419
+ }
420
+
421
+ for (const relationship of relationships) {
422
+ const relationshipNameCamelized = inflection.camelize(relationship.relationshipName)
423
+ const targetImportPath = `./${relationship.targetFileName}.js`
424
+
425
+ if (relationship.type == "hasMany") {
426
+ fileContent += "\n"
427
+ fileContent += " /**\n"
428
+ fileContent += ` * Returns ${relationship.relationshipName}.\n`
429
+ fileContent += ` * @returns {import(${JSON.stringify(importPath)}).FrontendModelHasManyRelationship<typeof import(${JSON.stringify(`./${inflection.dasherize(inflection.underscore(className))}.js`)}).default, typeof import(${JSON.stringify(targetImportPath)}).default>} - Relationship helper.\n`
430
+ fileContent += " */\n"
431
+ fileContent += ` ${relationship.relationshipName}() { return /** @type {import(${JSON.stringify(importPath)}).FrontendModelHasManyRelationship<typeof import(${JSON.stringify(`./${inflection.dasherize(inflection.underscore(className))}.js`)}).default, typeof import(${JSON.stringify(targetImportPath)}).default>} */ (this.getRelationshipByName(${JSON.stringify(relationship.relationshipName)})) }\n`
432
+
433
+ fileContent += "\n"
434
+ fileContent += " /**\n"
435
+ fileContent += ` * Returns loaded ${relationship.relationshipName}.\n`
436
+ fileContent += ` * @returns {Array<import(${JSON.stringify(targetImportPath)}).default>} - Loaded related models.\n`
437
+ fileContent += " */\n"
438
+ fileContent += ` ${relationship.relationshipName}Loaded() { return /** @type {Array<import(${JSON.stringify(targetImportPath)}).default>} */ (this.getRelationshipByName(${JSON.stringify(relationship.relationshipName)}).loaded()) }\n`
439
+
440
+ fileContent += "\n"
441
+ fileContent += " /**\n"
442
+ fileContent += ` * Loads ${relationship.relationshipName}.\n`
443
+ fileContent += ` * @returns {Promise<Array<import(${JSON.stringify(targetImportPath)}).default>>} - Loaded related models.\n`
444
+ fileContent += " */\n"
445
+ fileContent += ` async load${relationshipNameCamelized}() { return /** @type {Promise<Array<import(${JSON.stringify(targetImportPath)}).default>>} */ (this.loadRelationship(${JSON.stringify(relationship.relationshipName)})) }\n`
446
+ } else {
447
+ fileContent += "\n"
448
+ fileContent += " /**\n"
449
+ fileContent += ` * Returns ${relationship.relationshipName}.\n`
450
+ fileContent += ` * @returns {import(${JSON.stringify(targetImportPath)}).default | null} - Loaded related model.\n`
451
+ fileContent += " */\n"
452
+ fileContent += ` ${relationship.relationshipName}() { return /** @type {import(${JSON.stringify(targetImportPath)}).default | null} */ (this.getRelationshipByName(${JSON.stringify(relationship.relationshipName)}).loaded()) }\n`
453
+
454
+ fileContent += "\n"
455
+ fileContent += " /**\n"
456
+ fileContent += ` * Builds ${relationship.relationshipName}.\n`
457
+ fileContent += ` * @param {Record<string, ?>} [attributes] - Attributes for the new related model.\n`
458
+ fileContent += ` * @returns {import(${JSON.stringify(targetImportPath)}).default} - Built related model.\n`
459
+ fileContent += " */\n"
460
+ fileContent += ` build${relationshipNameCamelized}(attributes = {}) { return /** @type {import(${JSON.stringify(targetImportPath)}).default} */ (this.getRelationshipByName(${JSON.stringify(relationship.relationshipName)}).build(attributes)) }\n`
461
+
462
+ fileContent += "\n"
463
+ fileContent += " /**\n"
464
+ fileContent += ` * Loads ${relationship.relationshipName}.\n`
465
+ fileContent += ` * @returns {Promise<import(${JSON.stringify(targetImportPath)}).default | null>} - Loaded related model.\n`
466
+ fileContent += " */\n"
467
+ fileContent += ` async load${relationshipNameCamelized}() { return /** @type {Promise<import(${JSON.stringify(targetImportPath)}).default | null>} */ (this.loadRelationship(${JSON.stringify(relationship.relationshipName)})) }\n`
468
+
469
+ fileContent += "\n"
470
+ fileContent += " /**\n"
471
+ fileContent += ` * Returns or loads ${relationship.relationshipName}.\n`
472
+ fileContent += ` * @returns {Promise<import(${JSON.stringify(targetImportPath)}).default | null>} - Loaded related model.\n`
473
+ fileContent += " */\n"
474
+ fileContent += ` async ${relationship.relationshipName}OrLoad() { return /** @type {Promise<import(${JSON.stringify(targetImportPath)}).default | null>} */ (this.relationshipOrLoad(${JSON.stringify(relationship.relationshipName)})) }\n`
475
+
476
+ fileContent += "\n"
477
+ fileContent += " /**\n"
478
+ fileContent += ` * Sets ${relationship.relationshipName}.\n`
479
+ fileContent += ` * @param {import(${JSON.stringify(targetImportPath)}).default | null} model - Related model.\n`
480
+ fileContent += ` * @returns {import(${JSON.stringify(targetImportPath)}).default | null} - Assigned related model.\n`
481
+ fileContent += " */\n"
482
+ fileContent += ` set${relationshipNameCamelized}(model) { return /** @type {import(${JSON.stringify(targetImportPath)}).default | null} */ (this.setRelationship(${JSON.stringify(relationship.relationshipName)}, model)) }\n`
483
+ }
484
+ }
485
+
486
+ fileContent += "}\n"
487
+ fileContent += "\n"
488
+ fileContent += `FrontendModelBase.registerModel(${className})\n`
489
+
490
+ return fileContent
491
+ }
492
+
493
+ /**
494
+ * Runs build index file content.
495
+ * @param {Array<{className: string, fileName: string}>} generatedFiles - Generated model files.
496
+ * @returns {string} - Index file content that imports and re-exports all models.
497
+ */
498
+ buildIndexFileContent(generatedFiles) {
499
+ let content = ""
500
+
501
+ for (const {className, fileName} of generatedFiles) {
502
+ content += `export {default as ${className}} from "./${fileName}"\n`
503
+ }
504
+
505
+ return content
506
+ }
507
+
508
+ /**
509
+ * Runs build setup file content.
510
+ * @param {Array<{className: string, fileName: string}>} generatedFiles - Generated model files.
511
+ * @returns {string} - Setup file content with side-effect imports for model registration.
512
+ */
513
+ buildSetupFileContent(generatedFiles) {
514
+ let content = "// This file is auto-generated by Velocious. Do not edit manually.\n"
515
+
516
+ content += "// Run `velocious g:frontend-models` to regenerate.\n"
517
+
518
+ for (const {fileName} of generatedFiles) {
519
+ content += `import "./${fileName}"\n`
520
+ }
521
+
522
+ return content
523
+ }
524
+
525
+ /**
526
+ * Invokes a backend resource's `permittedParams()` instance method at
527
+ * generation time and extracts the relationship names that accept
528
+ * nested writes (`{fooAttributes: [...]}` entries). The generator
529
+ * emits those names into the frontend model's `resourceConfig()` so
530
+ * the client `save()` walker knows which relationships to ship.
531
+ *
532
+ * Constructed with no controller/ability so resource overrides must
533
+ * support being called without a request context.
534
+ * @param {import("../../../../../configuration-types.js").FrontendModelResourceClassType | null} resourceClass - Resource class.
535
+ * @returns {string[]} - Relationship names that accept nested writes (empty when none).
536
+ */
537
+ nestedRelationshipNamesForGenerator(resourceClass) {
538
+ if (!resourceClass || typeof resourceClass !== "function") return []
539
+
540
+ const prototypeWithMethod = /**
541
+ * Resource prototype.
542
+ * @type {{permittedParams?: (arg?: object) => Array<string | Record<string, ?>>}}
543
+ */ (resourceClass.prototype)
544
+
545
+ if (typeof prototypeWithMethod?.permittedParams !== "function") return []
546
+
547
+ let spec
548
+
549
+ try {
550
+ const instance = new resourceClass({
551
+ ability: undefined,
552
+ context: {},
553
+ locals: {},
554
+ modelClass: resourceClass.ModelClass,
555
+ modelName: resourceClass.ModelClass?.getModelName?.() || resourceClass.name,
556
+ params: {},
557
+ resourceConfiguration: /**
558
+ * Resource configuration.
559
+ * @type {import("../../../../../configuration-types.js").FrontendModelResourceConfiguration}
560
+ */ ({attributes: []})
561
+ })
562
+ spec = instance.permittedParams()
563
+ } catch (error) {
564
+ throw new Error(`Failed to invoke ${resourceClass.name}.permittedParams() while generating frontend models: ${error instanceof Error ? error.message : String(error)}`, {cause: error})
565
+ }
566
+
567
+ if (!Array.isArray(spec)) return []
568
+
569
+ /**
570
+ * Relationship names.
571
+ @type {string[]} */
572
+ const relationshipNames = []
573
+
574
+ for (const entry of spec) {
575
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue
576
+
577
+ for (const key of Object.keys(entry)) {
578
+ if (!key.endsWith("Attributes")) continue
579
+ const name = key.slice(0, -"Attributes".length)
580
+ if (name) relationshipNames.push(name)
581
+ }
582
+ }
583
+
584
+ return relationshipNames
585
+ }
586
+
587
+ /**
588
+ * Runs formatted array property.
589
+ * @param {object} args - Formatting args.
590
+ * @param {string} args.indent - Base indentation.
591
+ * @param {string} args.propertyName - Object property name.
592
+ * @param {string[]} args.values - String values.
593
+ * @returns {string} - Formatted multiline array property.
594
+ */
595
+ formattedArrayProperty({indent, propertyName, values}) {
596
+ let output = `${indent}${propertyName}: [\n`
597
+
598
+ for (const value of values) {
599
+ output += `${indent} ${JSON.stringify(value)},\n`
600
+ }
601
+
602
+ output += `${indent}],\n`
603
+
604
+ return output
605
+ }
606
+
607
+ /**
608
+ * Runs formatted commands property.
609
+ * @param {object} args - Formatting args.
610
+ * @param {string} args.indent - Base indentation.
611
+ * @param {string} args.propertyName - Object property name.
612
+ * @param {Record<string, string>} args.values - Command key-values.
613
+ * @returns {string} - Formatted multiline array property. Always emits
614
+ * the camelCase method-name array form (`memberCommands: ["updateAccess"]`)
615
+ * so the generated config matches the canonical
616
+ * `FrontendModelResourceConfig.{collection,member}Commands: string[]`
617
+ * shape. The runtime derives the command slug from the camelCase
618
+ * method name; consumers never need to write out
619
+ * `{updateAccess: "update-access"}` by hand.
620
+ */
621
+ formattedCommandsProperty({indent, propertyName, values}) {
622
+ return this.formattedArrayProperty({indent, propertyName, values: Object.keys(values)})
623
+ }
624
+
625
+ /**
626
+ * Runs formatted object property.
627
+ * @param {object} args - Formatting args.
628
+ * @param {string} args.indent - Base indentation.
629
+ * @param {string} args.propertyName - Object property name.
630
+ * @param {Record<string, string>} args.values - Object key-values.
631
+ * @param {Record<string, string>} [args.filterDefaultValues] - Default values to omit from output.
632
+ * @returns {string} - Formatted multiline object property.
633
+ */
634
+ formattedObjectProperty({filterDefaultValues, indent, propertyName, values}) {
635
+ let output = `${indent}${propertyName}: {\n`
636
+
637
+ for (const objectKey of Object.keys(values)) {
638
+ if (filterDefaultValues && filterDefaultValues[objectKey] === values[objectKey]) continue
639
+
640
+ output += `${indent} ${objectKey}: ${JSON.stringify(values[objectKey])},\n`
641
+ }
642
+
643
+ output += `${indent}},\n`
644
+
645
+ return output
646
+ }
647
+
648
+ /**
649
+ * Runs attribute definitions for model.
650
+ * @param {object} args - Arguments.
651
+ * @param {typeof import("../../../../../database/record/index.js").default | undefined} args.modelClass - Backend model class.
652
+ * @param {Record<string, ?>} args.modelConfig - Model configuration.
653
+ * @returns {Array<{jsDocType: string, name: string}>} - Attribute definitions.
654
+ */
655
+ attributeDefinitionsForModel({modelClass, modelConfig}) {
656
+ let attributes = modelConfig.attributes
657
+
658
+ // Auto-derive attributes from model columns when not explicitly defined
659
+ if ((!attributes || (Array.isArray(attributes) && attributes.length === 0)) && modelClass) {
660
+ try {
661
+ const columns = modelClass.getColumns()
662
+
663
+ if (Array.isArray(columns)) {
664
+ attributes = columns.map((column) => inflection.camelize(column.getName(), true))
665
+ }
666
+ } catch {
667
+ // Model may not be initialized yet
668
+ }
669
+ }
670
+
671
+ if (Array.isArray(attributes)) {
672
+ return attributes.map((entry) => {
673
+ const attributeName = typeof entry === "string" ? entry : entry.name
674
+
675
+ return {
676
+ jsDocType: this.jsDocTypeForFrontendAttribute({
677
+ attributeConfig: this.frontendAttributeConfigForModelAttribute({attributeName, modelClass})
678
+ }),
679
+ name: attributeName
680
+ }
681
+ })
682
+ }
683
+
684
+ if (!attributes || typeof attributes !== "object") {
685
+ throw new Error(`Expected 'attributes' as array or object but got: ${attributes}`)
686
+ }
687
+
688
+ return Object.keys(attributes).map((attributeName) => {
689
+ const attributeConfig = attributes[attributeName]
690
+
691
+ return {
692
+ jsDocType: this.jsDocTypeForFrontendAttribute({attributeConfig}),
693
+ name: attributeName
694
+ }
695
+ })
696
+ }
697
+
698
+ /**
699
+ * Runs js doc type for frontend attribute.
700
+ * @param {object} args - Arguments.
701
+ * @param {?} args.attributeConfig - Attribute configuration value.
702
+ * @returns {string} - JSDoc type.
703
+ */
704
+ jsDocTypeForFrontendAttribute({attributeConfig}) {
705
+ const jsDocType = this.jsDocTypeForFrontendAttributeBaseType(attributeConfig)
706
+
707
+ if (!this.frontendAttributeCanBeNull(attributeConfig)) {
708
+ return jsDocType
709
+ }
710
+
711
+ return `${jsDocType} | null`
712
+ }
713
+
714
+ /**
715
+ * Runs js doc type for frontend attribute base type.
716
+ * @param {?} attributeConfig - Attribute configuration value.
717
+ * @returns {string} - Non-nullable JSDoc type.
718
+ */
719
+ jsDocTypeForFrontendAttributeBaseType(attributeConfig) {
720
+ if (!attributeConfig || typeof attributeConfig !== "object") {
721
+ return "any"
722
+ }
723
+
724
+ const type = this.frontendAttributeTypeValue(attributeConfig)
725
+
726
+ if (type == "boolean") {
727
+ return "boolean"
728
+ } else if (type == "json" || type == "jsonb") {
729
+ return "Record<string, any>"
730
+ } else if (type && ["blob", "char", "nvarchar", "varchar", "text", "longtext", "uuid", "character varying"].includes(type)) {
731
+ return "string"
732
+ } else if (type && ["bit", "bigint", "decimal", "double", "double precision", "float", "int", "integer", "numeric", "real", "smallint", "tinyint"].includes(type)) {
733
+ return "number"
734
+ } else if (type && ["date", "datetime", "timestamp", "timestamp without time zone", "timestamptz"].includes(type)) {
735
+ return "Date"
736
+ } else {
737
+ return "any"
738
+ }
739
+ }
740
+
741
+ /**
742
+ * Runs frontend attribute can be null.
743
+ * @param {?} attributeConfig - Attribute configuration value.
744
+ * @returns {boolean} - Whether the attribute allows null values.
745
+ */
746
+ frontendAttributeCanBeNull(attributeConfig) {
747
+ if (!attributeConfig || typeof attributeConfig !== "object") {
748
+ return false
749
+ }
750
+
751
+ if (typeof attributeConfig.getNull == "function") {
752
+ return attributeConfig.getNull() === true
753
+ }
754
+
755
+ return attributeConfig.null === true
756
+ }
757
+
758
+ /**
759
+ * Runs frontend attribute type value.
760
+ * @param {?} attributeConfig - Attribute configuration value.
761
+ * @returns {string | null} - Normalized column type.
762
+ */
763
+ frontendAttributeTypeValue(attributeConfig) {
764
+ if (!attributeConfig || typeof attributeConfig !== "object") {
765
+ return null
766
+ }
767
+
768
+ if (typeof attributeConfig.getType == "function") {
769
+ return String(attributeConfig.getType())
770
+ }
771
+
772
+ const typeValue = attributeConfig.type || attributeConfig.columnType || attributeConfig.sqlType || attributeConfig.dataType
773
+
774
+ if (typeof typeValue !== "string") {
775
+ return null
776
+ }
777
+
778
+ return typeValue
779
+ }
780
+
781
+ /**
782
+ * Runs frontend attribute config for model attribute.
783
+ * @param {object} args - Arguments.
784
+ * @param {string} args.attributeName - Frontend model attribute name.
785
+ * @param {typeof import("../../../../../database/record/index.js").default | undefined} args.modelClass - Backend model class.
786
+ * @returns {?} - Attribute config inferred from the backend model when available.
787
+ */
788
+ frontendAttributeConfigForModelAttribute({attributeName, modelClass}) {
789
+ if (!modelClass) {
790
+ return null
791
+ }
792
+
793
+ const columnName = modelClass.getAttributeNameToColumnNameMap()[attributeName]
794
+
795
+ if (!columnName) {
796
+ return null
797
+ }
798
+
799
+ return modelClass.getColumnsHash()[columnName] || null
800
+ }
801
+
802
+ /**
803
+ * Runs relationships for model.
804
+ * @param {object} args - Arguments.
805
+ * @param {string} args.className - Model class name.
806
+ * @param {Record<string, ?>} args.modelConfig - Model configuration.
807
+ * @param {import("../../../../../configuration-types.js").FrontendModelResourceClassType | null} [args.resourceClass]
808
+ * @returns {Array<{autoload: boolean, relationshipName: string, targetClassName: string, targetFileName: string, type: "belongsTo" | "hasOne" | "hasMany"}>} - Relationships.
809
+ */
810
+ relationshipsForModel({className, modelConfig, resourceClass}) {
811
+ const relationships = modelConfig.relationships
812
+
813
+ if (relationships === undefined || relationships === null) {
814
+ return []
815
+ }
816
+
817
+ if (!Array.isArray(relationships)) {
818
+ throw new Error(`Model '${className}' has invalid relationships config — must be an array of relationship names, got ${typeof relationships}`)
819
+ }
820
+
821
+ return relationships.map((relationshipName) => this.inferredRelationshipDefinition({className, relationshipName, resourceClass}))
822
+ }
823
+
824
+ /**
825
+ * Runs inferred relationship definition.
826
+ * @param {object} args - Arguments.
827
+ * @param {string} args.className - Model class name.
828
+ * @param {string} args.relationshipName - Relationship name.
829
+ * @param {import("../../../../../configuration-types.js").FrontendModelResourceClassType | null} [args.resourceClass]
830
+ * @returns {{autoload: boolean, relationshipName: string, targetClassName: string, targetFileName: string, type: "belongsTo" | "hasOne" | "hasMany"}} Inferred relationship definition.
831
+ */
832
+ inferredRelationshipDefinition({className, relationshipName, resourceClass}) {
833
+ const modelClass = resourceClass?.ModelClass || this.getConfiguration().getModelClass(className)
834
+
835
+ if (!modelClass) {
836
+ throw new Error(`Could not find backend model class '${className}' for relationship '${relationshipName}'`)
837
+ }
838
+
839
+ const relationship = modelClass.getRelationshipByName(relationshipName)
840
+ const relationshipType = relationship.getType()
841
+
842
+ if (relationshipType !== "belongsTo" && relationshipType !== "hasOne" && relationshipType !== "hasMany") {
843
+ throw new Error(`Model '${className}' relationship '${relationshipName}' has unsupported type '${relationshipType}'`)
844
+ }
845
+
846
+ let targetClassName
847
+
848
+ try {
849
+ const targetModelClass = relationship.getTargetModelClass()
850
+
851
+ targetClassName = targetModelClass?.getModelName()
852
+ } catch {
853
+ // Model class not registered yet — fall back to className from relationship definition
854
+ }
855
+
856
+ if (!targetClassName) {
857
+ targetClassName = relationship.className
858
+
859
+ if (!targetClassName) {
860
+ throw new Error(`Model '${className}' relationship '${relationshipName}' has no target model class`)
861
+ }
862
+ }
863
+
864
+ return {
865
+ autoload: relationship.getAutoload(),
866
+ relationshipName,
867
+ targetClassName,
868
+ targetFileName: inflection.dasherize(inflection.underscore(targetClassName)),
869
+ type: relationshipType
870
+ }
871
+ }
872
+ }