velocious 1.0.643 → 1.0.645

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 (279) hide show
  1. package/README.md +21 -10
  2. package/build/authorization/ability.js +36 -13
  3. package/build/background-jobs/adapter.js +9 -0
  4. package/build/background-jobs/main.js +35 -10
  5. package/build/background-jobs/store.js +217 -38
  6. package/build/background-jobs/types.js +15 -0
  7. package/build/configuration-types.js +1 -1
  8. package/build/configuration.js +45 -9
  9. package/build/database/drivers/base-column.js +8 -0
  10. package/build/database/drivers/mssql/sql/update.js +1 -3
  11. package/build/database/drivers/mysql/sql/update.js +1 -3
  12. package/build/database/drivers/pgsql/column.js +22 -0
  13. package/build/database/drivers/pgsql/sql/update.js +1 -3
  14. package/build/database/drivers/sqlite/sql/alter-table.js +11 -1
  15. package/build/database/drivers/sqlite/sql/update.js +1 -3
  16. package/build/database/query/index.js +2 -2
  17. package/build/database/query/model-class-query.js +26 -10
  18. package/build/database/query/preloader/has-many.js +4 -1
  19. package/build/database/query/query-data.js +2 -1
  20. package/build/database/query/update-base.js +14 -0
  21. package/build/database/query/with-count.js +3 -1
  22. package/build/database/record/acts-as-list.js +37 -13
  23. package/build/database/record/attachments/store.js +336 -26
  24. package/build/database/record/auditing.js +6 -3
  25. package/build/database/record/index.js +197 -42
  26. package/build/database/record/instance-relationships/belongs-to.js +2 -1
  27. package/build/database/record/validators/uniqueness.js +8 -5
  28. package/build/environment-handlers/node/cli/commands/generate/frontend-models.js +24 -8
  29. package/build/frontend-model-controller.js +136 -53
  30. package/build/frontend-model-resource/base-resource.js +87 -37
  31. package/build/frontend-model-resource/velocious-attachment-resource.js +98 -31
  32. package/build/frontend-models/base.js +307 -59
  33. package/build/frontend-models/preloader.js +6 -3
  34. package/build/frontend-models/query.js +15 -6
  35. package/build/frontend-models/resource-definition.js +21 -2
  36. package/build/frontend-models/use-destroyed-event.js +1 -1
  37. package/build/frontend-models/use-model-class-event.js +2 -2
  38. package/build/frontend-models/use-updated-event.js +1 -1
  39. package/build/frontend-models/websocket-channel.js +256 -93
  40. package/build/frontend-models/websocket-publishers.js +218 -18
  41. package/build/http-server/client/websocket-session.js +13 -1
  42. package/build/http-server/websocket-channel.js +15 -2
  43. package/build/src/authorization/ability.d.ts +9 -3
  44. package/build/src/authorization/ability.d.ts.map +1 -1
  45. package/build/src/authorization/ability.js +33 -14
  46. package/build/src/background-jobs/adapter.d.ts +6 -0
  47. package/build/src/background-jobs/adapter.d.ts.map +1 -1
  48. package/build/src/background-jobs/adapter.js +9 -1
  49. package/build/src/background-jobs/main.d.ts +6 -0
  50. package/build/src/background-jobs/main.d.ts.map +1 -1
  51. package/build/src/background-jobs/main.js +34 -11
  52. package/build/src/background-jobs/store.d.ts +66 -12
  53. package/build/src/background-jobs/store.d.ts.map +1 -1
  54. package/build/src/background-jobs/store.js +191 -35
  55. package/build/src/background-jobs/types.d.ts +55 -0
  56. package/build/src/background-jobs/types.d.ts.map +1 -1
  57. package/build/src/background-jobs/types.js +16 -1
  58. package/build/src/configuration-types.d.ts +3 -3
  59. package/build/src/configuration-types.d.ts.map +1 -1
  60. package/build/src/configuration-types.js +2 -2
  61. package/build/src/configuration.d.ts +18 -8
  62. package/build/src/configuration.d.ts.map +1 -1
  63. package/build/src/configuration.js +38 -7
  64. package/build/src/database/drivers/base-column.d.ts +5 -0
  65. package/build/src/database/drivers/base-column.d.ts.map +1 -1
  66. package/build/src/database/drivers/base-column.js +8 -1
  67. package/build/src/database/drivers/mssql/sql/update.d.ts.map +1 -1
  68. package/build/src/database/drivers/mssql/sql/update.js +2 -4
  69. package/build/src/database/drivers/mysql/sql/update.d.ts.map +1 -1
  70. package/build/src/database/drivers/mysql/sql/update.js +2 -4
  71. package/build/src/database/drivers/pgsql/column.d.ts +5 -0
  72. package/build/src/database/drivers/pgsql/column.d.ts.map +1 -1
  73. package/build/src/database/drivers/pgsql/column.js +19 -1
  74. package/build/src/database/drivers/pgsql/sql/update.d.ts.map +1 -1
  75. package/build/src/database/drivers/pgsql/sql/update.js +2 -4
  76. package/build/src/database/drivers/sqlite/sql/alter-table.d.ts.map +1 -1
  77. package/build/src/database/drivers/sqlite/sql/alter-table.js +6 -2
  78. package/build/src/database/drivers/sqlite/sql/update.d.ts.map +1 -1
  79. package/build/src/database/drivers/sqlite/sql/update.js +2 -4
  80. package/build/src/database/query/index.d.ts +4 -4
  81. package/build/src/database/query/index.d.ts.map +1 -1
  82. package/build/src/database/query/index.js +3 -3
  83. package/build/src/database/query/model-class-query.d.ts +8 -2
  84. package/build/src/database/query/model-class-query.d.ts.map +1 -1
  85. package/build/src/database/query/model-class-query.js +25 -11
  86. package/build/src/database/query/preloader/has-many.d.ts.map +1 -1
  87. package/build/src/database/query/preloader/has-many.js +4 -2
  88. package/build/src/database/query/query-data.d.ts.map +1 -1
  89. package/build/src/database/query/query-data.js +3 -2
  90. package/build/src/database/query/update-base.d.ts +7 -0
  91. package/build/src/database/query/update-base.d.ts.map +1 -1
  92. package/build/src/database/query/update-base.js +13 -1
  93. package/build/src/database/query/with-count.d.ts.map +1 -1
  94. package/build/src/database/query/with-count.js +3 -2
  95. package/build/src/database/record/acts-as-list.d.ts.map +1 -1
  96. package/build/src/database/record/acts-as-list.js +35 -14
  97. package/build/src/database/record/attachments/store.d.ts +67 -0
  98. package/build/src/database/record/attachments/store.d.ts.map +1 -1
  99. package/build/src/database/record/attachments/store.js +301 -25
  100. package/build/src/database/record/auditing.d.ts.map +1 -1
  101. package/build/src/database/record/auditing.js +7 -4
  102. package/build/src/database/record/index.d.ts +78 -26
  103. package/build/src/database/record/index.d.ts.map +1 -1
  104. package/build/src/database/record/index.js +171 -42
  105. package/build/src/database/record/instance-relationships/belongs-to.d.ts.map +1 -1
  106. package/build/src/database/record/instance-relationships/belongs-to.js +3 -2
  107. package/build/src/database/record/validators/uniqueness.d.ts.map +1 -1
  108. package/build/src/database/record/validators/uniqueness.js +8 -6
  109. package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.d.ts +4 -4
  110. package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.d.ts.map +1 -1
  111. package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.js +24 -12
  112. package/build/src/frontend-model-controller.d.ts +29 -8
  113. package/build/src/frontend-model-controller.d.ts.map +1 -1
  114. package/build/src/frontend-model-controller.js +122 -51
  115. package/build/src/frontend-model-resource/base-resource.d.ts +51 -24
  116. package/build/src/frontend-model-resource/base-resource.d.ts.map +1 -1
  117. package/build/src/frontend-model-resource/base-resource.js +83 -37
  118. package/build/src/frontend-model-resource/velocious-attachment-resource.d.ts +45 -26
  119. package/build/src/frontend-model-resource/velocious-attachment-resource.d.ts.map +1 -1
  120. package/build/src/frontend-model-resource/velocious-attachment-resource.js +89 -31
  121. package/build/src/frontend-models/base.d.ts +53 -20
  122. package/build/src/frontend-models/base.d.ts.map +1 -1
  123. package/build/src/frontend-models/base.js +275 -59
  124. package/build/src/frontend-models/preloader.d.ts.map +1 -1
  125. package/build/src/frontend-models/preloader.js +6 -4
  126. package/build/src/frontend-models/query.d.ts +2 -2
  127. package/build/src/frontend-models/query.d.ts.map +1 -1
  128. package/build/src/frontend-models/query.js +14 -7
  129. package/build/src/frontend-models/resource-definition.d.ts.map +1 -1
  130. package/build/src/frontend-models/resource-definition.js +20 -3
  131. package/build/src/frontend-models/use-destroyed-event.d.ts +1 -1
  132. package/build/src/frontend-models/use-destroyed-event.d.ts.map +1 -1
  133. package/build/src/frontend-models/use-destroyed-event.js +2 -2
  134. package/build/src/frontend-models/use-model-class-event.d.ts +2 -2
  135. package/build/src/frontend-models/use-model-class-event.d.ts.map +1 -1
  136. package/build/src/frontend-models/use-model-class-event.js +3 -3
  137. package/build/src/frontend-models/use-updated-event.d.ts +1 -1
  138. package/build/src/frontend-models/use-updated-event.d.ts.map +1 -1
  139. package/build/src/frontend-models/use-updated-event.js +2 -2
  140. package/build/src/frontend-models/websocket-channel.d.ts +60 -41
  141. package/build/src/frontend-models/websocket-channel.d.ts.map +1 -1
  142. package/build/src/frontend-models/websocket-channel.js +225 -85
  143. package/build/src/frontend-models/websocket-publishers.d.ts +9 -0
  144. package/build/src/frontend-models/websocket-publishers.d.ts.map +1 -1
  145. package/build/src/frontend-models/websocket-publishers.js +190 -19
  146. package/build/src/http-server/client/websocket-session.d.ts.map +1 -1
  147. package/build/src/http-server/client/websocket-session.js +11 -2
  148. package/build/src/http-server/websocket-channel.d.ts +20 -8
  149. package/build/src/http-server/websocket-channel.d.ts.map +1 -1
  150. package/build/src/http-server/websocket-channel.js +15 -3
  151. package/build/src/sync/assets/cache.d.ts +288 -0
  152. package/build/src/sync/assets/cache.d.ts.map +1 -0
  153. package/build/src/sync/assets/cache.js +883 -0
  154. package/build/src/sync/assets/types.d.ts +199 -0
  155. package/build/src/sync/assets/types.d.ts.map +1 -0
  156. package/build/src/sync/assets/types.js +56 -0
  157. package/build/src/sync/sync-api-client.d.ts.map +1 -1
  158. package/build/src/sync/sync-api-client.js +4 -3
  159. package/build/src/sync/sync-client.d.ts.map +1 -1
  160. package/build/src/sync/sync-client.js +3 -2
  161. package/build/src/sync/sync-envelope-replay-service.d.ts.map +1 -1
  162. package/build/src/sync/sync-envelope-replay-service.js +6 -5
  163. package/build/src/sync/sync-publisher.d.ts.map +1 -1
  164. package/build/src/sync/sync-publisher.js +4 -3
  165. package/build/src/testing/browser-frontend-model-event-hook-scenarios.d.ts +2 -2
  166. package/build/src/testing/browser-frontend-model-event-hook-scenarios.d.ts.map +1 -1
  167. package/build/src/testing/browser-frontend-model-event-hook-scenarios.js +3 -3
  168. package/build/src/testing/test-profiler.d.ts +4 -4
  169. package/build/src/testing/test-profiler.d.ts.map +1 -1
  170. package/build/src/testing/test-profiler.js +3 -3
  171. package/build/src/testing/test-runner.d.ts +279 -117
  172. package/build/src/testing/test-runner.d.ts.map +1 -1
  173. package/build/src/testing/test-runner.js +503 -933
  174. package/build/src/testing/test.d.ts +11 -72
  175. package/build/src/testing/test.d.ts.map +1 -1
  176. package/build/src/testing/test.js +131 -284
  177. package/build/src/testing/velocious-attempt-executor.d.ts +54 -0
  178. package/build/src/testing/velocious-attempt-executor.d.ts.map +1 -0
  179. package/build/src/testing/velocious-attempt-executor.js +408 -0
  180. package/build/src/testing/velocious-runner-reporter.d.ts +67 -0
  181. package/build/src/testing/velocious-runner-reporter.d.ts.map +1 -0
  182. package/build/src/testing/velocious-runner-reporter.js +240 -0
  183. package/build/src/testing/velocious-suite-hook-executor.d.ts +19 -0
  184. package/build/src/testing/velocious-suite-hook-executor.d.ts.map +1 -0
  185. package/build/src/testing/velocious-suite-hook-executor.js +41 -0
  186. package/build/src/testing/velocious-test-arguments.d.ts +39 -0
  187. package/build/src/testing/velocious-test-arguments.d.ts.map +1 -0
  188. package/build/src/testing/velocious-test-arguments.js +55 -0
  189. package/build/src/utils/model-primary-key.d.ts +73 -0
  190. package/build/src/utils/model-primary-key.d.ts.map +1 -0
  191. package/build/src/utils/model-primary-key.js +144 -0
  192. package/build/src/utils/sha256-bytes-hex.d.ts +7 -0
  193. package/build/src/utils/sha256-bytes-hex.d.ts.map +1 -0
  194. package/build/src/utils/sha256-bytes-hex.js +117 -0
  195. package/build/src/utils/sha256-hex.d.ts +2 -4
  196. package/build/src/utils/sha256-hex.d.ts.map +1 -1
  197. package/build/src/utils/sha256-hex.js +6 -120
  198. package/build/sync/assets/cache.js +998 -0
  199. package/build/sync/assets/types.js +62 -0
  200. package/build/sync/sync-api-client.js +3 -2
  201. package/build/sync/sync-client.js +2 -1
  202. package/build/sync/sync-envelope-replay-service.js +5 -4
  203. package/build/sync/sync-publisher.js +3 -2
  204. package/build/testing/browser-frontend-model-event-hook-scenarios.js +2 -2
  205. package/build/testing/test-profiler.js +2 -2
  206. package/build/testing/test-runner.js +496 -990
  207. package/build/testing/test.js +164 -306
  208. package/build/testing/velocious-attempt-executor.js +441 -0
  209. package/build/testing/velocious-runner-reporter.js +264 -0
  210. package/build/testing/velocious-suite-hook-executor.js +43 -0
  211. package/build/testing/velocious-test-arguments.js +64 -0
  212. package/build/tsconfig.tsbuildinfo +1 -1
  213. package/build/utils/model-primary-key.js +171 -0
  214. package/build/utils/sha256-bytes-hex.js +132 -0
  215. package/build/utils/sha256-hex.js +7 -135
  216. package/package.json +5 -4
  217. package/src/authorization/ability.js +36 -13
  218. package/src/background-jobs/adapter.js +9 -0
  219. package/src/background-jobs/main.js +35 -10
  220. package/src/background-jobs/store.js +217 -38
  221. package/src/background-jobs/types.js +15 -0
  222. package/src/configuration-types.js +1 -1
  223. package/src/configuration.js +45 -9
  224. package/src/database/drivers/base-column.js +8 -0
  225. package/src/database/drivers/mssql/sql/update.js +1 -3
  226. package/src/database/drivers/mysql/sql/update.js +1 -3
  227. package/src/database/drivers/pgsql/column.js +22 -0
  228. package/src/database/drivers/pgsql/sql/update.js +1 -3
  229. package/src/database/drivers/sqlite/sql/alter-table.js +11 -1
  230. package/src/database/drivers/sqlite/sql/update.js +1 -3
  231. package/src/database/query/index.js +2 -2
  232. package/src/database/query/model-class-query.js +26 -10
  233. package/src/database/query/preloader/has-many.js +4 -1
  234. package/src/database/query/query-data.js +2 -1
  235. package/src/database/query/update-base.js +14 -0
  236. package/src/database/query/with-count.js +3 -1
  237. package/src/database/record/acts-as-list.js +37 -13
  238. package/src/database/record/attachments/store.js +336 -26
  239. package/src/database/record/auditing.js +6 -3
  240. package/src/database/record/index.js +197 -42
  241. package/src/database/record/instance-relationships/belongs-to.js +2 -1
  242. package/src/database/record/validators/uniqueness.js +8 -5
  243. package/src/environment-handlers/node/cli/commands/generate/frontend-models.js +24 -8
  244. package/src/frontend-model-controller.js +136 -53
  245. package/src/frontend-model-resource/base-resource.js +87 -37
  246. package/src/frontend-model-resource/velocious-attachment-resource.js +98 -31
  247. package/src/frontend-models/base.js +307 -59
  248. package/src/frontend-models/preloader.js +6 -3
  249. package/src/frontend-models/query.js +15 -6
  250. package/src/frontend-models/resource-definition.js +21 -2
  251. package/src/frontend-models/use-destroyed-event.js +1 -1
  252. package/src/frontend-models/use-model-class-event.js +2 -2
  253. package/src/frontend-models/use-updated-event.js +1 -1
  254. package/src/frontend-models/websocket-channel.js +256 -93
  255. package/src/frontend-models/websocket-publishers.js +218 -18
  256. package/src/http-server/client/websocket-session.js +13 -1
  257. package/src/http-server/websocket-channel.js +15 -2
  258. package/src/sync/assets/cache.js +998 -0
  259. package/src/sync/assets/types.js +62 -0
  260. package/src/sync/sync-api-client.js +3 -2
  261. package/src/sync/sync-client.js +2 -1
  262. package/src/sync/sync-envelope-replay-service.js +5 -4
  263. package/src/sync/sync-publisher.js +3 -2
  264. package/src/testing/browser-frontend-model-event-hook-scenarios.js +2 -2
  265. package/src/testing/test-profiler.js +2 -2
  266. package/src/testing/test-runner.js +496 -990
  267. package/src/testing/test.js +164 -306
  268. package/src/testing/velocious-attempt-executor.js +441 -0
  269. package/src/testing/velocious-runner-reporter.js +264 -0
  270. package/src/testing/velocious-suite-hook-executor.js +43 -0
  271. package/src/testing/velocious-test-arguments.js +64 -0
  272. package/src/utils/model-primary-key.js +171 -0
  273. package/src/utils/sha256-bytes-hex.js +132 -0
  274. package/src/utils/sha256-hex.js +7 -135
  275. package/build/src/testing/testing-package-adapter.d.ts +0 -9
  276. package/build/src/testing/testing-package-adapter.d.ts.map +0 -1
  277. package/build/src/testing/testing-package-adapter.js +0 -69
  278. package/build/testing/testing-package-adapter.js +0 -76
  279. package/src/testing/testing-package-adapter.js +0 -76
