velocious 1.0.430 → 1.0.432

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 (831) hide show
  1. package/bin/velocious.js +48 -0
  2. package/build/application.js +229 -0
  3. package/build/authorization/ability.js +329 -0
  4. package/build/authorization/base-resource.js +143 -0
  5. package/build/background-jobs/client.js +50 -0
  6. package/build/background-jobs/cron-expression.js +277 -0
  7. package/build/background-jobs/forked-runner-child.js +86 -0
  8. package/build/background-jobs/job-record.js +13 -0
  9. package/build/background-jobs/job-registry.js +92 -0
  10. package/build/background-jobs/job-runner.js +107 -0
  11. package/build/background-jobs/job.js +77 -0
  12. package/build/background-jobs/json-socket.js +78 -0
  13. package/build/background-jobs/main.js +926 -0
  14. package/build/background-jobs/normalize-error.js +26 -0
  15. package/build/background-jobs/scheduler.js +274 -0
  16. package/build/background-jobs/socket-request.js +68 -0
  17. package/build/background-jobs/status-reporter.js +101 -0
  18. package/build/background-jobs/store.js +994 -0
  19. package/build/background-jobs/types.js +70 -0
  20. package/build/background-jobs/web/authorization.js +89 -0
  21. package/build/background-jobs/web/controller.js +280 -0
  22. package/build/background-jobs/web/index.js +57 -0
  23. package/build/background-jobs/web/path-matcher.js +74 -0
  24. package/build/background-jobs/web/registry.js +49 -0
  25. package/build/background-jobs/worker.js +683 -0
  26. package/build/beacon/client.js +330 -0
  27. package/build/beacon/in-process-broker.js +71 -0
  28. package/build/beacon/in-process-client.js +139 -0
  29. package/build/beacon/server.js +148 -0
  30. package/build/beacon/types.js +55 -0
  31. package/build/bin/velocious.js +39 -34
  32. package/build/cli/base-command.js +67 -0
  33. package/build/cli/browser-cli.js +45 -0
  34. package/build/cli/commands/background-jobs-main.js +7 -0
  35. package/build/cli/commands/background-jobs-runner.js +7 -0
  36. package/build/cli/commands/background-jobs-worker.js +7 -0
  37. package/build/cli/commands/beacon.js +7 -0
  38. package/build/cli/commands/console.js +12 -0
  39. package/build/cli/commands/db/base-command.js +82 -0
  40. package/build/cli/commands/db/create.js +64 -0
  41. package/build/cli/commands/db/drop.js +75 -0
  42. package/build/cli/commands/db/migrate.js +17 -0
  43. package/build/cli/commands/db/reset.js +22 -0
  44. package/build/cli/commands/db/rollback.js +15 -0
  45. package/build/cli/commands/db/schema/dump.js +12 -0
  46. package/build/cli/commands/db/schema/load.js +12 -0
  47. package/build/cli/commands/db/seed.js +12 -0
  48. package/build/cli/commands/db/tenants/check.js +38 -0
  49. package/build/cli/commands/db/tenants/create.js +33 -0
  50. package/build/cli/commands/db/tenants/migrate.js +49 -0
  51. package/build/cli/commands/destroy/migration.js +7 -0
  52. package/build/cli/commands/generate/base-models.js +7 -0
  53. package/build/cli/commands/generate/frontend-models.js +12 -0
  54. package/build/cli/commands/generate/migration.js +7 -0
  55. package/build/cli/commands/generate/model.js +7 -0
  56. package/build/cli/commands/init.js +11 -0
  57. package/build/cli/commands/routes.js +7 -0
  58. package/build/cli/commands/run-script.js +12 -0
  59. package/build/cli/commands/runner.js +12 -0
  60. package/build/cli/commands/server.js +7 -0
  61. package/build/cli/commands/test.js +9 -0
  62. package/build/cli/index.js +152 -0
  63. package/build/cli/tenant-database-command-helper.js +198 -0
  64. package/build/cli/use-browser-cli.js +30 -0
  65. package/build/configuration-resolver.js +65 -0
  66. package/build/configuration-types.js +429 -0
  67. package/build/configuration.js +2590 -0
  68. package/build/controller.js +421 -0
  69. package/build/current-configuration.js +31 -0
  70. package/build/current.js +80 -0
  71. package/build/database/annotations-async-hooks.js +47 -0
  72. package/build/database/annotations.js +40 -0
  73. package/build/database/drivers/base-column.js +182 -0
  74. package/build/database/drivers/base-columns-index.js +81 -0
  75. package/build/database/drivers/base-foreign-key.js +104 -0
  76. package/build/database/drivers/base-table.js +156 -0
  77. package/build/database/drivers/base.js +1609 -0
  78. package/build/database/drivers/mssql/column.js +74 -0
  79. package/build/database/drivers/mssql/columns-index.js +6 -0
  80. package/build/database/drivers/mssql/connect-connection.js +16 -0
  81. package/build/database/drivers/mssql/foreign-key.js +12 -0
  82. package/build/database/drivers/mssql/index.js +590 -0
  83. package/build/database/drivers/mssql/options.js +79 -0
  84. package/build/database/drivers/mssql/query-parser.js +6 -0
  85. package/build/database/drivers/mssql/sql/alter-table.js +4 -0
  86. package/build/database/drivers/mssql/sql/create-database.js +36 -0
  87. package/build/database/drivers/mssql/sql/create-index.js +4 -0
  88. package/build/database/drivers/mssql/sql/create-table.js +4 -0
  89. package/build/database/drivers/mssql/sql/delete.js +19 -0
  90. package/build/database/drivers/mssql/sql/drop-database.js +36 -0
  91. package/build/database/drivers/mssql/sql/drop-table.js +4 -0
  92. package/build/database/drivers/mssql/sql/insert.js +4 -0
  93. package/build/database/drivers/mssql/sql/update.js +31 -0
  94. package/build/database/drivers/mssql/sql/upsert.js +23 -0
  95. package/build/database/drivers/mssql/structure-sql.js +120 -0
  96. package/build/database/drivers/mssql/table.js +145 -0
  97. package/build/database/drivers/mysql/column.js +112 -0
  98. package/build/database/drivers/mysql/columns-index.js +22 -0
  99. package/build/database/drivers/mysql/foreign-key.js +12 -0
  100. package/build/database/drivers/mysql/index.js +473 -0
  101. package/build/database/drivers/mysql/options.js +34 -0
  102. package/build/database/drivers/mysql/query-parser.js +6 -0
  103. package/build/database/drivers/mysql/query.js +37 -0
  104. package/build/database/drivers/mysql/sql/alter-table.js +6 -0
  105. package/build/database/drivers/mysql/sql/create-database.js +39 -0
  106. package/build/database/drivers/mysql/sql/create-index.js +6 -0
  107. package/build/database/drivers/mysql/sql/create-table.js +6 -0
  108. package/build/database/drivers/mysql/sql/delete.js +21 -0
  109. package/build/database/drivers/mysql/sql/drop-database.js +6 -0
  110. package/build/database/drivers/mysql/sql/drop-table.js +6 -0
  111. package/build/database/drivers/mysql/sql/insert.js +6 -0
  112. package/build/database/drivers/mysql/sql/update.js +33 -0
  113. package/build/database/drivers/mysql/sql/upsert.js +13 -0
  114. package/build/database/drivers/mysql/structure-sql.js +93 -0
  115. package/build/database/drivers/mysql/table.js +121 -0
  116. package/build/database/drivers/pgsql/column.js +90 -0
  117. package/build/database/drivers/pgsql/columns-index.js +6 -0
  118. package/build/database/drivers/pgsql/foreign-key.js +12 -0
  119. package/build/database/drivers/pgsql/index.js +441 -0
  120. package/build/database/drivers/pgsql/options.js +32 -0
  121. package/build/database/drivers/pgsql/query-parser.js +6 -0
  122. package/build/database/drivers/pgsql/sql/alter-table.js +6 -0
  123. package/build/database/drivers/pgsql/sql/create-database.js +38 -0
  124. package/build/database/drivers/pgsql/sql/create-index.js +6 -0
  125. package/build/database/drivers/pgsql/sql/create-table.js +6 -0
  126. package/build/database/drivers/pgsql/sql/delete.js +21 -0
  127. package/build/database/drivers/pgsql/sql/drop-database.js +6 -0
  128. package/build/database/drivers/pgsql/sql/drop-table.js +6 -0
  129. package/build/database/drivers/pgsql/sql/insert.js +6 -0
  130. package/build/database/drivers/pgsql/sql/update.js +33 -0
  131. package/build/database/drivers/pgsql/sql/upsert.js +14 -0
  132. package/build/database/drivers/pgsql/structure-sql.js +126 -0
  133. package/build/database/drivers/pgsql/table.js +135 -0
  134. package/build/database/drivers/sqlite/base.js +509 -0
  135. package/build/database/drivers/sqlite/column.js +75 -0
  136. package/build/database/drivers/sqlite/columns-index.js +30 -0
  137. package/build/database/drivers/sqlite/connection-sql-js.js +46 -0
  138. package/build/database/drivers/sqlite/foreign-key.js +24 -0
  139. package/build/database/drivers/sqlite/index.js +394 -0
  140. package/build/database/drivers/sqlite/index.native.js +72 -0
  141. package/build/database/drivers/sqlite/index.web.js +99 -0
  142. package/build/database/drivers/sqlite/options.js +32 -0
  143. package/build/database/drivers/sqlite/query-parser.js +6 -0
  144. package/build/database/drivers/sqlite/query.js +35 -0
  145. package/build/database/drivers/sqlite/query.native.js +35 -0
  146. package/build/database/drivers/sqlite/query.web.js +49 -0
  147. package/build/database/drivers/sqlite/sql/alter-table.js +187 -0
  148. package/build/database/drivers/sqlite/sql/create-index.js +6 -0
  149. package/build/database/drivers/sqlite/sql/create-table.js +6 -0
  150. package/build/database/drivers/sqlite/sql/delete.js +26 -0
  151. package/build/database/drivers/sqlite/sql/drop-table.js +6 -0
  152. package/build/database/drivers/sqlite/sql/insert.js +6 -0
  153. package/build/database/drivers/sqlite/sql/update.js +33 -0
  154. package/build/database/drivers/sqlite/sql/upsert.js +14 -0
  155. package/build/database/drivers/sqlite/structure-sql.js +56 -0
  156. package/build/database/drivers/sqlite/table-rebuilder.js +96 -0
  157. package/build/database/drivers/sqlite/table.js +131 -0
  158. package/build/database/drivers/structure-sql/utils.js +35 -0
  159. package/build/database/handler.js +13 -0
  160. package/build/database/initializer-from-require-context.js +101 -0
  161. package/build/database/migration/index.js +438 -0
  162. package/build/database/migrator/files-finder.js +55 -0
  163. package/build/database/migrator/types.js +31 -0
  164. package/build/database/migrator.js +557 -0
  165. package/build/database/pool/async-tracked-multi-connection.js +1164 -0
  166. package/build/database/pool/base-methods-forward.js +52 -0
  167. package/build/database/pool/base.js +380 -0
  168. package/build/database/pool/single-multi-use.js +118 -0
  169. package/build/database/query/alter-table-base.js +104 -0
  170. package/build/database/query/base.js +49 -0
  171. package/build/database/query/create-database-base.js +42 -0
  172. package/build/database/query/create-index-base.js +117 -0
  173. package/build/database/query/create-table-base.js +205 -0
  174. package/build/database/query/delete-base.js +19 -0
  175. package/build/database/query/drop-database-base.js +38 -0
  176. package/build/database/query/drop-table-base.js +58 -0
  177. package/build/database/query/from-base.js +36 -0
  178. package/build/database/query/from-plain.js +16 -0
  179. package/build/database/query/from-table.js +18 -0
  180. package/build/database/query/index.js +533 -0
  181. package/build/database/query/insert-base.js +172 -0
  182. package/build/database/query/join-base.js +43 -0
  183. package/build/database/query/join-object.js +167 -0
  184. package/build/database/query/join-plain.js +18 -0
  185. package/build/database/query/join-tracker.js +93 -0
  186. package/build/database/query/model-class-query.js +1577 -0
  187. package/build/database/query/order-base.js +33 -0
  188. package/build/database/query/order-column.js +77 -0
  189. package/build/database/query/order-plain.js +28 -0
  190. package/build/database/query/preloader/belongs-to.js +267 -0
  191. package/build/database/query/preloader/ensure-model-class-initialized.js +18 -0
  192. package/build/database/query/preloader/has-many.js +316 -0
  193. package/build/database/query/preloader/has-one.js +123 -0
  194. package/build/database/query/preloader/selection.js +152 -0
  195. package/build/database/query/preloader.js +201 -0
  196. package/build/database/query/query-data.js +305 -0
  197. package/build/database/query/select-base.js +30 -0
  198. package/build/database/query/select-plain.js +18 -0
  199. package/build/database/query/select-table-and-column.js +28 -0
  200. package/build/database/query/update-base.js +41 -0
  201. package/build/database/query/upsert-base.js +103 -0
  202. package/build/database/query/where-base.js +38 -0
  203. package/build/database/query/where-combinator.js +31 -0
  204. package/build/database/query/where-hash.js +77 -0
  205. package/build/database/query/where-model-class-hash.js +505 -0
  206. package/build/database/query/where-not.js +23 -0
  207. package/build/database/query/where-plain.js +20 -0
  208. package/build/database/query/with-count.js +219 -0
  209. package/build/database/query-parser/base-query-parser.js +40 -0
  210. package/build/database/query-parser/from-parser.js +49 -0
  211. package/build/database/query-parser/group-parser.js +55 -0
  212. package/build/database/query-parser/joins-parser.js +37 -0
  213. package/build/database/query-parser/limit-parser.js +77 -0
  214. package/build/database/query-parser/options.js +94 -0
  215. package/build/database/query-parser/order-parser.js +45 -0
  216. package/build/database/query-parser/select-parser.js +67 -0
  217. package/build/database/query-parser/where-parser.js +46 -0
  218. package/build/database/record/acts-as-list.js +374 -0
  219. package/build/database/record/attachments/download.js +49 -0
  220. package/build/database/record/attachments/handle.js +188 -0
  221. package/build/database/record/attachments/normalize-input.js +213 -0
  222. package/build/database/record/attachments/storage-drivers/filesystem.js +114 -0
  223. package/build/database/record/attachments/storage-drivers/native.js +146 -0
  224. package/build/database/record/attachments/storage-drivers/s3.js +245 -0
  225. package/build/database/record/attachments/store.js +591 -0
  226. package/build/database/record/index.js +4094 -0
  227. package/build/database/record/instance-relationships/base.js +289 -0
  228. package/build/database/record/instance-relationships/belongs-to.js +84 -0
  229. package/build/database/record/instance-relationships/has-many.js +284 -0
  230. package/build/database/record/instance-relationships/has-one.js +117 -0
  231. package/build/database/record/record-not-found-error.js +3 -0
  232. package/build/database/record/relationships/base.js +195 -0
  233. package/build/database/record/relationships/belongs-to.js +57 -0
  234. package/build/database/record/relationships/has-many.js +46 -0
  235. package/build/database/record/relationships/has-one.js +46 -0
  236. package/build/database/record/state-machine.js +278 -0
  237. package/build/database/record/user-module.js +43 -0
  238. package/build/database/record/validators/base.js +27 -0
  239. package/build/database/record/validators/format.js +50 -0
  240. package/build/database/record/validators/presence.js +24 -0
  241. package/build/database/record/validators/uniqueness.js +124 -0
  242. package/build/database/table-data/index.js +241 -0
  243. package/build/database/table-data/table-column.js +416 -0
  244. package/build/database/table-data/table-foreign-key.js +69 -0
  245. package/build/database/table-data/table-index.js +46 -0
  246. package/build/database/table-data/table-reference.js +13 -0
  247. package/build/database/use-database.js +48 -0
  248. package/build/environment-handlers/base.js +561 -0
  249. package/build/environment-handlers/browser.js +338 -0
  250. package/build/environment-handlers/node/cli/commands/background-jobs-main.js +21 -0
  251. package/build/environment-handlers/node/cli/commands/background-jobs-runner.js +24 -0
  252. package/build/environment-handlers/node/cli/commands/background-jobs-worker.js +47 -0
  253. package/build/environment-handlers/node/cli/commands/beacon.js +21 -0
  254. package/build/environment-handlers/node/cli/commands/cli-command-context.js +31 -0
  255. package/build/environment-handlers/node/cli/commands/console.js +149 -0
  256. package/build/environment-handlers/node/cli/commands/db/schema/dump.js +43 -0
  257. package/build/environment-handlers/node/cli/commands/db/schema/load.js +69 -0
  258. package/build/environment-handlers/node/cli/commands/db/seed.js +79 -0
  259. package/build/environment-handlers/node/cli/commands/destroy/migration.js +47 -0
  260. package/build/environment-handlers/node/cli/commands/generate/base-models.js +396 -0
  261. package/build/environment-handlers/node/cli/commands/generate/frontend-models.js +872 -0
  262. package/build/environment-handlers/node/cli/commands/generate/migration.js +45 -0
  263. package/build/environment-handlers/node/cli/commands/generate/model.js +45 -0
  264. package/build/environment-handlers/node/cli/commands/init.js +68 -0
  265. package/build/environment-handlers/node/cli/commands/routes.js +63 -0
  266. package/build/environment-handlers/node/cli/commands/run-script.js +85 -0
  267. package/build/environment-handlers/node/cli/commands/runner.js +84 -0
  268. package/build/environment-handlers/node/cli/commands/server.js +151 -0
  269. package/build/environment-handlers/node/cli/commands/test.js +118 -0
  270. package/build/environment-handlers/node.js +887 -0
  271. package/build/error-logger.js +30 -0
  272. package/build/frontend-model-controller.js +3491 -0
  273. package/build/frontend-model-resource/base-resource.js +935 -0
  274. package/build/frontend-models/base.js +4004 -0
  275. package/build/frontend-models/clear-pending-debounced-callback.js +16 -0
  276. package/build/frontend-models/event-hook-models.js +49 -0
  277. package/build/frontend-models/model-registry.js +28 -0
  278. package/build/frontend-models/outgoing-event-buffer.js +51 -0
  279. package/build/frontend-models/preloader.js +169 -0
  280. package/build/frontend-models/query.js +2245 -0
  281. package/build/frontend-models/resource-config-validation.js +56 -0
  282. package/build/frontend-models/resource-definition.js +399 -0
  283. package/build/frontend-models/transport-serialization.js +369 -0
  284. package/build/frontend-models/use-created-event.js +21 -0
  285. package/build/frontend-models/use-destroyed-event.js +148 -0
  286. package/build/frontend-models/use-model-class-event.js +164 -0
  287. package/build/frontend-models/use-updated-event.js +152 -0
  288. package/build/frontend-models/websocket-channel.js +494 -0
  289. package/build/frontend-models/websocket-publishers.js +224 -0
  290. package/build/http-client/header.js +17 -0
  291. package/build/http-client/index.js +139 -0
  292. package/build/http-client/request.js +94 -0
  293. package/build/http-client/response.js +151 -0
  294. package/build/http-client/websocket-client.js +27 -0
  295. package/build/http-server/client/index.js +507 -0
  296. package/build/http-server/client/params-to-object.js +152 -0
  297. package/build/http-server/client/request-buffer/form-data-part.js +139 -0
  298. package/build/http-server/client/request-buffer/header.js +19 -0
  299. package/build/http-server/client/request-buffer/index.js +535 -0
  300. package/build/http-server/client/request-parser.js +195 -0
  301. package/build/http-server/client/request-runner.js +321 -0
  302. package/build/http-server/client/request-timing.js +171 -0
  303. package/build/http-server/client/request.js +114 -0
  304. package/build/http-server/client/response.js +251 -0
  305. package/build/http-server/client/uploaded-file/memory-uploaded-file.js +32 -0
  306. package/build/http-server/client/uploaded-file/temporary-uploaded-file.js +32 -0
  307. package/build/http-server/client/uploaded-file/uploaded-file.js +36 -0
  308. package/build/http-server/client/websocket-request.js +147 -0
  309. package/build/http-server/client/websocket-session.js +1755 -0
  310. package/build/http-server/cookie.js +245 -0
  311. package/build/http-server/development-reloader.js +240 -0
  312. package/build/http-server/index.js +561 -0
  313. package/build/http-server/remote-address.js +77 -0
  314. package/build/http-server/server-client.js +222 -0
  315. package/build/http-server/server-lock.js +178 -0
  316. package/build/http-server/websocket-channel-subscribers.js +110 -0
  317. package/build/http-server/websocket-channel.js +137 -0
  318. package/build/http-server/websocket-connection.js +118 -0
  319. package/build/http-server/websocket-event-log-store.js +433 -0
  320. package/build/http-server/websocket-events-host.js +170 -0
  321. package/build/http-server/websocket-events.js +50 -0
  322. package/build/http-server/worker-handler/channel-subscriber-dispatch.js +28 -0
  323. package/build/http-server/worker-handler/in-process.js +155 -0
  324. package/build/http-server/worker-handler/index.js +370 -0
  325. package/build/http-server/worker-handler/worker-script.js +6 -0
  326. package/build/http-server/worker-handler/worker-thread.js +286 -0
  327. package/build/index.js +1 -2
  328. package/build/initializer.js +39 -0
  329. package/build/jobs/mail-delivery.js +22 -0
  330. package/build/logger/base-logger.js +34 -0
  331. package/build/logger/console-logger.js +28 -0
  332. package/build/logger/file-logger.js +36 -0
  333. package/build/logger/outputs/array-output.js +50 -0
  334. package/build/logger/outputs/console-output.js +32 -0
  335. package/build/logger/outputs/file-output.js +55 -0
  336. package/build/logger/outputs/stdout-output.js +64 -0
  337. package/build/logger.js +507 -0
  338. package/build/mailer/backends/smtp.js +197 -0
  339. package/build/mailer/base.js +337 -0
  340. package/build/mailer/delivery.js +70 -0
  341. package/build/mailer/index.js +24 -0
  342. package/build/mailer.js +15 -0
  343. package/build/plugins/sqljs-wasm-route-controller.js +70 -0
  344. package/build/plugins/sqljs-wasm-route.js +71 -0
  345. package/build/record-payload-values.js +83 -0
  346. package/build/routes/app-routes.js +17 -0
  347. package/build/routes/base-route.js +133 -0
  348. package/build/routes/basic-route.js +109 -0
  349. package/build/routes/built-in/debug/controller.js +12 -0
  350. package/build/routes/built-in/errors/controller.js +7 -0
  351. package/build/routes/get-route.js +75 -0
  352. package/build/routes/hooks/frontend-model-command-route-hook.js +100 -0
  353. package/build/routes/index.js +50 -0
  354. package/build/routes/namespace-route.js +51 -0
  355. package/build/routes/plugin-routes.js +141 -0
  356. package/build/routes/post-route.js +74 -0
  357. package/build/routes/resolver.js +535 -0
  358. package/build/routes/resource-route.js +154 -0
  359. package/build/routes/root-route.js +11 -0
  360. package/build/src/authorization/ability.d.ts +24 -23
  361. package/build/src/authorization/ability.d.ts.map +1 -1
  362. package/build/src/authorization/ability.js +14 -13
  363. package/build/src/authorization/base-resource.d.ts +20 -26
  364. package/build/src/authorization/base-resource.d.ts.map +1 -1
  365. package/build/src/authorization/base-resource.js +13 -11
  366. package/build/src/configuration-types.d.ts +21 -2
  367. package/build/src/configuration-types.d.ts.map +1 -1
  368. package/build/src/configuration-types.js +8 -2
  369. package/build/src/database/query/where-combinator.d.ts.map +1 -1
  370. package/build/src/database/query/where-combinator.js +1 -2
  371. package/build/src/database/record/acts-as-list.js +2 -2
  372. package/build/src/database/record/attachments/store.d.ts +1 -1
  373. package/build/src/database/record/attachments/store.d.ts.map +1 -1
  374. package/build/src/database/record/attachments/store.js +2 -2
  375. package/build/src/database/record/index.d.ts +82 -20
  376. package/build/src/database/record/index.d.ts.map +1 -1
  377. package/build/src/database/record/index.js +126 -13
  378. package/build/src/database/record/relationships/base.d.ts +2 -2
  379. package/build/src/database/record/relationships/base.d.ts.map +1 -1
  380. package/build/src/database/record/relationships/base.js +3 -3
  381. package/build/src/environment-handlers/node/cli/commands/generate/base-models.d.ts +4 -2
  382. package/build/src/environment-handlers/node/cli/commands/generate/base-models.d.ts.map +1 -1
  383. package/build/src/environment-handlers/node/cli/commands/generate/base-models.js +59 -36
  384. package/build/src/frontend-model-controller.d.ts +6 -6
  385. package/build/src/frontend-model-controller.d.ts.map +1 -1
  386. package/build/src/frontend-model-controller.js +4 -4
  387. package/build/src/frontend-model-resource/base-resource.d.ts +18 -17
  388. package/build/src/frontend-model-resource/base-resource.d.ts.map +1 -1
  389. package/build/src/frontend-model-resource/base-resource.js +22 -10
  390. package/build/src/frontend-models/base.d.ts +19 -12
  391. package/build/src/frontend-models/base.d.ts.map +1 -1
  392. package/build/src/frontend-models/base.js +79 -48
  393. package/build/src/frontend-models/preloader.d.ts +6 -6
  394. package/build/src/frontend-models/preloader.d.ts.map +1 -1
  395. package/build/src/frontend-models/preloader.js +5 -5
  396. package/build/src/frontend-models/query.d.ts.map +1 -1
  397. package/build/src/frontend-models/query.js +1 -4
  398. package/build/src/utils/ransack.d.ts.map +1 -1
  399. package/build/src/utils/ransack.js +1 -2
  400. package/build/templates/configuration.js +61 -0
  401. package/build/templates/generate-migration.js +11 -0
  402. package/build/templates/generate-model.js +6 -0
  403. package/build/templates/routes.js +11 -0
  404. package/build/testing/base-expect.js +17 -0
  405. package/build/testing/browser-frontend-model-event-hook-scenarios.js +520 -0
  406. package/build/testing/browser-test-app.js +32 -0
  407. package/build/testing/expect-to-change.js +55 -0
  408. package/build/testing/expect-utils.js +269 -0
  409. package/build/testing/expect.js +763 -0
  410. package/build/testing/request-client.js +90 -0
  411. package/build/testing/test-files-finder.js +364 -0
  412. package/build/testing/test-filter-parser.js +198 -0
  413. package/build/testing/test-runner.js +1168 -0
  414. package/build/testing/test-suite-splitter.js +177 -0
  415. package/build/testing/test.js +370 -0
  416. package/build/utils/backtrace-cleaner-node.js +87 -0
  417. package/build/utils/backtrace-cleaner.js +266 -0
  418. package/build/utils/ensure-error.js +15 -0
  419. package/build/utils/event-emitter.js +8 -0
  420. package/build/utils/file-exists.js +18 -0
  421. package/build/utils/format-value.js +101 -0
  422. package/build/utils/model-scope.js +56 -0
  423. package/build/utils/nest-callbacks.js +22 -0
  424. package/build/utils/plain-object.js +14 -0
  425. package/build/utils/ransack.js +859 -0
  426. package/build/utils/rest-args-error.js +14 -0
  427. package/build/utils/singularize-model-name.js +18 -0
  428. package/build/utils/split-sql-statements.js +88 -0
  429. package/build/utils/to-import-specifier.js +53 -0
  430. package/build/utils/with-tracked-stack-async-hooks.js +103 -0
  431. package/build/utils/with-tracked-stack.js +38 -0
  432. package/build/velocious-error.js +34 -0
  433. package/index.js +1 -0
  434. package/package.json +10 -4
  435. package/scripts/clean-build.js +8 -0
  436. package/scripts/ensure-bin-executable.js +13 -0
  437. package/scripts/run-tests.js +37 -0
  438. package/scripts/test-browser.js +486 -0
  439. package/src/application.js +229 -0
  440. package/src/authorization/ability.js +329 -0
  441. package/src/authorization/base-resource.js +143 -0
  442. package/src/background-jobs/client.js +50 -0
  443. package/src/background-jobs/cron-expression.js +277 -0
  444. package/src/background-jobs/forked-runner-child.js +86 -0
  445. package/src/background-jobs/job-record.js +13 -0
  446. package/src/background-jobs/job-registry.js +92 -0
  447. package/src/background-jobs/job-runner.js +107 -0
  448. package/src/background-jobs/job.js +77 -0
  449. package/src/background-jobs/json-socket.js +78 -0
  450. package/src/background-jobs/main.js +926 -0
  451. package/src/background-jobs/normalize-error.js +26 -0
  452. package/src/background-jobs/scheduler.js +274 -0
  453. package/src/background-jobs/socket-request.js +68 -0
  454. package/src/background-jobs/status-reporter.js +101 -0
  455. package/src/background-jobs/store.js +994 -0
  456. package/src/background-jobs/types.js +70 -0
  457. package/src/background-jobs/web/authorization.js +89 -0
  458. package/src/background-jobs/web/controller.js +280 -0
  459. package/src/background-jobs/web/index.js +57 -0
  460. package/src/background-jobs/web/path-matcher.js +74 -0
  461. package/src/background-jobs/web/registry.js +49 -0
  462. package/src/background-jobs/worker.js +683 -0
  463. package/src/beacon/client.js +330 -0
  464. package/src/beacon/in-process-broker.js +71 -0
  465. package/src/beacon/in-process-client.js +139 -0
  466. package/src/beacon/server.js +148 -0
  467. package/src/beacon/types.js +55 -0
  468. package/src/cli/base-command.js +67 -0
  469. package/src/cli/browser-cli.js +45 -0
  470. package/src/cli/commands/background-jobs-main.js +7 -0
  471. package/src/cli/commands/background-jobs-runner.js +7 -0
  472. package/src/cli/commands/background-jobs-worker.js +7 -0
  473. package/src/cli/commands/beacon.js +7 -0
  474. package/src/cli/commands/console.js +12 -0
  475. package/src/cli/commands/db/base-command.js +82 -0
  476. package/src/cli/commands/db/create.js +64 -0
  477. package/src/cli/commands/db/drop.js +75 -0
  478. package/src/cli/commands/db/migrate.js +17 -0
  479. package/src/cli/commands/db/reset.js +22 -0
  480. package/src/cli/commands/db/rollback.js +15 -0
  481. package/src/cli/commands/db/schema/dump.js +12 -0
  482. package/src/cli/commands/db/schema/load.js +12 -0
  483. package/src/cli/commands/db/seed.js +12 -0
  484. package/src/cli/commands/db/tenants/check.js +38 -0
  485. package/src/cli/commands/db/tenants/create.js +33 -0
  486. package/src/cli/commands/db/tenants/migrate.js +49 -0
  487. package/src/cli/commands/destroy/migration.js +7 -0
  488. package/src/cli/commands/generate/base-models.js +7 -0
  489. package/src/cli/commands/generate/frontend-models.js +12 -0
  490. package/src/cli/commands/generate/migration.js +7 -0
  491. package/src/cli/commands/generate/model.js +7 -0
  492. package/src/cli/commands/init.js +11 -0
  493. package/src/cli/commands/routes.js +7 -0
  494. package/src/cli/commands/run-script.js +12 -0
  495. package/src/cli/commands/runner.js +12 -0
  496. package/src/cli/commands/server.js +7 -0
  497. package/src/cli/commands/test.js +9 -0
  498. package/src/cli/index.js +152 -0
  499. package/src/cli/tenant-database-command-helper.js +198 -0
  500. package/src/cli/use-browser-cli.js +30 -0
  501. package/src/configuration-resolver.js +65 -0
  502. package/src/configuration-types.js +429 -0
  503. package/src/configuration.js +2590 -0
  504. package/src/controller.js +421 -0
  505. package/src/current-configuration.js +31 -0
  506. package/src/current.js +80 -0
  507. package/src/database/annotations-async-hooks.js +47 -0
  508. package/src/database/annotations.js +40 -0
  509. package/src/database/drivers/base-column.js +182 -0
  510. package/src/database/drivers/base-columns-index.js +81 -0
  511. package/src/database/drivers/base-foreign-key.js +104 -0
  512. package/src/database/drivers/base-table.js +156 -0
  513. package/src/database/drivers/base.js +1609 -0
  514. package/src/database/drivers/mssql/column.js +74 -0
  515. package/src/database/drivers/mssql/columns-index.js +6 -0
  516. package/src/database/drivers/mssql/connect-connection.js +16 -0
  517. package/src/database/drivers/mssql/foreign-key.js +12 -0
  518. package/src/database/drivers/mssql/index.js +590 -0
  519. package/src/database/drivers/mssql/options.js +79 -0
  520. package/src/database/drivers/mssql/query-parser.js +6 -0
  521. package/src/database/drivers/mssql/sql/alter-table.js +4 -0
  522. package/src/database/drivers/mssql/sql/create-database.js +36 -0
  523. package/src/database/drivers/mssql/sql/create-index.js +4 -0
  524. package/src/database/drivers/mssql/sql/create-table.js +4 -0
  525. package/src/database/drivers/mssql/sql/delete.js +19 -0
  526. package/src/database/drivers/mssql/sql/drop-database.js +36 -0
  527. package/src/database/drivers/mssql/sql/drop-table.js +4 -0
  528. package/src/database/drivers/mssql/sql/insert.js +4 -0
  529. package/src/database/drivers/mssql/sql/update.js +31 -0
  530. package/src/database/drivers/mssql/sql/upsert.js +23 -0
  531. package/src/database/drivers/mssql/structure-sql.js +120 -0
  532. package/src/database/drivers/mssql/table.js +145 -0
  533. package/src/database/drivers/mysql/column.js +112 -0
  534. package/src/database/drivers/mysql/columns-index.js +22 -0
  535. package/src/database/drivers/mysql/foreign-key.js +12 -0
  536. package/src/database/drivers/mysql/index.js +473 -0
  537. package/src/database/drivers/mysql/options.js +34 -0
  538. package/src/database/drivers/mysql/query-parser.js +6 -0
  539. package/src/database/drivers/mysql/query.js +37 -0
  540. package/src/database/drivers/mysql/sql/alter-table.js +6 -0
  541. package/src/database/drivers/mysql/sql/create-database.js +39 -0
  542. package/src/database/drivers/mysql/sql/create-index.js +6 -0
  543. package/src/database/drivers/mysql/sql/create-table.js +6 -0
  544. package/src/database/drivers/mysql/sql/delete.js +21 -0
  545. package/src/database/drivers/mysql/sql/drop-database.js +6 -0
  546. package/src/database/drivers/mysql/sql/drop-table.js +6 -0
  547. package/src/database/drivers/mysql/sql/insert.js +6 -0
  548. package/src/database/drivers/mysql/sql/update.js +33 -0
  549. package/src/database/drivers/mysql/sql/upsert.js +13 -0
  550. package/src/database/drivers/mysql/structure-sql.js +93 -0
  551. package/src/database/drivers/mysql/table.js +121 -0
  552. package/src/database/drivers/pgsql/column.js +90 -0
  553. package/src/database/drivers/pgsql/columns-index.js +6 -0
  554. package/src/database/drivers/pgsql/foreign-key.js +12 -0
  555. package/src/database/drivers/pgsql/index.js +441 -0
  556. package/src/database/drivers/pgsql/options.js +32 -0
  557. package/src/database/drivers/pgsql/query-parser.js +6 -0
  558. package/src/database/drivers/pgsql/sql/alter-table.js +6 -0
  559. package/src/database/drivers/pgsql/sql/create-database.js +38 -0
  560. package/src/database/drivers/pgsql/sql/create-index.js +6 -0
  561. package/src/database/drivers/pgsql/sql/create-table.js +6 -0
  562. package/src/database/drivers/pgsql/sql/delete.js +21 -0
  563. package/src/database/drivers/pgsql/sql/drop-database.js +6 -0
  564. package/src/database/drivers/pgsql/sql/drop-table.js +6 -0
  565. package/src/database/drivers/pgsql/sql/insert.js +6 -0
  566. package/src/database/drivers/pgsql/sql/update.js +33 -0
  567. package/src/database/drivers/pgsql/sql/upsert.js +14 -0
  568. package/src/database/drivers/pgsql/structure-sql.js +126 -0
  569. package/src/database/drivers/pgsql/table.js +135 -0
  570. package/src/database/drivers/sqlite/base.js +509 -0
  571. package/src/database/drivers/sqlite/column.js +75 -0
  572. package/src/database/drivers/sqlite/columns-index.js +30 -0
  573. package/src/database/drivers/sqlite/connection-sql-js.js +46 -0
  574. package/src/database/drivers/sqlite/foreign-key.js +24 -0
  575. package/src/database/drivers/sqlite/index.js +394 -0
  576. package/src/database/drivers/sqlite/index.native.js +72 -0
  577. package/src/database/drivers/sqlite/index.web.js +99 -0
  578. package/src/database/drivers/sqlite/options.js +32 -0
  579. package/src/database/drivers/sqlite/query-parser.js +6 -0
  580. package/src/database/drivers/sqlite/query.js +35 -0
  581. package/src/database/drivers/sqlite/query.native.js +35 -0
  582. package/src/database/drivers/sqlite/query.web.js +49 -0
  583. package/src/database/drivers/sqlite/sql/alter-table.js +187 -0
  584. package/src/database/drivers/sqlite/sql/create-index.js +6 -0
  585. package/src/database/drivers/sqlite/sql/create-table.js +6 -0
  586. package/src/database/drivers/sqlite/sql/delete.js +26 -0
  587. package/src/database/drivers/sqlite/sql/drop-table.js +6 -0
  588. package/src/database/drivers/sqlite/sql/insert.js +6 -0
  589. package/src/database/drivers/sqlite/sql/update.js +33 -0
  590. package/src/database/drivers/sqlite/sql/upsert.js +14 -0
  591. package/src/database/drivers/sqlite/structure-sql.js +56 -0
  592. package/src/database/drivers/sqlite/table-rebuilder.js +96 -0
  593. package/src/database/drivers/sqlite/table.js +131 -0
  594. package/src/database/drivers/structure-sql/utils.js +35 -0
  595. package/src/database/handler.js +13 -0
  596. package/src/database/initializer-from-require-context.js +101 -0
  597. package/src/database/migration/index.js +438 -0
  598. package/src/database/migrator/files-finder.js +55 -0
  599. package/src/database/migrator/types.js +31 -0
  600. package/src/database/migrator.js +557 -0
  601. package/src/database/pool/async-tracked-multi-connection.js +1164 -0
  602. package/src/database/pool/base-methods-forward.js +52 -0
  603. package/src/database/pool/base.js +380 -0
  604. package/src/database/pool/single-multi-use.js +118 -0
  605. package/src/database/query/alter-table-base.js +104 -0
  606. package/src/database/query/base.js +49 -0
  607. package/src/database/query/create-database-base.js +42 -0
  608. package/src/database/query/create-index-base.js +117 -0
  609. package/src/database/query/create-table-base.js +205 -0
  610. package/src/database/query/delete-base.js +19 -0
  611. package/src/database/query/drop-database-base.js +38 -0
  612. package/src/database/query/drop-table-base.js +58 -0
  613. package/src/database/query/from-base.js +36 -0
  614. package/src/database/query/from-plain.js +16 -0
  615. package/src/database/query/from-table.js +18 -0
  616. package/src/database/query/index.js +533 -0
  617. package/src/database/query/insert-base.js +172 -0
  618. package/src/database/query/join-base.js +43 -0
  619. package/src/database/query/join-object.js +167 -0
  620. package/src/database/query/join-plain.js +18 -0
  621. package/src/database/query/join-tracker.js +93 -0
  622. package/src/database/query/model-class-query.js +1577 -0
  623. package/src/database/query/order-base.js +33 -0
  624. package/src/database/query/order-column.js +77 -0
  625. package/src/database/query/order-plain.js +28 -0
  626. package/src/database/query/preloader/belongs-to.js +267 -0
  627. package/src/database/query/preloader/ensure-model-class-initialized.js +18 -0
  628. package/src/database/query/preloader/has-many.js +316 -0
  629. package/src/database/query/preloader/has-one.js +123 -0
  630. package/src/database/query/preloader/selection.js +152 -0
  631. package/src/database/query/preloader.js +201 -0
  632. package/src/database/query/query-data.js +305 -0
  633. package/src/database/query/select-base.js +30 -0
  634. package/src/database/query/select-plain.js +18 -0
  635. package/src/database/query/select-table-and-column.js +28 -0
  636. package/src/database/query/update-base.js +41 -0
  637. package/src/database/query/upsert-base.js +103 -0
  638. package/src/database/query/where-base.js +38 -0
  639. package/src/database/query/where-combinator.js +31 -0
  640. package/src/database/query/where-hash.js +77 -0
  641. package/src/database/query/where-model-class-hash.js +505 -0
  642. package/src/database/query/where-not.js +23 -0
  643. package/src/database/query/where-plain.js +20 -0
  644. package/src/database/query/with-count.js +219 -0
  645. package/src/database/query-parser/base-query-parser.js +40 -0
  646. package/src/database/query-parser/from-parser.js +49 -0
  647. package/src/database/query-parser/group-parser.js +55 -0
  648. package/src/database/query-parser/joins-parser.js +37 -0
  649. package/src/database/query-parser/limit-parser.js +77 -0
  650. package/src/database/query-parser/options.js +94 -0
  651. package/src/database/query-parser/order-parser.js +45 -0
  652. package/src/database/query-parser/select-parser.js +67 -0
  653. package/src/database/query-parser/where-parser.js +46 -0
  654. package/src/database/record/acts-as-list.js +374 -0
  655. package/src/database/record/attachments/download.js +49 -0
  656. package/src/database/record/attachments/handle.js +188 -0
  657. package/src/database/record/attachments/normalize-input.js +213 -0
  658. package/src/database/record/attachments/storage-drivers/filesystem.js +114 -0
  659. package/src/database/record/attachments/storage-drivers/native.js +146 -0
  660. package/src/database/record/attachments/storage-drivers/s3.js +245 -0
  661. package/src/database/record/attachments/store.js +591 -0
  662. package/src/database/record/index.js +4094 -0
  663. package/src/database/record/instance-relationships/base.js +289 -0
  664. package/src/database/record/instance-relationships/belongs-to.js +84 -0
  665. package/src/database/record/instance-relationships/has-many.js +284 -0
  666. package/src/database/record/instance-relationships/has-one.js +117 -0
  667. package/src/database/record/record-not-found-error.js +3 -0
  668. package/src/database/record/relationships/base.js +195 -0
  669. package/src/database/record/relationships/belongs-to.js +57 -0
  670. package/src/database/record/relationships/has-many.js +46 -0
  671. package/src/database/record/relationships/has-one.js +46 -0
  672. package/src/database/record/state-machine.js +278 -0
  673. package/src/database/record/user-module.js +43 -0
  674. package/src/database/record/validators/base.js +27 -0
  675. package/src/database/record/validators/format.js +50 -0
  676. package/src/database/record/validators/presence.js +24 -0
  677. package/src/database/record/validators/uniqueness.js +124 -0
  678. package/src/database/table-data/index.js +241 -0
  679. package/src/database/table-data/table-column.js +416 -0
  680. package/src/database/table-data/table-foreign-key.js +69 -0
  681. package/src/database/table-data/table-index.js +46 -0
  682. package/src/database/table-data/table-reference.js +13 -0
  683. package/src/database/use-database.js +48 -0
  684. package/src/environment-handlers/base.js +561 -0
  685. package/src/environment-handlers/browser.js +338 -0
  686. package/src/environment-handlers/node/cli/commands/background-jobs-main.js +21 -0
  687. package/src/environment-handlers/node/cli/commands/background-jobs-runner.js +24 -0
  688. package/src/environment-handlers/node/cli/commands/background-jobs-worker.js +47 -0
  689. package/src/environment-handlers/node/cli/commands/beacon.js +21 -0
  690. package/src/environment-handlers/node/cli/commands/cli-command-context.js +31 -0
  691. package/src/environment-handlers/node/cli/commands/console.js +149 -0
  692. package/src/environment-handlers/node/cli/commands/db/schema/dump.js +43 -0
  693. package/src/environment-handlers/node/cli/commands/db/schema/load.js +69 -0
  694. package/src/environment-handlers/node/cli/commands/db/seed.js +79 -0
  695. package/src/environment-handlers/node/cli/commands/destroy/migration.js +47 -0
  696. package/src/environment-handlers/node/cli/commands/generate/base-models.js +396 -0
  697. package/src/environment-handlers/node/cli/commands/generate/frontend-models.js +872 -0
  698. package/src/environment-handlers/node/cli/commands/generate/migration.js +45 -0
  699. package/src/environment-handlers/node/cli/commands/generate/model.js +45 -0
  700. package/src/environment-handlers/node/cli/commands/init.js +68 -0
  701. package/src/environment-handlers/node/cli/commands/routes.js +63 -0
  702. package/src/environment-handlers/node/cli/commands/run-script.js +85 -0
  703. package/src/environment-handlers/node/cli/commands/runner.js +84 -0
  704. package/src/environment-handlers/node/cli/commands/server.js +151 -0
  705. package/src/environment-handlers/node/cli/commands/test.js +118 -0
  706. package/src/environment-handlers/node.js +887 -0
  707. package/src/error-logger.js +30 -0
  708. package/src/frontend-model-controller.js +3491 -0
  709. package/src/frontend-model-resource/base-resource.js +935 -0
  710. package/src/frontend-models/base.js +4004 -0
  711. package/src/frontend-models/clear-pending-debounced-callback.js +16 -0
  712. package/src/frontend-models/event-hook-models.js +49 -0
  713. package/src/frontend-models/model-registry.js +28 -0
  714. package/src/frontend-models/outgoing-event-buffer.js +51 -0
  715. package/src/frontend-models/preloader.js +169 -0
  716. package/src/frontend-models/query.js +2245 -0
  717. package/src/frontend-models/resource-config-validation.js +56 -0
  718. package/src/frontend-models/resource-definition.js +399 -0
  719. package/src/frontend-models/transport-serialization.js +369 -0
  720. package/src/frontend-models/use-created-event.js +21 -0
  721. package/src/frontend-models/use-destroyed-event.js +148 -0
  722. package/src/frontend-models/use-model-class-event.js +164 -0
  723. package/src/frontend-models/use-updated-event.js +152 -0
  724. package/src/frontend-models/websocket-channel.js +494 -0
  725. package/src/frontend-models/websocket-publishers.js +224 -0
  726. package/src/http-client/header.js +17 -0
  727. package/src/http-client/index.js +139 -0
  728. package/src/http-client/request.js +94 -0
  729. package/src/http-client/response.js +151 -0
  730. package/src/http-client/websocket-client.js +27 -0
  731. package/src/http-server/client/index.js +507 -0
  732. package/src/http-server/client/params-to-object.js +152 -0
  733. package/src/http-server/client/request-buffer/form-data-part.js +139 -0
  734. package/src/http-server/client/request-buffer/header.js +19 -0
  735. package/src/http-server/client/request-buffer/index.js +535 -0
  736. package/src/http-server/client/request-parser.js +195 -0
  737. package/src/http-server/client/request-runner.js +321 -0
  738. package/src/http-server/client/request-timing.js +171 -0
  739. package/src/http-server/client/request.js +114 -0
  740. package/src/http-server/client/response.js +251 -0
  741. package/src/http-server/client/uploaded-file/memory-uploaded-file.js +32 -0
  742. package/src/http-server/client/uploaded-file/temporary-uploaded-file.js +32 -0
  743. package/src/http-server/client/uploaded-file/uploaded-file.js +36 -0
  744. package/src/http-server/client/websocket-request.js +147 -0
  745. package/src/http-server/client/websocket-session.js +1755 -0
  746. package/src/http-server/cookie.js +245 -0
  747. package/src/http-server/development-reloader.js +240 -0
  748. package/src/http-server/index.js +561 -0
  749. package/src/http-server/remote-address.js +77 -0
  750. package/src/http-server/server-client.js +222 -0
  751. package/src/http-server/server-lock.js +178 -0
  752. package/src/http-server/websocket-channel-subscribers.js +110 -0
  753. package/src/http-server/websocket-channel.js +137 -0
  754. package/src/http-server/websocket-connection.js +118 -0
  755. package/src/http-server/websocket-event-log-store.js +433 -0
  756. package/src/http-server/websocket-events-host.js +170 -0
  757. package/src/http-server/websocket-events.js +50 -0
  758. package/src/http-server/worker-handler/channel-subscriber-dispatch.js +28 -0
  759. package/src/http-server/worker-handler/in-process.js +155 -0
  760. package/src/http-server/worker-handler/index.js +370 -0
  761. package/src/http-server/worker-handler/worker-script.js +6 -0
  762. package/src/http-server/worker-handler/worker-thread.js +286 -0
  763. package/src/initializer.js +39 -0
  764. package/src/jobs/.gitkeep +1 -0
  765. package/src/jobs/mail-delivery.js +22 -0
  766. package/src/logger/base-logger.js +34 -0
  767. package/src/logger/console-logger.js +28 -0
  768. package/src/logger/file-logger.js +36 -0
  769. package/src/logger/outputs/array-output.js +50 -0
  770. package/src/logger/outputs/console-output.js +32 -0
  771. package/src/logger/outputs/file-output.js +55 -0
  772. package/src/logger/outputs/stdout-output.js +64 -0
  773. package/src/logger.js +507 -0
  774. package/src/mailer/backends/smtp.js +197 -0
  775. package/src/mailer/base.js +337 -0
  776. package/src/mailer/delivery.js +70 -0
  777. package/src/mailer/index.js +24 -0
  778. package/src/mailer.js +15 -0
  779. package/src/plugins/sqljs-wasm-route-controller.js +70 -0
  780. package/src/plugins/sqljs-wasm-route.js +71 -0
  781. package/src/record-payload-values.js +83 -0
  782. package/src/routes/app-routes.js +17 -0
  783. package/src/routes/base-route.js +133 -0
  784. package/src/routes/basic-route.js +109 -0
  785. package/src/routes/built-in/debug/controller.js +12 -0
  786. package/src/routes/built-in/errors/controller.js +7 -0
  787. package/src/routes/built-in/errors/not-found.ejs +1 -0
  788. package/src/routes/get-route.js +75 -0
  789. package/src/routes/hooks/frontend-model-command-route-hook.js +100 -0
  790. package/src/routes/index.js +50 -0
  791. package/src/routes/namespace-route.js +51 -0
  792. package/src/routes/plugin-routes.js +141 -0
  793. package/src/routes/post-route.js +74 -0
  794. package/src/routes/resolver.js +535 -0
  795. package/src/routes/resource-route.js +154 -0
  796. package/src/routes/root-route.js +11 -0
  797. package/src/templates/configuration.js +61 -0
  798. package/src/templates/generate-migration.js +11 -0
  799. package/src/templates/generate-model.js +6 -0
  800. package/src/templates/routes.js +11 -0
  801. package/src/testing/base-expect.js +17 -0
  802. package/src/testing/browser-frontend-model-event-hook-scenarios.js +520 -0
  803. package/src/testing/browser-test-app.js +32 -0
  804. package/src/testing/expect-to-change.js +55 -0
  805. package/src/testing/expect-utils.js +269 -0
  806. package/src/testing/expect.js +763 -0
  807. package/src/testing/request-client.js +90 -0
  808. package/src/testing/test-files-finder.js +364 -0
  809. package/src/testing/test-filter-parser.js +198 -0
  810. package/src/testing/test-runner.js +1168 -0
  811. package/src/testing/test-suite-splitter.js +177 -0
  812. package/src/testing/test.js +370 -0
  813. package/src/types/external-modules.d.ts +57 -0
  814. package/src/utils/backtrace-cleaner-node.js +87 -0
  815. package/src/utils/backtrace-cleaner.js +266 -0
  816. package/src/utils/ensure-error.js +15 -0
  817. package/src/utils/event-emitter.js +8 -0
  818. package/src/utils/file-exists.js +18 -0
  819. package/src/utils/format-value.js +101 -0
  820. package/src/utils/model-scope.js +56 -0
  821. package/src/utils/nest-callbacks.js +22 -0
  822. package/src/utils/plain-object.js +14 -0
  823. package/src/utils/ransack.js +859 -0
  824. package/src/utils/rest-args-error.js +14 -0
  825. package/src/utils/singularize-model-name.js +18 -0
  826. package/src/utils/split-sql-statements.js +88 -0
  827. package/src/utils/to-import-specifier.js +53 -0
  828. package/src/utils/with-tracked-stack-async-hooks.js +103 -0
  829. package/src/utils/with-tracked-stack.js +38 -0
  830. package/src/velocious-error.js +34 -0
  831. package/tsconfig.json +16 -0
@@ -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 {typeof import("../../../../../frontend-model-resource/base-resource.js").default | 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 {typeof import("../../../../../frontend-model-resource/base-resource.js").default | 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 {typeof import("../../../../../frontend-model-resource/base-resource.js").default | 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 {typeof import("../../../../../frontend-model-resource/base-resource.js").default | 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 {typeof import("../../../../../frontend-model-resource/base-resource.js").default | 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
+ }