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,939 @@
1
+ // @ts-check
2
+
3
+ import AuthorizationBaseResource from "../authorization/base-resource.js"
4
+ import * as inflection from "inflection"
5
+
6
+ /**
7
+ * FrontendModelResourceControllerArgs type.
8
+ * @typedef {object} FrontendModelResourceControllerArgs
9
+ * @property {import("../controller.js").default} controller - Frontend-model controller instance.
10
+ * @property {typeof import("../database/record/index.js").default} modelClass - Backing model class.
11
+ * @property {string} modelName - Model name.
12
+ * @property {import("../configuration-types.js").VelociousLooseObject} params - Request params.
13
+ * @property {import("../configuration-types.js").NormalizedFrontendModelResourceConfiguration | import("../configuration-types.js").FrontendModelResourceConfiguration} resourceConfiguration - Normalized resource configuration (or raw input shape during early bootstrap).
14
+ */
15
+
16
+ /**
17
+ * FrontendModelResourceAbilityArgs type.
18
+ * @typedef {object} FrontendModelResourceAbilityArgs
19
+ * @property {import("../authorization/ability.js").default} [ability] - Ability instance when the resource is used directly for authorization.
20
+ * @property {import("../configuration-types.js").VelociousLooseObject} [context] - Ability context.
21
+ * @property {import("../configuration-types.js").VelociousLooseObject} [locals] - Ability locals.
22
+ * @property {typeof import("../database/record/index.js").default} [modelClass] - Optional backing model class override.
23
+ * @property {string} [modelName] - Optional model name override.
24
+ * @property {import("../configuration-types.js").VelociousLooseObject} [params] - Optional params override.
25
+ * @property {import("../configuration-types.js").NormalizedFrontendModelResourceConfiguration | import("../configuration-types.js").FrontendModelResourceConfiguration} [resourceConfiguration] - Optional normalized resource configuration.
26
+ */
27
+
28
+ /**
29
+ * Base class for backend frontend-model resources.
30
+ * @template {typeof import("../database/record/index.js").default} [out TModelClass=typeof import("../database/record/index.js").default]
31
+ */
32
+ export default class FrontendModelBaseResource extends AuthorizationBaseResource {
33
+ /**
34
+ * Backing model class.
35
+ @type {typeof import("../database/record/index.js").default | undefined} */
36
+ static ModelClass = undefined
37
+
38
+ /**
39
+ * Attributes.
40
+ @type {Record<string, ?> | string[] | undefined} */
41
+ static attributes = undefined
42
+ /**
43
+ * Abilities.
44
+ @type {string[] | undefined} */
45
+ static abilities = undefined
46
+ /**
47
+ * Attachments.
48
+ @type {Record<string, ?> | undefined} */
49
+ static attachments = undefined
50
+ /**
51
+ * Collection commands.
52
+ @type {string[] | undefined} */
53
+ static collectionCommands = undefined
54
+ /**
55
+ * Built in collection commands.
56
+ @type {string[] | undefined} */
57
+ static builtInCollectionCommands = undefined
58
+ /**
59
+ * Member commands.
60
+ @type {string[] | undefined} */
61
+ static memberCommands = undefined
62
+ /**
63
+ * Built in member commands.
64
+ @type {string[] | undefined} */
65
+ static builtInMemberCommands = undefined
66
+ /**
67
+ * Relationships.
68
+ @type {string[] | undefined} */
69
+ static relationships = undefined
70
+ /**
71
+ * Translated attributes.
72
+ @type {string[] | undefined} */
73
+ static translatedAttributes = undefined
74
+
75
+ /**
76
+ * Runs constructor.
77
+ * @param {FrontendModelResourceAbilityArgs | FrontendModelResourceControllerArgs} args - Resource args.
78
+ */
79
+ constructor(args) {
80
+ super({
81
+ ability: "ability" in args ? args.ability : undefined,
82
+ context: "context" in args ? args.context || {} : {},
83
+ locals: "locals" in args ? args.locals || {} : {}
84
+ })
85
+
86
+ this.controller = "controller" in args ? args.controller : undefined
87
+ this.modelClassValue = "modelClass" in args ? args.modelClass : /**
88
+ * Narrows the runtime value to the documented type.
89
+ @type {typeof import("../database/record/index.js").default | undefined} */ (/**
90
+ * Narrows the runtime value to the documented type.
91
+ @type {typeof FrontendModelBaseResource} */ (this.constructor).modelClass())
92
+ this.modelNameValue = "modelName" in args ? args.modelName : (this.modelClassValue?.getModelName ? this.modelClassValue.getModelName() : this.modelClassValue?.name || "")
93
+ this.paramsValue = "params" in args ? args.params : undefined
94
+ this.resourceConfigurationValue = "resourceConfiguration" in args ? args.resourceConfiguration : /**
95
+ * Narrows the runtime value to the documented type.
96
+ @type {import("../configuration-types.js").FrontendModelResourceConfiguration} */ ({attributes: []})
97
+ }
98
+
99
+ /**
100
+ * Runs typed controller instance.
101
+ * @returns {import("../controller.js").default & {
102
+ * frontendModelAuthorizedQuery: (action: "index" | "find" | "create" | "update" | "destroy" | "attach" | "download" | "url") => import("../database/query/model-class-query.js").default<typeof import("../database/record/index.js").default>,
103
+ * frontendModelAbilityAction: (action: string) => string,
104
+ * currentAbility: () => import("../authorization/ability.js").default | undefined,
105
+ * frontendModelIndexQuery: () => import("../database/query/model-class-query.js").default<typeof import("../database/record/index.js").default>,
106
+ * frontendModelPreload: () => import("../database/query/index.js").NestedPreloadRecord | null,
107
+ * serializeFrontendModel: (model: import("../database/record/index.js").default) => Promise<Record<string, unknown>>
108
+ * }} - Controller instance with frontend-model helpers.
109
+ */
110
+ typedControllerInstance() {
111
+ return /** Narrows the runtime value to the documented type. @type {?} */ (this.controller)
112
+ }
113
+
114
+ /**
115
+ * Runs resource config.
116
+ * @returns {import("../configuration-types.js").FrontendModelResourceConfiguration} - Static resource config (raw user input shape; consumers normalize).
117
+ */
118
+ static resourceConfig() {
119
+ /**
120
+ * Config.
121
+ @type {import("../configuration-types.js").FrontendModelResourceConfiguration} */
122
+ const config = {
123
+ attributes: this.attributes || []
124
+ }
125
+
126
+ if (this.abilities) config.abilities = this.abilities
127
+ if (this.attachments) config.attachments = this.attachments
128
+ if (this.builtInCollectionCommands) config.builtInCollectionCommands = this.builtInCollectionCommands
129
+ if (this.builtInMemberCommands) config.builtInMemberCommands = this.builtInMemberCommands
130
+ if (this.collectionCommands) config.collectionCommands = this.collectionCommands
131
+ if (this.memberCommands) config.memberCommands = this.memberCommands
132
+ if (this.relationships) config.relationships = this.relationships
133
+
134
+ return config
135
+ }
136
+
137
+ /**
138
+ * Runs static model class.
139
+ * @returns {typeof import("../database/record/index.js").default | undefined} - Backing model class.
140
+ */
141
+ static modelClass() {
142
+ return this.ModelClass
143
+ }
144
+
145
+ /**
146
+ * Runs controller instance.
147
+ * @returns {import("../controller.js").default} - Controller instance.
148
+ */
149
+ controllerInstance() {
150
+ if (!this.controller) throw new Error(`${this.constructor.name} requires a controller instance.`)
151
+
152
+ return this.controller
153
+ }
154
+
155
+ /**
156
+ * Runs model class.
157
+ * @returns {TModelClass} - Model class.
158
+ */
159
+ modelClass() {
160
+ if (!this.modelClassValue) {
161
+ throw new Error(`${this.constructor.name} requires a model class.`)
162
+ }
163
+
164
+ return /** @type {TModelClass} */ (this.modelClassValue)
165
+ }
166
+
167
+ /**
168
+ * Runs model name.
169
+ * @returns {string} - Model name.
170
+ */
171
+ modelName() {
172
+ if (!this.modelNameValue) throw new Error(`${this.constructor.name} requires a model name.`)
173
+
174
+ return this.modelNameValue
175
+ }
176
+
177
+ /**
178
+ * Runs params.
179
+ * @returns {import("../configuration-types.js").VelociousLooseObject} - Params.
180
+ */
181
+ params() { return this.paramsValue || super.params() || {} }
182
+
183
+ /**
184
+ * Runs resource configuration.
185
+ * @returns {import("../configuration-types.js").NormalizedFrontendModelResourceConfiguration | import("../configuration-types.js").FrontendModelResourceConfiguration} - Resource config (normalized at runtime; raw during early bootstrap).
186
+ */
187
+ resourceConfiguration() {
188
+ if (!this.resourceConfigurationValue) throw new Error(`${this.constructor.name} requires a resource configuration.`)
189
+
190
+ return this.resourceConfigurationValue
191
+ }
192
+
193
+ /**
194
+ * Returns a Rails-strong-params / api_maker-style permit spec declaring
195
+ * which attributes and nested attributes are writable for the current
196
+ * request. Submitting an attribute or nested-relationship key that is
197
+ * not permitted raises an error and fails the write.
198
+ *
199
+ * The returned value is a flat array that mixes:
200
+ * - `"attributeName"` strings for plain attribute writes
201
+ * - `{<relationshipName>Attributes: [...]}` objects where the value
202
+ * is itself a permit spec for the nested relationship
203
+ *
204
+ * This matches Rails strong_params (`permit(:first_name, :last_name,
205
+ * contact_attributes: [:email, details_attributes: [:detail]])`) and
206
+ * the api_maker sister project. Include `"_destroy"` inside a nested
207
+ * permit to allow `_destroy: true` entries for that relationship —
208
+ * the model must also declare `acceptsNestedAttributesFor(name,
209
+ * {allowDestroy: true})` for the destroy to be applied.
210
+ *
211
+ * Example:
212
+ *
213
+ * class ProjectResource extends FrontendModelBaseResource {
214
+ * permittedParams(arg) {
215
+ * return [
216
+ * "name",
217
+ * "description",
218
+ * {tasksAttributes: ["id", "_destroy", "name",
219
+ * {subtasksAttributes: ["id", "_destroy", "name"]}
220
+ * ]}
221
+ * ]
222
+ * }
223
+ * }
224
+ *
225
+ * Default implementation returns `[]` — nothing permitted. Subclasses
226
+ * must override to enable writes. A resource that does not declare
227
+ * `permittedParams` cannot accept any write.
228
+ * @param {{action?: "create" | "update", params?: Record<string, ?>, ability?: import("../authorization/ability.js").default, locals?: Record<string, ?>}} [arg] - Request context.
229
+ * @returns {Array<string | Record<string, ?>>} - Permit spec.
230
+ */
231
+ permittedParams(arg) {
232
+ void arg
233
+
234
+ return []
235
+ }
236
+
237
+ /**
238
+ * Runs primary key.
239
+ * @returns {string} - Primary key.
240
+ */
241
+ primaryKey() { return this.modelClass().primaryKey() }
242
+
243
+ /**
244
+ * Runs authorized query.
245
+ * @param {"index" | "find" | "create" | "update" | "destroy" | "attach" | "download" | "url"} action - Ability action.
246
+ * @template {typeof import("../database/record/index.js").default} [MC=typeof import("../database/record/index.js").default]
247
+ * @returns {import("../database/query/model-class-query.js").default<MC>} - Authorized query.
248
+ */
249
+ authorizedQuery(action) {
250
+ return /** Narrows the authorized query to the resource's model class. @type {import("../database/query/model-class-query.js").default<MC>} */ (this.typedControllerInstance().frontendModelAuthorizedQuery(action))
251
+ }
252
+
253
+
254
+ /**
255
+ * Runs supports pluck.
256
+ * @param {"index" | "find" | "create" | "update" | "destroy" | "attach" | "download" | "url"} action - Action.
257
+ * @returns {boolean | Promise<boolean>} - Whether pluck is supported.
258
+ */
259
+ supportsPluck(action) {
260
+ void action
261
+
262
+ return Object.getPrototypeOf(this).records === FrontendModelBaseResource.prototype.records
263
+ }
264
+
265
+ /**
266
+ * Runs supports count.
267
+ * @param {"index" | "find" | "create" | "update" | "destroy" | "attach" | "download" | "url"} action - Action.
268
+ * @returns {boolean | Promise<boolean>} - Whether count is supported.
269
+ */
270
+ supportsCount(action) {
271
+ void action
272
+
273
+ return Object.getPrototypeOf(this).records === FrontendModelBaseResource.prototype.records ||
274
+ Object.getPrototypeOf(this).count !== FrontendModelBaseResource.prototype.count
275
+ }
276
+
277
+ /**
278
+ * Runs before action.
279
+ * @param {"index" | "find" | "create" | "update" | "destroy" | "attach" | "download" | "url"} action - Action.
280
+ * @returns {boolean | void | Promise<boolean | void>} - Continue processing unless false.
281
+ */
282
+ beforeAction(action) {
283
+ void action
284
+
285
+ // No-op by default.
286
+ }
287
+
288
+ /**
289
+ * Runs records.
290
+ * @returns {Promise<import("../database/record/index.js").default[]>} - Records for index action.
291
+ */
292
+ async records() {
293
+ return await this.typedControllerInstance().frontendModelIndexQuery().toArray()
294
+ }
295
+
296
+ /**
297
+ * Runs count.
298
+ * @returns {Promise<number>} - Records count for index action.
299
+ */
300
+ async count() {
301
+ return await this.typedControllerInstance().frontendModelIndexQuery().count()
302
+ }
303
+
304
+ /**
305
+ * Runs find.
306
+ * @param {"find" | "update" | "destroy" | "attach" | "download" | "url"} action - Action.
307
+ * @param {string | number} id - Record id.
308
+ * @returns {Promise<import("../database/record/index.js").default | null>} - Located model.
309
+ */
310
+ async find(action, id) {
311
+ let query = this.authorizedQuery(action)
312
+ const preload = action === "find" ? this.typedControllerInstance().frontendModelPreload() : null
313
+
314
+ if (preload) {
315
+ query = query.preload(preload)
316
+ }
317
+
318
+ return await query.findBy({[this.primaryKey()]: id})
319
+ }
320
+
321
+ /**
322
+ * Runs create.
323
+ * @param {Record<string, ?>} attributes - Create attributes.
324
+ * @param {{controller?: ?, nestedAttributes?: Record<string, ?> | null}} [options] - Save options.
325
+ * @returns {Promise<import("../database/record/index.js").default>} - Created model.
326
+ */
327
+ async create(attributes, options = {}) {
328
+ const permit = parsePermittedParams(this.permittedParams({action: "create", ability: this.ability, locals: this.locals, params: attributes}))
329
+ const filtered = filterWritableFrontendModelAttributes(this.modelClass().prototype, attributes, this, permit.attributes)
330
+ const ModelClass = this.modelClass()
331
+ const model = new ModelClass()
332
+
333
+ await ModelClass.transaction(async () => {
334
+ await this._assignWithVirtualSetters(model, filtered)
335
+ await model.save()
336
+
337
+ if (options.nestedAttributes) {
338
+ await this._applyNestedAttributes(model, options.nestedAttributes, options.controller || null, permit)
339
+ }
340
+ })
341
+
342
+ await this._preloadNestedWritableRelationships(model, permit)
343
+
344
+ return model
345
+ }
346
+
347
+ /**
348
+ * Runs handle unauthorized created model.
349
+ * @param {import("../database/record/index.js").default} model - Created model.
350
+ * @returns {Promise<void>} - Cleanup after failed authorization.
351
+ */
352
+ async handleUnauthorizedCreatedModel(model) {
353
+ await model.destroy()
354
+ }
355
+
356
+ /**
357
+ * Runs update.
358
+ * @param {import("../database/record/index.js").default} model - Existing model.
359
+ * @param {Record<string, ?>} attributes - Update attributes.
360
+ * @param {{controller?: ?, nestedAttributes?: Record<string, ?> | null}} [options] - Save options.
361
+ * @returns {Promise<import("../database/record/index.js").default>} - Updated model.
362
+ */
363
+ async update(model, attributes, options = {}) {
364
+ const permit = parsePermittedParams(this.permittedParams({action: "update", ability: this.ability, locals: this.locals, params: attributes}))
365
+ const filtered = filterWritableFrontendModelAttributes(model, attributes, this, permit.attributes)
366
+ const ModelClass = this.modelClass()
367
+
368
+ await ModelClass.transaction(async () => {
369
+ await this._assignWithVirtualSetters(model, filtered)
370
+ await model.save()
371
+
372
+ if (options.nestedAttributes) {
373
+ await this._applyNestedAttributes(model, options.nestedAttributes, options.controller || null, permit)
374
+ }
375
+ })
376
+
377
+ await this._preloadNestedWritableRelationships(model, permit)
378
+
379
+ return model
380
+ }
381
+
382
+ /**
383
+ * Assigns attributes to a model, using virtual setters on the resource when available.
384
+ * @param {import("../database/record/index.js").default} model - Model instance.
385
+ * @param {Record<string, ?>} attributes - Attributes to assign.
386
+ * @returns {Promise<void>}
387
+ */
388
+ async _assignWithVirtualSetters(model, attributes) {
389
+ /**
390
+ * Direct attributes.
391
+ @type {Record<string, ?>} */
392
+ const directAttributes = {}
393
+ const translatedSet = new Set(/**
394
+ * Narrows the runtime value to the documented type.
395
+ @type {typeof FrontendModelBaseResource} */ (this.constructor).translatedAttributes || [])
396
+
397
+ for (const [name, value] of Object.entries(attributes)) {
398
+ const resourceSetterName = `set${inflection.camelize(name)}Attribute`
399
+
400
+ if (typeof /**
401
+ * Narrows the runtime value to the documented type.
402
+ @type {Record<string, ?>} */ (/**
403
+ * Narrows the runtime value to the documented type.
404
+ @type {?} */ (this))[resourceSetterName] === "function") {
405
+ await /**
406
+ * Narrows the runtime value to the documented type.
407
+ @type {Record<string, ?>} */ (/**
408
+ * Narrows the runtime value to the documented type.
409
+ @type {?} */ (this))[resourceSetterName](model, value)
410
+ } else if (translatedSet.has(name)) {
411
+ await this._setTranslatedAttributeOnModel(model, name, value)
412
+ } else {
413
+ directAttributes[name] = value
414
+ }
415
+ }
416
+
417
+ if (Object.keys(directAttributes).length > 0) {
418
+ model.assign(directAttributes)
419
+ }
420
+ }
421
+
422
+ /**
423
+ * Sets a translated attribute on a model via the translations relationship.
424
+ * @param {import("../database/record/index.js").default} model - Model instance.
425
+ * @param {string} name - Attribute name.
426
+ * @param {?} value - Attribute value.
427
+ * @returns {Promise<void>}
428
+ */
429
+ async _setTranslatedAttributeOnModel(model, name, value) {
430
+ const locale = this.context?.configuration?.getLocale?.() || "en"
431
+ const instanceRelationship = model.getRelationshipByName("translations")
432
+
433
+ /**
434
+ * Defines translation.
435
+ @type {import("../database/record/index.js").default | undefined} */
436
+ let translation
437
+
438
+ if (model.isNewRecord()) {
439
+ const loaded = instanceRelationship.loaded()
440
+
441
+ if (Array.isArray(loaded)) {
442
+ translation = loaded.find((/**
443
+ * Narrows the runtime value to the documented type.
444
+ @type {Record<string, ?>} */ t) => t.locale() === locale)
445
+ }
446
+ } else {
447
+ if (!instanceRelationship.getPreloaded()) {
448
+ await model.loadRelationship("translations")
449
+ }
450
+
451
+ const loaded = instanceRelationship.loaded()
452
+
453
+ if (Array.isArray(loaded)) {
454
+ translation = loaded.find((/**
455
+ * Narrows the runtime value to the documented type.
456
+ @type {Record<string, ?>} */ t) => t.locale() === locale)
457
+ }
458
+ }
459
+
460
+ if (!translation) {
461
+ translation = instanceRelationship.build({locale})
462
+ }
463
+
464
+ /**
465
+ * Assignments.
466
+ @type {Record<string, ?>} */
467
+ const assignments = {}
468
+
469
+ assignments[name] = value
470
+ translation.assign(assignments)
471
+ }
472
+
473
+ /**
474
+ * Runs destroy.
475
+ * @param {import("../database/record/index.js").default} model - Existing model.
476
+ * @returns {Promise<void>} - No return value.
477
+ */
478
+ async destroy(model) {
479
+ await model.destroy()
480
+ }
481
+
482
+ /**
483
+ * Runs serialize.
484
+ * @param {import("../database/record/index.js").default} model - Model to serialize.
485
+ * @param {"index" | "find" | "create" | "update"} [action] - Action.
486
+ * @returns {Promise<Record<string, ?>>} - Serialized model payload.
487
+ */
488
+ async serialize(model, action) {
489
+ void action
490
+
491
+ return await this.typedControllerInstance().serializeFrontendModel(model)
492
+ }
493
+
494
+ /**
495
+ * Applies a `nestedAttributes` payload to a freshly-saved parent model,
496
+ * cascading create/update/destroy writes across the declared relationships.
497
+ *
498
+ * Each child is authorized against its own resource's abilities (never the
499
+ * parent's). Destroys run before updates, updates before creates, to avoid
500
+ * unique-constraint conflicts when replacing a child at the same natural key.
501
+ *
502
+ * Attribute filtering for nested children uses the parent resource's
503
+ * permit spec for that relationship — api_maker-style. Policy options
504
+ * (allowDestroy, limit, rejectIf) come from the MODEL's
505
+ * `acceptedNestedAttributesFor(name)` declaration.
506
+ * @param {import("../database/record/index.js").default} parent - Parent model instance.
507
+ * @param {Record<string, ?>} nestedAttributes - Nested-attribute payload keyed by relationship name.
508
+ * @param {?} controller - Controller instance for resource resolution and authorization.
509
+ * @param {{attributes: string[], nested: Record<string, ?>} | null} [parentPermit] - Parsed parent permit spec.
510
+ * @returns {Promise<void>}
511
+ */
512
+ async _applyNestedAttributes(parent, nestedAttributes, controller, parentPermit = null) {
513
+ const resolvedParent = parentPermit
514
+ || parsePermittedParams(this.permittedParams({action: "update", ability: this.ability, locals: this.locals, params: {}}))
515
+
516
+ for (const relationshipName of Object.keys(nestedAttributes)) {
517
+ const childPermit = resolvedParent.nested[relationshipName]
518
+
519
+ if (!childPermit) {
520
+ throw new Error(`Nested attributes for '${relationshipName}' are not permitted by ${this.constructor.name}.permittedParams(). Include {${relationshipName}Attributes: [...]} in the returned permit.`)
521
+ }
522
+
523
+ const entries = nestedAttributes[relationshipName]
524
+
525
+ if (!Array.isArray(entries)) {
526
+ throw new Error(`Expected array for nestedAttributes['${relationshipName}'] but got: ${typeof entries}`)
527
+ }
528
+
529
+ const parentModelClass = /**
530
+ * Narrows the runtime value to the documented type.
531
+ @type {?} */ (parent.getModelClass())
532
+ const modelAcceptance = parentModelClass.acceptedNestedAttributesFor?.(relationshipName)
533
+
534
+ if (!modelAcceptance) {
535
+ throw new Error(`Model ${parentModelClass.name} does not accept nested attributes for '${relationshipName}'. Declare it via ${parentModelClass.name}.acceptsNestedAttributesFor('${relationshipName}').`)
536
+ }
537
+
538
+ const destroyPermitted = childPermit.attributes.includes("_destroy")
539
+
540
+ if (destroyPermitted && !modelAcceptance.allowDestroy) {
541
+ throw new Error(`Resource permits _destroy on nestedAttributes['${relationshipName}'] but the model ${parentModelClass.name} does not allow destroy for that relationship. Set {allowDestroy: true} on ${parentModelClass.name}.acceptsNestedAttributesFor('${relationshipName}', ...).`)
542
+ }
543
+
544
+ if (typeof modelAcceptance.limit === "number" && entries.length > modelAcceptance.limit) {
545
+ throw new Error(`nestedAttributes['${relationshipName}'] exceeds model-declared limit of ${modelAcceptance.limit}.`)
546
+ }
547
+
548
+ const parentRelationship = parent.getRelationshipByName(relationshipName)
549
+ const relationshipDefinitions = parentModelClass.relationships?.() || {}
550
+ const definition = relationshipDefinitions[relationshipName]
551
+
552
+ if (!definition || definition.type !== "hasMany") {
553
+ throw new Error(`Nested attributes for '${relationshipName}' require a hasMany relationship. v1 does not support '${definition?.type}'.`)
554
+ }
555
+
556
+ const targetModelClass = /**
557
+ * Narrows the runtime value to the documented type.
558
+ @type {?} */ (parent.getModelClass()).relationshipModelClass?.(relationshipName)
559
+
560
+ if (!targetModelClass) {
561
+ throw new Error(`No target model class resolved for relationship '${relationshipName}' on ${parent.getModelClass().name}.`)
562
+ }
563
+
564
+ const childResourceConfig = controller?.frontendModelResourceConfigurationForModelClass?.(targetModelClass)
565
+
566
+ if (!childResourceConfig) {
567
+ throw new Error(`No frontend-model resource registered for child model '${targetModelClass.getModelName?.() || targetModelClass.name}' under relationship '${relationshipName}'.`)
568
+ }
569
+
570
+ const childResource = new childResourceConfig.resourceClass({
571
+ ability: this.ability,
572
+ controller,
573
+ context: this.context || {},
574
+ locals: this.locals || {},
575
+ modelClass: targetModelClass,
576
+ modelName: childResourceConfig.modelName,
577
+ params: controller?.frontendModelParams?.() || {},
578
+ resourceConfiguration: childResourceConfig.resourceConfiguration
579
+ })
580
+
581
+ const foreignKey = definition.foreignKey || this._inferForeignKey(parent, definition)
582
+ const ability = controller?.currentAbility?.()
583
+
584
+ const destroyEntries = []
585
+ const updateEntries = []
586
+ const createEntries = []
587
+
588
+ for (const entry of entries) {
589
+ if (typeof modelAcceptance.rejectIf === "function" && modelAcceptance.rejectIf(entry?.attributes || {})) continue
590
+
591
+ if (entry?._destroy) {
592
+ if (!destroyPermitted) {
593
+ throw new Error(`nestedAttributes['${relationshipName}'] entry requested _destroy but "_destroy" is not in the permit for this relationship.`)
594
+ }
595
+ if (!entry.id) {
596
+ throw new Error(`nestedAttributes['${relationshipName}'] _destroy entry is missing an id.`)
597
+ }
598
+ destroyEntries.push(entry)
599
+ } else if (entry?.id) {
600
+ updateEntries.push(entry)
601
+ } else {
602
+ createEntries.push(entry)
603
+ }
604
+ }
605
+
606
+ // The permit's attribute list governs what child fields can be written.
607
+ // Exclude `_destroy` from the writable set since it's a control flag,
608
+ // not an attribute on the record.
609
+ const childWritableAttributes = /**
610
+ * Narrows the runtime value to the documented type.
611
+ @type {string[]} */ (childPermit.attributes).filter((name) => name !== "_destroy")
612
+
613
+ for (const entry of destroyEntries) {
614
+ const existing = await this._findScopedChild({
615
+ ability,
616
+ action: "destroy",
617
+ childResourceConfiguration: childResourceConfig.resourceConfiguration,
618
+ foreignKey,
619
+ id: entry.id,
620
+ parent,
621
+ relationshipName,
622
+ targetModelClass
623
+ })
624
+
625
+ await childResource.destroy(existing)
626
+ }
627
+
628
+ for (const entry of updateEntries) {
629
+ const existing = await this._findScopedChild({
630
+ ability,
631
+ action: "update",
632
+ childResourceConfiguration: childResourceConfig.resourceConfiguration,
633
+ foreignKey,
634
+ id: entry.id,
635
+ parent,
636
+ relationshipName,
637
+ targetModelClass
638
+ })
639
+
640
+ if (entry.attributes && typeof entry.attributes === "object") {
641
+ const filtered = filterWritableFrontendModelAttributes(existing, entry.attributes, childResource, childWritableAttributes)
642
+ await /**
643
+ * Narrows the runtime value to the documented type.
644
+ @type {?} */ (childResource)._assignWithVirtualSetters(existing, filtered)
645
+ await existing.save()
646
+ }
647
+
648
+ if (entry.nestedAttributes) {
649
+ await /**
650
+ * Narrows the runtime value to the documented type.
651
+ @type {?} */ (childResource)._applyNestedAttributes(existing, entry.nestedAttributes, controller, childPermit)
652
+ }
653
+ }
654
+
655
+ for (const entry of createEntries) {
656
+ const childAttributes = entry?.attributes && typeof entry.attributes === "object" ? entry.attributes : {}
657
+
658
+ const child = parentRelationship.build({...childAttributes, [foreignKey]: parent.id()})
659
+
660
+ const filtered = filterWritableFrontendModelAttributes(child, childAttributes, childResource, childWritableAttributes)
661
+
662
+ await /**
663
+ * Narrows the runtime value to the documented type.
664
+ @type {?} */ (childResource)._assignWithVirtualSetters(child, filtered)
665
+ await child.save()
666
+
667
+ await this._authorizeCreatedChild({
668
+ ability,
669
+ child,
670
+ childResourceConfiguration: childResourceConfig.resourceConfiguration,
671
+ relationshipName,
672
+ targetModelClass
673
+ })
674
+
675
+ if (entry.nestedAttributes) {
676
+ await /**
677
+ * Narrows the runtime value to the documented type.
678
+ @type {?} */ (childResource)._applyNestedAttributes(child, entry.nestedAttributes, controller, childPermit)
679
+ }
680
+ }
681
+ }
682
+ }
683
+
684
+ /**
685
+ * Resolves the ability action for a child resource using the child's own
686
+ * `abilities` mapping — never the parent controller's. This preserves
687
+ * custom mappings like `{update: "manage"}` and catches unmapped actions
688
+ * instead of silently defaulting to the raw action name.
689
+ * @param {import("../configuration-types.js").FrontendModelResourceConfiguration} childResourceConfiguration - Child resource configuration.
690
+ * @param {"create" | "update" | "destroy"} action - Frontend action.
691
+ * @returns {string} - Ability action for the child resource.
692
+ */
693
+ _resolveChildAbilityAction(childResourceConfiguration, action) {
694
+ const abilities = childResourceConfiguration?.abilities
695
+
696
+ if (!abilities || typeof abilities !== "object" || Array.isArray(abilities)) {
697
+ throw new Error(`Nested child resource must define an 'abilities' object to authorize nested ${action}.`)
698
+ }
699
+
700
+ const abilityAction = /**
701
+ * Narrows the runtime value to the documented type.
702
+ @type {Record<string, string>} */ (abilities)[action]
703
+
704
+ if (typeof abilityAction !== "string" || abilityAction.length < 1) {
705
+ throw new Error(`Nested child resource must define abilities.${action}.`)
706
+ }
707
+
708
+ return abilityAction
709
+ }
710
+
711
+ /**
712
+ * Finds an existing child for a nested update/destroy, scoped to the
713
+ * child's own model class, the parent's foreign key, AND the child
714
+ * resource's ability mapping for the requested action. Throws when the
715
+ * child does not exist, does not belong to the current parent, or is
716
+ * not authorized — all of which must roll the transaction back.
717
+ * @param {object} args - Arguments.
718
+ * @param {import("../authorization/ability.js").default | undefined} args.ability - Current ability.
719
+ * @param {"update" | "destroy"} args.action - Frontend action.
720
+ * @param {import("../configuration-types.js").FrontendModelResourceConfiguration} args.childResourceConfiguration - Child resource configuration.
721
+ * @param {string} args.foreignKey - Foreign-key attribute on the child pointing to the parent.
722
+ * @param {string | number} args.id - Child id from the payload.
723
+ * @param {import("../database/record/index.js").default} args.parent - Parent model instance.
724
+ * @param {string} args.relationshipName - Parent's relationship name (for error messages).
725
+ * @param {typeof import("../database/record/index.js").default} args.targetModelClass - Child model class.
726
+ * @returns {Promise<import("../database/record/index.js").default>} - Authorized, parent-linked child model.
727
+ */
728
+ async _findScopedChild({ability, action, childResourceConfiguration, foreignKey, id, parent, relationshipName, targetModelClass}) {
729
+ const primaryKey = targetModelClass.primaryKey()
730
+ const lookup = {[primaryKey]: id, [foreignKey]: parent.id()}
731
+ const query = ability
732
+ ? /**
733
+ * Narrows the runtime value to the documented type.
734
+ @type {?} */ (targetModelClass).accessibleFor(this._resolveChildAbilityAction(childResourceConfiguration, action), ability)
735
+ : /**
736
+ * Narrows the runtime value to the documented type.
737
+ @type {?} */ (targetModelClass).where({})
738
+
739
+ const existing = await query.findBy(lookup)
740
+
741
+ if (!existing) {
742
+ throw new Error(`Cannot ${action} nested ${relationshipName}[id=${id}]: record not found, does not belong to parent ${parent.getModelClass().name}[id=${parent.id()}], or is not authorized.`)
743
+ }
744
+
745
+ return existing
746
+ }
747
+
748
+ /**
749
+ * Verifies an already-saved nested child is authorized under the child
750
+ * resource's own `create` ability. Rolls back via thrown error when not
751
+ * authorized so the outer transaction destroys the insert.
752
+ * @param {object} args - Arguments.
753
+ * @param {import("../authorization/ability.js").default | undefined} args.ability - Current ability.
754
+ * @param {import("../database/record/index.js").default} args.child - Child model instance just created.
755
+ * @param {import("../configuration-types.js").FrontendModelResourceConfiguration} args.childResourceConfiguration - Child resource configuration.
756
+ * @param {string} args.relationshipName - Parent's relationship name (for error messages).
757
+ * @param {typeof import("../database/record/index.js").default} args.targetModelClass - Child model class.
758
+ * @returns {Promise<void>}
759
+ */
760
+ async _authorizeCreatedChild({ability, child, childResourceConfiguration, relationshipName, targetModelClass}) {
761
+ if (!ability) return
762
+
763
+ const abilityAction = this._resolveChildAbilityAction(childResourceConfiguration, "create")
764
+ const primaryKey = targetModelClass.primaryKey()
765
+ const authorizedIds = await /**
766
+ * Narrows the runtime value to the documented type.
767
+ @type {?} */ (targetModelClass)
768
+ .accessibleFor(abilityAction, ability)
769
+ .where({[primaryKey]: child.readAttribute(primaryKey)})
770
+ .pluck(primaryKey)
771
+
772
+ if (authorizedIds.length === 0) {
773
+ throw new Error(`Nested create on ${relationshipName}[${targetModelClass.name}] not authorized.`)
774
+ }
775
+ }
776
+
777
+ /**
778
+ * Best-effort foreign-key inference for relationships that don't declare it.
779
+ * @param {import("../database/record/index.js").default} parent - Parent model.
780
+ * @param {{foreignKey?: string}} definition - Relationship definition.
781
+ * @returns {string} - Foreign-key attribute name.
782
+ */
783
+ _inferForeignKey(parent, definition) {
784
+ if (definition.foreignKey) return definition.foreignKey
785
+
786
+ const parentModelName = parent.getModelClass().name || ""
787
+ const underscored = parentModelName.replace(/([A-Z])/g, (match, letter, index) => (index === 0 ? letter.toLowerCase() : `_${letter.toLowerCase()}`))
788
+
789
+ return `${inflection.camelize(underscored, true)}Id`
790
+ }
791
+
792
+ /**
793
+ * After nested writes, preload every relationship declared in the
794
+ * parent's permit so the post-save serialize step emits them and the
795
+ * client can reconcile ids.
796
+ * @param {import("../database/record/index.js").default} model - Saved parent model.
797
+ * @param {{attributes: string[], nested: Record<string, ?>}} permit - Parsed parent permit.
798
+ * @returns {Promise<void>}
799
+ */
800
+ async _preloadNestedWritableRelationships(model, permit) {
801
+ const relationshipNames = Object.keys(permit.nested)
802
+
803
+ if (relationshipNames.length === 0) return
804
+
805
+ for (const relationshipName of relationshipNames) {
806
+ if (typeof /**
807
+ * Narrows the runtime value to the documented type.
808
+ @type {?} */ (model).loadRelationship === "function") {
809
+ await /**
810
+ * Narrows the runtime value to the documented type.
811
+ @type {?} */ (model).loadRelationship(relationshipName)
812
+ }
813
+ }
814
+ }
815
+ }
816
+
817
+ /**
818
+ * Parses the Rails/api_maker-style flat permit spec returned from
819
+ * `permittedParams(arg)` into a structured shape used internally by the
820
+ * write pipeline. Strings become attribute permits; objects whose keys
821
+ * end in `Attributes` become nested permits (the key prefix names the
822
+ * relationship).
823
+ *
824
+ * parsePermittedParams(["firstName", "lastName",
825
+ * {tasksAttributes: ["id", "_destroy", "name"]}
826
+ * ])
827
+ * // → {
828
+ * // attributes: ["firstName", "lastName"],
829
+ * // nested: {
830
+ * // tasks: {attributes: ["id", "_destroy", "name"], nested: {}}
831
+ * // }
832
+ * // }
833
+ * @param {Array<string | Record<string, ?>> | undefined} permitSpec - Flat permit spec.
834
+ * @returns {{attributes: string[], nested: Record<string, {attributes: string[], nested: Record<string, ?>}>}} - Parsed structure.
835
+ */
836
+ function parsePermittedParams(permitSpec) {
837
+ /**
838
+ * Attributes.
839
+ @type {string[]} */
840
+ const attributes = []
841
+ /**
842
+ * Nested.
843
+ @type {Record<string, {attributes: string[], nested: Record<string, ?>}>} */
844
+ const nested = {}
845
+
846
+ if (!Array.isArray(permitSpec)) return {attributes, nested}
847
+
848
+ for (const entry of permitSpec) {
849
+ if (typeof entry === "string") {
850
+ attributes.push(entry)
851
+ } else if (entry && typeof entry === "object" && !Array.isArray(entry)) {
852
+ for (const [key, value] of Object.entries(entry)) {
853
+ if (!key.endsWith("Attributes")) {
854
+ throw new Error(`Invalid permittedParams entry: nested relationship keys must end in "Attributes" (got "${key}"). Use "${key}Attributes" instead.`)
855
+ }
856
+ const relationshipName = key.slice(0, -"Attributes".length)
857
+
858
+ if (!relationshipName) {
859
+ throw new Error(`Invalid permittedParams entry: empty relationship name in key "${key}".`)
860
+ }
861
+ if (!Array.isArray(value)) {
862
+ throw new Error(`Invalid permittedParams entry for "${key}": expected array permit spec, got ${typeof value}.`)
863
+ }
864
+
865
+ nested[relationshipName] = parsePermittedParams(value)
866
+ }
867
+ } else {
868
+ throw new Error(`Invalid permittedParams entry: expected string or nested-attributes object, got ${typeof entry}.`)
869
+ }
870
+ }
871
+
872
+ return {attributes, nested}
873
+ }
874
+
875
+ /**
876
+ * Runs filter writable frontend model attributes.
877
+ * @param {Record<string, ?>} receiver - Model instance or prototype.
878
+ * @param {Record<string, ?>} attributes - Incoming frontend-model attributes.
879
+ * @param {FrontendModelBaseResource | null} [resource] - Resource instance for virtual-setter detection.
880
+ * @param {string[] | null} [permittedAttributeNames] - Optional explicit permit list. `null` falls back to setter-existence checks only.
881
+ * @returns {Record<string, ?>} - Writable attributes only.
882
+ */
883
+ function filterWritableFrontendModelAttributes(receiver, attributes, resource = /**
884
+ * Narrows the runtime value to the documented type.
885
+ @type {FrontendModelBaseResource | null} */ (null), permittedAttributeNames = null) {
886
+ // Frontend-model writes should fail fast when callers submit read-only or unknown attrs.
887
+ // Silent drops hide contract mistakes in generated models and app-side wrapper code.
888
+ /**
889
+ * Writable attributes.
890
+ @type {Record<string, ?>} */
891
+ const writableAttributes = {}
892
+ /**
893
+ * Invalid attributes.
894
+ @type {string[]} */
895
+ const invalidAttributes = []
896
+ /**
897
+ * Not permitted attributes.
898
+ @type {string[]} */
899
+ const notPermittedAttributes = []
900
+
901
+ const permitSet = Array.isArray(permittedAttributeNames) ? new Set(permittedAttributeNames) : null
902
+ const translatedSet = resource ? new Set(/**
903
+ * Narrows the runtime value to the documented type.
904
+ @type {typeof FrontendModelBaseResource} */ (resource.constructor).translatedAttributes || []) : new Set()
905
+
906
+ for (const [attributeName, value] of Object.entries(attributes)) {
907
+ if (permitSet && !permitSet.has(attributeName)) {
908
+ notPermittedAttributes.push(attributeName)
909
+ continue
910
+ }
911
+
912
+ const setterName = `set${inflection.camelize(attributeName)}`
913
+ const resourceSetterName = `${setterName}Attribute`
914
+
915
+ if (setterName in receiver) {
916
+ writableAttributes[attributeName] = value
917
+ } else if (resource && typeof /**
918
+ * Narrows the runtime value to the documented type.
919
+ @type {Record<string, ?>} */ (/**
920
+ * Narrows the runtime value to the documented type.
921
+ @type {?} */ (resource))[resourceSetterName] === "function") {
922
+ writableAttributes[attributeName] = value
923
+ } else if (translatedSet.has(attributeName)) {
924
+ writableAttributes[attributeName] = value
925
+ } else {
926
+ invalidAttributes.push(attributeName)
927
+ }
928
+ }
929
+
930
+ if (notPermittedAttributes.length > 0) {
931
+ throw new Error(`Frontend model write attributes not permitted by permittedParams(): ${notPermittedAttributes.join(", ")}`)
932
+ }
933
+
934
+ if (invalidAttributes.length > 0) {
935
+ throw new Error(`Invalid frontend model write attributes: ${invalidAttributes.join(", ")}`)
936
+ }
937
+
938
+ return writableAttributes
939
+ }