@@ -1,5 +1,7 @@
1
1
  // @ts-check
2
2
 
3
+ import {modelPrimaryKeyCacheKey, scalarModelPrimaryKey} from "../utils/model-primary-key.js"
4
+
3
5
  /**
4
6
  * Preloads relationships onto already-loaded frontend model instances.
5
7
  *
@@ -36,7 +38,8 @@ export default class FrontendModelPreloader {
36
38
 
37
39
  if (modelsToLoad.length === 0) return
38
40
 
39
- const primaryKey = modelClass.primaryKey()
41
+ const primaryKeyDefinition = modelClass.primaryKey()
42
+ const primaryKey = scalarModelPrimaryKey(primaryKeyDefinition, `FrontendModelPreloader.preload() for ${modelClass.name}`)
40
43
  const ids = modelsToLoad.map((model) => model.primaryKeyValue())
41
44
 
42
45
  // Rebuild a fresh query carrying only the projection-relevant state so a
@@ -58,11 +61,11 @@ export default class FrontendModelPreloader {
58
61
  const reloadedById = new Map()
59
62
 
60
63
  for (const reloadedModel of reloaded) {
61
- reloadedById.set(String(reloadedModel.primaryKeyValue()), reloadedModel)
64
+ reloadedById.set(modelPrimaryKeyCacheKey(primaryKeyDefinition, reloadedModel.primaryKeyValue()), reloadedModel)
62
65
  }
63
66
 
64
67
  for (const model of modelsToLoad) {
65
- const reloadedModel = reloadedById.get(String(model.primaryKeyValue()))
68
+ const reloadedModel = reloadedById.get(modelPrimaryKeyCacheKey(primaryKeyDefinition, model.primaryKeyValue()))
66
69
 
67
70
  // The record may have been deleted/filtered between the original load and
68
71
  // this preload — skip it rather than crashing on a missing reload.
@@ -4,6 +4,7 @@ import {resolveFrontendModelClass} from "./model-registry.js"
4
4
  import {normalizeRansackGroup, parseRansackSort} from "../utils/ransack.js"
5
5
  import {isModelScopeDescriptor} from "../utils/model-scope.js"
6
6
  import isPlainObject from "../utils/plain-object.js"
7
+ import {modelPrimaryKeyConditions} from "../utils/model-primary-key.js"
7
8
 
8
9
  /**
9
10
  * FrontendModelSearch type.
@@ -1333,7 +1334,11 @@ export default class FrontendModelQuery {
1333
1334
 
1334
1335
  return {
1335
1336
  ...selectMap,
1336
- [rootModelName]: Array.from(new Set([rootPrimaryKey, ...existingRootAttributes, ...requiredAttributes]))
1337
+ [rootModelName]: Array.from(new Set([
1338
+ ...(Array.isArray(rootPrimaryKey) ? rootPrimaryKey : [rootPrimaryKey]),
1339
+ ...existingRootAttributes,
1340
+ ...requiredAttributes
1341
+ ]))
1337
1342
  }
1338
1343
  }
1339
1344
 
@@ -1936,7 +1941,9 @@ export default class FrontendModelQuery {
1936
1941
  const query = this.clone()
1937
1942
 
1938
1943
  if (query._sort.length < 1) {
1939
- query.sort([[this.modelClass.primaryKey(), "asc"]])
1944
+ const primaryKey = this.modelClass.primaryKey()
1945
+
1946
+ query.sort((Array.isArray(primaryKey) ? primaryKey : [primaryKey]).map((column) => [column, "asc"]))
1940
1947
  }
1941
1948
 
1942
1949
  query.limit(1)
@@ -1963,7 +1970,9 @@ export default class FrontendModelQuery {
1963
1970
  const query = this.clone()
1964
1971
 
1965
1972
  if (query._sort.length < 1) {
1966
- query.sort([[this.modelClass.primaryKey(), "desc"]])
1973
+ const primaryKey = this.modelClass.primaryKey()
1974
+
1975
+ query.sort((Array.isArray(primaryKey) ? primaryKey : [primaryKey]).map((column) => [column, "desc"]))
1967
1976
  } else {
1968
1977
  query._sort = query._sort.map((sortEntry) => ({
1969
1978
  ...sortEntry,
@@ -2017,15 +2026,15 @@ export default class FrontendModelQuery {
2017
2026
 
2018
2027
  /**
2019
2028
  * Runs find.
2020
- * @param {number | string} id - Record id.
2029
+ * @param {import("../utils/model-primary-key.js").ModelPrimaryKeyValue} id - Record id.
2021
2030
  * @returns {Promise<InstanceType<T>>} - Found model.
2022
2031
  */
2023
2032
  async find(id) {
2024
2033
  const pk = this.modelClass.primaryKey()
2025
- const model = await this.findBy({[pk]: id})
2034
+ const model = await this.findBy(modelPrimaryKeyConditions(pk, id))
2026
2035
 
2027
2036
  if (!model) {
2028
- throw new Error(`${this.modelClass.getModelName()} not found with ${pk}=${id}`)
2037
+ throw new Error(`${this.modelClass.getModelName()} not found with ${pk}=${JSON.stringify(id)}`)
2029
2038
  }
2030
2039
 
2031
2040
  return model
@@ -176,6 +176,7 @@ function normalizeFrontendModelResourceConfiguration(resourceConfiguration) {
176
176
  }
177
177
 
178
178
  restArgsError(restArgs)
179
+ validateFrontendModelResourcePrimaryKey(resourceConfiguration.primaryKey)
179
180
 
180
181
  const normalizedCommands = normalizeFrontendModelResourceCommands(resourceConfiguration)
181
182
  const sync = normalizeFrontendModelResourceSync(resourceConfiguration)
@@ -195,6 +196,23 @@ function normalizeFrontendModelResourceConfiguration(resourceConfiguration) {
195
196
  }
196
197
  }
197
198
 
199
+ /**
200
+ * Validates a resource primary-key definition before it can be used to build CRUD conditions.
201
+ * @param {import("../utils/model-primary-key.js").ModelPrimaryKeyDefinition | undefined} primaryKey - Resource primary key.
202
+ * @returns {void}
203
+ */
204
+ function validateFrontendModelResourcePrimaryKey(primaryKey) {
205
+ if (!Array.isArray(primaryKey)) return
206
+
207
+ if (primaryKey.length === 0) {
208
+ throw new Error("Resource primaryKey arrays must contain at least one attribute.")
209
+ }
210
+
211
+ if (new Set(primaryKey).size !== primaryKey.length) {
212
+ throw new Error("Resource primaryKey arrays must contain unique attributes.")
213
+ }
214
+ }
215
+
198
216
  /**
199
217
  * Runs normalize frontend model resource abilities.
200
218
  * @param {string[] | undefined} abilities - Resource abilities config (camelCase action list).
@@ -286,8 +304,9 @@ export function frontendModelApiManifest(backendProjects) {
286
304
  for (const configuredModelName of Object.keys(projectResources).sort()) {
287
305
  const resourceDefinition = projectResources[configuredModelName]
288
306
  const resourceConfiguration = frontendModelResourceConfigurationFromDefinition(resourceDefinition)
307
+ const resourceClass = frontendModelResourceClassFromDefinition(resourceDefinition)
289
308
 
290
- if (!resourceConfiguration) continue
309
+ if (!resourceConfiguration || !resourceClass) continue
291
310
 
292
311
  const modelName = resourceConfiguration.modelName || configuredModelName
293
312
  const resourcePath = `/${inflection.dasherize(inflection.pluralize(inflection.underscore(configuredModelName)))}`
@@ -296,7 +315,7 @@ export function frontendModelApiManifest(backendProjects) {
296
315
  const entry = {
297
316
  modelName,
298
317
  path: resourcePath,
299
- primaryKey: resourceConfiguration.primaryKey || "id",
318
+ primaryKey: resourceClass.resolvedPrimaryKey(resourceConfiguration),
300
319
  attributes: manifestAttributes(resourceConfiguration.attributes),
301
320
  abilities: resourceConfiguration.abilities,
302
321
  builtInCommands: {
@@ -19,7 +19,7 @@ import useModelClassEvent from "./use-model-class-event.js"
19
19
  * @typedef {import("./use-model-class-event.js").FrontendModelDestroyEventPayload} FrontendModelClassDestroyEventPayload */
20
20
  /**
21
21
  * Defines this typedef.
22
- * @typedef {{id: string}} FrontendModelInstanceDestroyEventPayload */
22
+ * @typedef {{id: string | import("../utils/model-primary-key.js").CompositeModelPrimaryKeyValue}} FrontendModelInstanceDestroyEventPayload */
23
23
  /**
24
24
  * FrontendModelDestroyEventPayload type.
25
25
  * @typedef {FrontendModelClassDestroyEventPayload | FrontendModelInstanceDestroyEventPayload} FrontendModelDestroyEventPayload */
@@ -17,10 +17,10 @@ import {frontendModelRemoteRequestContextKey} from "./remote-request-context.js"
17
17
  * @typedef {"create" | "update" | "destroy"} FrontendModelClassEventName */
18
18
  /**
19
19
  * Defines this typedef.
20
- * @typedef {{id: string, model: FrontendModelInstance}} FrontendModelCreateUpdateEventPayload */
20
+ * @typedef {{id: string | import("../utils/model-primary-key.js").CompositeModelPrimaryKeyValue, model: FrontendModelInstance}} FrontendModelCreateUpdateEventPayload */
21
21
  /**
22
22
  * Defines this typedef.
23
- * @typedef {{id: string}} FrontendModelDestroyEventPayload */
23
+ * @typedef {{id: string | import("../utils/model-primary-key.js").CompositeModelPrimaryKeyValue}} FrontendModelDestroyEventPayload */
24
24
  /**
25
25
  * FrontendModelClassEventPayload type.
26
26
  * @typedef {FrontendModelCreateUpdateEventPayload | FrontendModelDestroyEventPayload} FrontendModelClassEventPayload */
@@ -19,7 +19,7 @@ import useModelClassEvent from "./use-model-class-event.js"
19
19
  * @typedef {import("./use-model-class-event.js").FrontendModelCreateUpdateEventPayload} FrontendModelClassUpdateEventPayload */
20
20
  /**
21
21
  * Defines this typedef.
22
- * @typedef {{id: string, model: FrontendModelInstance}} FrontendModelInstanceUpdateEventPayload */
22
+ * @typedef {{id: string | import("../utils/model-primary-key.js").CompositeModelPrimaryKeyValue, model: FrontendModelInstance}} FrontendModelInstanceUpdateEventPayload */
23
23
  /**
24
24
  * FrontendModelUpdateEventPayload type.
25
25
  * @typedef {FrontendModelClassUpdateEventPayload | FrontendModelInstanceUpdateEventPayload} FrontendModelUpdateEventPayload */