@statezero/core 0.2.37 → 0.2.38

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 (307) hide show
  1. package/dist/adaptors/vue/components/LayoutRenderer.js +166 -0
  2. package/dist/adaptors/vue/components/defaults/AlertElement.js +31 -0
  3. package/dist/adaptors/vue/components/defaults/DisplayElement.js +44 -0
  4. package/dist/adaptors/vue/components/defaults/DividerElement.js +10 -0
  5. package/dist/adaptors/vue/components/defaults/ErrorBlock.js +24 -0
  6. package/dist/adaptors/vue/components/defaults/GroupElement.js +41 -0
  7. package/dist/adaptors/vue/components/defaults/LabelElement.js +21 -0
  8. package/dist/adaptors/vue/components/defaults/TabsElement.js +38 -0
  9. package/package.json +6 -4
  10. package/dist/actions/backend1/django_app/calculate-hash.d.ts +0 -57
  11. package/dist/actions/backend1/django_app/calculate-hash.js +0 -80
  12. package/dist/actions/backend1/django_app/calculate-hash.schema.json +0 -148
  13. package/dist/actions/backend1/django_app/get-current-username.d.ts +0 -29
  14. package/dist/actions/backend1/django_app/get-current-username.js +0 -65
  15. package/dist/actions/backend1/django_app/get-current-username.schema.json +0 -47
  16. package/dist/actions/backend1/django_app/get-server-status.d.ts +0 -38
  17. package/dist/actions/backend1/django_app/get-server-status.js +0 -68
  18. package/dist/actions/backend1/django_app/get-server-status.schema.json +0 -93
  19. package/dist/actions/backend1/django_app/get-user-info.d.ts +0 -44
  20. package/dist/actions/backend1/django_app/get-user-info.js +0 -70
  21. package/dist/actions/backend1/django_app/get-user-info.schema.json +0 -127
  22. package/dist/actions/backend1/django_app/index.d.ts +0 -1
  23. package/dist/actions/backend1/django_app/index.js +0 -6
  24. package/dist/actions/backend1/django_app/process-data.d.ts +0 -51
  25. package/dist/actions/backend1/django_app/process-data.js +0 -78
  26. package/dist/actions/backend1/django_app/process-data.schema.json +0 -117
  27. package/dist/actions/backend1/django_app/send-notification.d.ts +0 -55
  28. package/dist/actions/backend1/django_app/send-notification.js +0 -81
  29. package/dist/actions/backend1/django_app/send-notification.schema.json +0 -175
  30. package/dist/actions/backend1/index.d.ts +0 -1
  31. package/dist/actions/backend1/index.js +0 -1
  32. package/dist/actions/default/django_app/calculate-hash.d.ts +0 -57
  33. package/dist/actions/default/django_app/calculate-hash.js +0 -80
  34. package/dist/actions/default/django_app/calculate-hash.schema.json +0 -148
  35. package/dist/actions/default/django_app/get-current-username.d.ts +0 -29
  36. package/dist/actions/default/django_app/get-current-username.js +0 -65
  37. package/dist/actions/default/django_app/get-current-username.schema.json +0 -47
  38. package/dist/actions/default/django_app/get-server-status.d.ts +0 -38
  39. package/dist/actions/default/django_app/get-server-status.js +0 -68
  40. package/dist/actions/default/django_app/get-server-status.schema.json +0 -93
  41. package/dist/actions/default/django_app/get-user-info.d.ts +0 -44
  42. package/dist/actions/default/django_app/get-user-info.js +0 -70
  43. package/dist/actions/default/django_app/get-user-info.schema.json +0 -127
  44. package/dist/actions/default/django_app/index.d.ts +0 -1
  45. package/dist/actions/default/django_app/index.js +0 -6
  46. package/dist/actions/default/django_app/process-data.d.ts +0 -51
  47. package/dist/actions/default/django_app/process-data.js +0 -78
  48. package/dist/actions/default/django_app/process-data.schema.json +0 -117
  49. package/dist/actions/default/django_app/send-notification.d.ts +0 -55
  50. package/dist/actions/default/django_app/send-notification.js +0 -81
  51. package/dist/actions/default/django_app/send-notification.schema.json +0 -175
  52. package/dist/actions/default/index.d.ts +0 -1
  53. package/dist/actions/default/index.js +0 -1
  54. package/dist/actions/index.d.ts +0 -1
  55. package/dist/actions/index.js +0 -5
  56. package/dist/adaptors/react/composables.d.ts +0 -1
  57. package/dist/adaptors/react/composables.js +0 -4
  58. package/dist/adaptors/react/index.d.ts +0 -1
  59. package/dist/adaptors/react/index.js +0 -1
  60. package/dist/adaptors/vue/components/LayoutRenderer.vue +0 -361
  61. package/dist/adaptors/vue/components/defaults/AlertElement.vue +0 -38
  62. package/dist/adaptors/vue/components/defaults/DisplayElement.vue +0 -57
  63. package/dist/adaptors/vue/components/defaults/DividerElement.vue +0 -13
  64. package/dist/adaptors/vue/components/defaults/ErrorBlock.vue +0 -28
  65. package/dist/adaptors/vue/components/defaults/GroupElement.vue +0 -53
  66. package/dist/adaptors/vue/components/defaults/LabelElement.vue +0 -25
  67. package/dist/adaptors/vue/components/defaults/TabsElement.vue +0 -54
  68. package/dist/adaptors/vue/components/defaults/index.d.ts +0 -7
  69. package/dist/adaptors/vue/components/defaults/index.js +0 -31
  70. package/dist/adaptors/vue/components/index.d.ts +0 -1
  71. package/dist/adaptors/vue/components/index.js +0 -7
  72. package/dist/adaptors/vue/composables.d.ts +0 -2
  73. package/dist/adaptors/vue/composables.js +0 -44
  74. package/dist/adaptors/vue/index.d.ts +0 -3
  75. package/dist/adaptors/vue/index.js +0 -4
  76. package/dist/adaptors/vue/reactivity.d.ts +0 -18
  77. package/dist/adaptors/vue/reactivity.js +0 -132
  78. package/dist/cli/commands/sync.d.ts +0 -6
  79. package/dist/cli/commands/sync.js +0 -30
  80. package/dist/cli/commands/syncActions.d.ts +0 -46
  81. package/dist/cli/commands/syncActions.js +0 -717
  82. package/dist/cli/commands/syncModels.d.ts +0 -132
  83. package/dist/cli/commands/syncModels.js +0 -1120
  84. package/dist/cli/configFileLoader.d.ts +0 -10
  85. package/dist/cli/configFileLoader.js +0 -85
  86. package/dist/cli/index.d.ts +0 -2
  87. package/dist/cli/index.js +0 -22
  88. package/dist/config.d.ts +0 -57
  89. package/dist/config.js +0 -273
  90. package/dist/core/eventReceivers.d.ts +0 -185
  91. package/dist/core/eventReceivers.js +0 -266
  92. package/dist/core/utils.d.ts +0 -8
  93. package/dist/core/utils.js +0 -62
  94. package/dist/errorHandler.d.ts +0 -21
  95. package/dist/errorHandler.js +0 -27
  96. package/dist/filtering/localFiltering.d.ts +0 -110
  97. package/dist/filtering/localFiltering.js +0 -1080
  98. package/dist/flavours/django/dates.d.ts +0 -34
  99. package/dist/flavours/django/dates.js +0 -113
  100. package/dist/flavours/django/errors.d.ts +0 -138
  101. package/dist/flavours/django/errors.js +0 -195
  102. package/dist/flavours/django/f.d.ts +0 -6
  103. package/dist/flavours/django/f.js +0 -91
  104. package/dist/flavours/django/files.d.ts +0 -62
  105. package/dist/flavours/django/files.js +0 -355
  106. package/dist/flavours/django/makeApiCall.d.ts +0 -36
  107. package/dist/flavours/django/makeApiCall.js +0 -169
  108. package/dist/flavours/django/manager.d.ts +0 -204
  109. package/dist/flavours/django/manager.js +0 -222
  110. package/dist/flavours/django/model.d.ts +0 -137
  111. package/dist/flavours/django/model.js +0 -366
  112. package/dist/flavours/django/operationFactory.d.ts +0 -73
  113. package/dist/flavours/django/operationFactory.js +0 -248
  114. package/dist/flavours/django/q.d.ts +0 -70
  115. package/dist/flavours/django/q.js +0 -43
  116. package/dist/flavours/django/queryExecutor.d.ts +0 -149
  117. package/dist/flavours/django/queryExecutor.js +0 -590
  118. package/dist/flavours/django/querySet.d.ts +0 -301
  119. package/dist/flavours/django/querySet.js +0 -736
  120. package/dist/flavours/django/serializers.d.ts +0 -39
  121. package/dist/flavours/django/serializers.js +0 -296
  122. package/dist/flavours/django/tempPk.d.ts +0 -31
  123. package/dist/flavours/django/tempPk.js +0 -92
  124. package/dist/flavours/django/utils.d.ts +0 -19
  125. package/dist/flavours/django/utils.js +0 -29
  126. package/dist/index.d.ts +0 -46
  127. package/dist/index.js +0 -48
  128. package/dist/models/backend1/django_app/comprehensivemodel.d.ts +0 -894
  129. package/dist/models/backend1/django_app/comprehensivemodel.js +0 -71
  130. package/dist/models/backend1/django_app/comprehensivemodel.schema.json +0 -870
  131. package/dist/models/backend1/django_app/custompkmodel.d.ts +0 -92
  132. package/dist/models/backend1/django_app/custompkmodel.js +0 -69
  133. package/dist/models/backend1/django_app/custompkmodel.schema.json +0 -71
  134. package/dist/models/backend1/django_app/dailyrate.d.ts +0 -230
  135. package/dist/models/backend1/django_app/dailyrate.js +0 -71
  136. package/dist/models/backend1/django_app/dailyrate.schema.json +0 -212
  137. package/dist/models/backend1/django_app/deepmodellevel1.d.ts +0 -140
  138. package/dist/models/backend1/django_app/deepmodellevel1.js +0 -72
  139. package/dist/models/backend1/django_app/deepmodellevel1.schema.json +0 -114
  140. package/dist/models/backend1/django_app/deepmodellevel2.d.ts +0 -118
  141. package/dist/models/backend1/django_app/deepmodellevel2.js +0 -71
  142. package/dist/models/backend1/django_app/deepmodellevel2.schema.json +0 -92
  143. package/dist/models/backend1/django_app/deepmodellevel3.d.ts +0 -92
  144. package/dist/models/backend1/django_app/deepmodellevel3.js +0 -69
  145. package/dist/models/backend1/django_app/deepmodellevel3.schema.json +0 -69
  146. package/dist/models/backend1/django_app/dummymodel.d.ts +0 -134
  147. package/dist/models/backend1/django_app/dummymodel.js +0 -71
  148. package/dist/models/backend1/django_app/dummymodel.schema.json +0 -109
  149. package/dist/models/backend1/django_app/dummyrelatedmodel.d.ts +0 -92
  150. package/dist/models/backend1/django_app/dummyrelatedmodel.js +0 -69
  151. package/dist/models/backend1/django_app/dummyrelatedmodel.schema.json +0 -69
  152. package/dist/models/backend1/django_app/filetest.d.ts +0 -140
  153. package/dist/models/backend1/django_app/filetest.js +0 -69
  154. package/dist/models/backend1/django_app/filetest.schema.json +0 -111
  155. package/dist/models/backend1/django_app/index.d.ts +0 -1
  156. package/dist/models/backend1/django_app/index.js +0 -21
  157. package/dist/models/backend1/django_app/m2mdepthtestlevel1.d.ts +0 -118
  158. package/dist/models/backend1/django_app/m2mdepthtestlevel1.js +0 -71
  159. package/dist/models/backend1/django_app/m2mdepthtestlevel1.schema.json +0 -94
  160. package/dist/models/backend1/django_app/m2mdepthtestlevel2.d.ts +0 -118
  161. package/dist/models/backend1/django_app/m2mdepthtestlevel2.js +0 -71
  162. package/dist/models/backend1/django_app/m2mdepthtestlevel2.schema.json +0 -94
  163. package/dist/models/backend1/django_app/m2mdepthtestlevel3.d.ts +0 -134
  164. package/dist/models/backend1/django_app/m2mdepthtestlevel3.js +0 -71
  165. package/dist/models/backend1/django_app/m2mdepthtestlevel3.schema.json +0 -112
  166. package/dist/models/backend1/django_app/modelwithcustompkrelation.d.ts +0 -118
  167. package/dist/models/backend1/django_app/modelwithcustompkrelation.js +0 -71
  168. package/dist/models/backend1/django_app/modelwithcustompkrelation.schema.json +0 -93
  169. package/dist/models/backend1/django_app/modelwithrestrictedfields.d.ts +0 -134
  170. package/dist/models/backend1/django_app/modelwithrestrictedfields.js +0 -71
  171. package/dist/models/backend1/django_app/modelwithrestrictedfields.schema.json +0 -111
  172. package/dist/models/backend1/django_app/namefiltercustompkmodel.d.ts +0 -92
  173. package/dist/models/backend1/django_app/namefiltercustompkmodel.js +0 -69
  174. package/dist/models/backend1/django_app/namefiltercustompkmodel.schema.json +0 -71
  175. package/dist/models/backend1/django_app/order.d.ts +0 -220
  176. package/dist/models/backend1/django_app/order.js +0 -71
  177. package/dist/models/backend1/django_app/order.schema.json +0 -203
  178. package/dist/models/backend1/django_app/orderitem.d.ts +0 -172
  179. package/dist/models/backend1/django_app/orderitem.js +0 -72
  180. package/dist/models/backend1/django_app/orderitem.schema.json +0 -149
  181. package/dist/models/backend1/django_app/product.d.ts +0 -254
  182. package/dist/models/backend1/django_app/product.js +0 -71
  183. package/dist/models/backend1/django_app/product.schema.json +0 -277
  184. package/dist/models/backend1/django_app/productcategory.d.ts +0 -92
  185. package/dist/models/backend1/django_app/productcategory.js +0 -69
  186. package/dist/models/backend1/django_app/productcategory.schema.json +0 -70
  187. package/dist/models/backend1/django_app/rateplan.d.ts +0 -92
  188. package/dist/models/backend1/django_app/rateplan.js +0 -69
  189. package/dist/models/backend1/django_app/rateplan.schema.json +0 -70
  190. package/dist/models/backend1/django_app/restrictedfieldrelatedmodel.d.ts +0 -108
  191. package/dist/models/backend1/django_app/restrictedfieldrelatedmodel.js +0 -69
  192. package/dist/models/backend1/django_app/restrictedfieldrelatedmodel.schema.json +0 -87
  193. package/dist/models/backend1/fileobject.d.ts +0 -4
  194. package/dist/models/backend1/fileobject.js +0 -9
  195. package/dist/models/backend1/index.d.ts +0 -2
  196. package/dist/models/backend1/index.js +0 -2
  197. package/dist/models/default/django_app/comprehensivemodel.d.ts +0 -894
  198. package/dist/models/default/django_app/comprehensivemodel.js +0 -71
  199. package/dist/models/default/django_app/comprehensivemodel.schema.json +0 -870
  200. package/dist/models/default/django_app/custompkmodel.d.ts +0 -92
  201. package/dist/models/default/django_app/custompkmodel.js +0 -69
  202. package/dist/models/default/django_app/custompkmodel.schema.json +0 -71
  203. package/dist/models/default/django_app/dailyrate.d.ts +0 -230
  204. package/dist/models/default/django_app/dailyrate.js +0 -71
  205. package/dist/models/default/django_app/dailyrate.schema.json +0 -212
  206. package/dist/models/default/django_app/deepmodellevel1.d.ts +0 -128
  207. package/dist/models/default/django_app/deepmodellevel1.js +0 -72
  208. package/dist/models/default/django_app/deepmodellevel1.schema.json +0 -102
  209. package/dist/models/default/django_app/deepmodellevel2.d.ts +0 -106
  210. package/dist/models/default/django_app/deepmodellevel2.js +0 -71
  211. package/dist/models/default/django_app/deepmodellevel2.schema.json +0 -80
  212. package/dist/models/default/django_app/deepmodellevel3.d.ts +0 -80
  213. package/dist/models/default/django_app/deepmodellevel3.js +0 -69
  214. package/dist/models/default/django_app/deepmodellevel3.schema.json +0 -57
  215. package/dist/models/default/django_app/dummymodel.d.ts +0 -122
  216. package/dist/models/default/django_app/dummymodel.js +0 -71
  217. package/dist/models/default/django_app/dummymodel.schema.json +0 -97
  218. package/dist/models/default/django_app/dummyrelatedmodel.d.ts +0 -80
  219. package/dist/models/default/django_app/dummyrelatedmodel.js +0 -69
  220. package/dist/models/default/django_app/dummyrelatedmodel.schema.json +0 -57
  221. package/dist/models/default/django_app/filetest.d.ts +0 -128
  222. package/dist/models/default/django_app/filetest.js +0 -69
  223. package/dist/models/default/django_app/filetest.schema.json +0 -99
  224. package/dist/models/default/django_app/index.d.ts +0 -1
  225. package/dist/models/default/django_app/index.js +0 -21
  226. package/dist/models/default/django_app/m2mdepthtestlevel1.d.ts +0 -118
  227. package/dist/models/default/django_app/m2mdepthtestlevel1.js +0 -71
  228. package/dist/models/default/django_app/m2mdepthtestlevel1.schema.json +0 -94
  229. package/dist/models/default/django_app/m2mdepthtestlevel2.d.ts +0 -118
  230. package/dist/models/default/django_app/m2mdepthtestlevel2.js +0 -71
  231. package/dist/models/default/django_app/m2mdepthtestlevel2.schema.json +0 -94
  232. package/dist/models/default/django_app/m2mdepthtestlevel3.d.ts +0 -134
  233. package/dist/models/default/django_app/m2mdepthtestlevel3.js +0 -71
  234. package/dist/models/default/django_app/m2mdepthtestlevel3.schema.json +0 -112
  235. package/dist/models/default/django_app/modelwithcustompkrelation.d.ts +0 -118
  236. package/dist/models/default/django_app/modelwithcustompkrelation.js +0 -71
  237. package/dist/models/default/django_app/modelwithcustompkrelation.schema.json +0 -93
  238. package/dist/models/default/django_app/modelwithrestrictedfields.d.ts +0 -134
  239. package/dist/models/default/django_app/modelwithrestrictedfields.js +0 -71
  240. package/dist/models/default/django_app/modelwithrestrictedfields.schema.json +0 -111
  241. package/dist/models/default/django_app/namefiltercustompkmodel.d.ts +0 -92
  242. package/dist/models/default/django_app/namefiltercustompkmodel.js +0 -69
  243. package/dist/models/default/django_app/namefiltercustompkmodel.schema.json +0 -71
  244. package/dist/models/default/django_app/order.d.ts +0 -220
  245. package/dist/models/default/django_app/order.js +0 -71
  246. package/dist/models/default/django_app/order.schema.json +0 -203
  247. package/dist/models/default/django_app/orderitem.d.ts +0 -172
  248. package/dist/models/default/django_app/orderitem.js +0 -72
  249. package/dist/models/default/django_app/orderitem.schema.json +0 -149
  250. package/dist/models/default/django_app/product.d.ts +0 -254
  251. package/dist/models/default/django_app/product.js +0 -71
  252. package/dist/models/default/django_app/product.schema.json +0 -277
  253. package/dist/models/default/django_app/productcategory.d.ts +0 -92
  254. package/dist/models/default/django_app/productcategory.js +0 -69
  255. package/dist/models/default/django_app/productcategory.schema.json +0 -70
  256. package/dist/models/default/django_app/rateplan.d.ts +0 -92
  257. package/dist/models/default/django_app/rateplan.js +0 -69
  258. package/dist/models/default/django_app/rateplan.schema.json +0 -70
  259. package/dist/models/default/django_app/restrictedfieldrelatedmodel.d.ts +0 -108
  260. package/dist/models/default/django_app/restrictedfieldrelatedmodel.js +0 -69
  261. package/dist/models/default/django_app/restrictedfieldrelatedmodel.schema.json +0 -87
  262. package/dist/models/default/fileobject.d.ts +0 -4
  263. package/dist/models/default/fileobject.js +0 -9
  264. package/dist/models/default/index.d.ts +0 -2
  265. package/dist/models/default/index.js +0 -2
  266. package/dist/models/index.d.ts +0 -1
  267. package/dist/models/index.js +0 -5
  268. package/dist/react-entry.d.ts +0 -2
  269. package/dist/react-entry.js +0 -2
  270. package/dist/reactiveAdaptor.d.ts +0 -24
  271. package/dist/reactiveAdaptor.js +0 -38
  272. package/dist/reset.d.ts +0 -15
  273. package/dist/reset.js +0 -97
  274. package/dist/setup.d.ts +0 -15
  275. package/dist/setup.js +0 -33
  276. package/dist/syncEngine/cache/cache.d.ts +0 -75
  277. package/dist/syncEngine/cache/cache.js +0 -355
  278. package/dist/syncEngine/metrics/metricOptCalcs.d.ts +0 -79
  279. package/dist/syncEngine/metrics/metricOptCalcs.js +0 -284
  280. package/dist/syncEngine/registries/metricRegistry.d.ts +0 -58
  281. package/dist/syncEngine/registries/metricRegistry.js +0 -171
  282. package/dist/syncEngine/registries/modelStoreRegistry.d.ts +0 -11
  283. package/dist/syncEngine/registries/modelStoreRegistry.js +0 -63
  284. package/dist/syncEngine/registries/querysetStoreGraph.d.ts +0 -41
  285. package/dist/syncEngine/registries/querysetStoreGraph.js +0 -174
  286. package/dist/syncEngine/registries/querysetStoreRegistry.d.ts +0 -72
  287. package/dist/syncEngine/registries/querysetStoreRegistry.js +0 -335
  288. package/dist/syncEngine/stores/metricStore.d.ts +0 -55
  289. package/dist/syncEngine/stores/metricStore.js +0 -222
  290. package/dist/syncEngine/stores/modelStore.d.ts +0 -53
  291. package/dist/syncEngine/stores/modelStore.js +0 -565
  292. package/dist/syncEngine/stores/operation.d.ts +0 -139
  293. package/dist/syncEngine/stores/operation.js +0 -291
  294. package/dist/syncEngine/stores/operationEventHandlers.d.ts +0 -8
  295. package/dist/syncEngine/stores/operationEventHandlers.js +0 -322
  296. package/dist/syncEngine/stores/querysetStore.d.ts +0 -60
  297. package/dist/syncEngine/stores/querysetStore.js +0 -294
  298. package/dist/syncEngine/stores/reactivity.d.ts +0 -3
  299. package/dist/syncEngine/stores/reactivity.js +0 -4
  300. package/dist/syncEngine/stores/utils.d.ts +0 -14
  301. package/dist/syncEngine/stores/utils.js +0 -32
  302. package/dist/syncEngine/sync.d.ts +0 -46
  303. package/dist/syncEngine/sync.js +0 -389
  304. package/dist/testing.d.ts +0 -63
  305. package/dist/testing.js +0 -175
  306. package/dist/vue-entry.d.ts +0 -15
  307. package/dist/vue-entry.js +0 -7
@@ -1,565 +0,0 @@
1
- import { Operation, Status, Type, operationRegistry } from './operation.js';
2
- import { isNil, isEmpty, trim, isEqual } from 'lodash-es';
3
- import { modelEventEmitter } from './reactivity.js';
4
- import { Cache } from '../cache/cache.js';
5
- import { replaceTempPks, containsTempPk, resolveToRealPk, onTempPkResolved } from '../../flavours/django/tempPk.js';
6
- const emitEvents = (store, event) => {
7
- if (!event || !event.pks || event.pks.length === 0)
8
- return;
9
- // Get prior values for these pks in one pass (before computing new)
10
- const lastRenderedDataArray = event.pks.map(pk => store._lastRenderedData.get(pk) ?? null);
11
- // Batch render all pks - useCache=false to get fresh data for comparison
12
- const newRenderedDataArray = store.render(event.pks, true, false);
13
- // Single equality check on the whole batch
14
- if (!isEqual(newRenderedDataArray, lastRenderedDataArray)) {
15
- // Update cache for all pks
16
- const pkField = store.pkField;
17
- for (const item of newRenderedDataArray) {
18
- if (item && item[pkField] != null) {
19
- store._lastRenderedData.set(item[pkField], item);
20
- }
21
- }
22
- // Also mark any pks that are now null (deleted)
23
- for (const pk of event.pks) {
24
- if (!newRenderedDataArray.some(item => item && item[pkField] === pk)) {
25
- store._lastRenderedData.set(pk, null);
26
- }
27
- }
28
- modelEventEmitter.emit(`${store.modelClass.configKey}::${store.modelClass.modelName}::render`, event);
29
- store.renderCallbacks.forEach((callback) => {
30
- try {
31
- callback();
32
- }
33
- catch (error) {
34
- console.warn("Error in model store render callback:", error);
35
- }
36
- });
37
- }
38
- };
39
- class EventData {
40
- constructor(ModelClass, pks) {
41
- this.ModelClass = ModelClass;
42
- this.pks = Array.isArray(pks) ? pks : [pks];
43
- }
44
- /**
45
- * Single event containing all PKs from an operation
46
- */
47
- static fromOperation(operation) {
48
- const ModelClass = operation.queryset.ModelClass;
49
- const pkField = ModelClass.primaryKeyField;
50
- const pks = operation.instances
51
- .filter(instance => instance != null && typeof instance === 'object' && pkField in instance)
52
- .map(instance => instance[pkField]);
53
- return pks.length > 0 ? new EventData(ModelClass, pks) : null;
54
- }
55
- /**
56
- * Single event containing all unique PKs across multiple operations
57
- */
58
- static fromOperations(operations) {
59
- if (!operations.length)
60
- return null;
61
- const ModelClass = operations[0].queryset.ModelClass;
62
- const pkField = ModelClass.primaryKeyField;
63
- const uniquePks = new Set();
64
- for (const op of operations) {
65
- for (const inst of op.instances) {
66
- if (inst != null && typeof inst === 'object' && pkField in inst) {
67
- uniquePks.add(inst[pkField]);
68
- }
69
- }
70
- }
71
- return uniquePks.size > 0 ? new EventData(ModelClass, Array.from(uniquePks)) : null;
72
- }
73
- /**
74
- * Single event containing all unique PKs from an array of instances
75
- */
76
- static fromInstances(instances, ModelClass) {
77
- const pkField = ModelClass.primaryKeyField;
78
- const uniquePks = new Set(instances
79
- .filter(inst => inst && inst[pkField] != null)
80
- .map(inst => inst[pkField]));
81
- return uniquePks.size > 0 ? new EventData(ModelClass, Array.from(uniquePks)) : null;
82
- }
83
- }
84
- export class ModelStore {
85
- constructor(modelClass, fetchFn, initialGroundTruth = null, initialOperations = null, options = {}) {
86
- this.modelClass = modelClass;
87
- this.fetchFn = fetchFn;
88
- this.isSyncing = false;
89
- this.pruneThreshold = options.pruneThreshold || 10;
90
- this.groundTruthArray = initialGroundTruth || [];
91
- this.operationsMap = new Map();
92
- // Handle initial operations if provided
93
- if (initialOperations && initialOperations.length > 0) {
94
- this._loadOperations(initialOperations);
95
- }
96
- this.modelCache = new Cache("model-cache", {}, this.onHydrated.bind(this));
97
- this._lastRenderedData = new Map();
98
- this.renderCallbacks = new Set();
99
- // Migrate cache entries when temp pks are resolved to real pks
100
- this._unsubscribeTempPk = onTempPkResolved((tempPk, realPk) => {
101
- if (this._lastRenderedData.has(tempPk)) {
102
- const data = this._lastRenderedData.get(tempPk);
103
- // Update the pk field in the cached data
104
- if (data && typeof data === 'object') {
105
- data[this.pkField] = realPk;
106
- }
107
- this._lastRenderedData.set(realPk, data);
108
- this._lastRenderedData.delete(tempPk);
109
- }
110
- });
111
- }
112
- registerRenderCallback(callback) {
113
- this.renderCallbacks.add(callback);
114
- return () => this.renderCallbacks.delete(callback);
115
- }
116
- /**
117
- * Load operations from data and add them to the operations map,
118
- * reusing existing operations from the registry if they exist
119
- */
120
- _loadOperations(operationsData) {
121
- operationsData.forEach((opData) => {
122
- const existingOp = operationRegistry.get(opData.operationId);
123
- if (existingOp) {
124
- // If the operation exists in the registry, use it
125
- this.operationsMap.set(existingOp.operationId, existingOp);
126
- }
127
- else {
128
- // Otherwise just use the plain object data
129
- this.operationsMap.set(opData.operationId, new Operation(opData, true));
130
- }
131
- });
132
- }
133
- // Caching
134
- get cacheKey() {
135
- return `${this.modelClass.configKey}::${this.modelClass.modelName}`;
136
- }
137
- onHydrated() {
138
- if (this.groundTruthArray.length === 0 && this.operationsMap.size === 0) {
139
- let cached = this.modelCache.get(this.cacheKey);
140
- console.log(`[ModelStore] Hydrated ${this.modelClass.modelName} with ${(cached || []).length} items from cache`);
141
- if (!isNil(cached) && !isEmpty(cached)) {
142
- this.setGroundTruth(cached);
143
- }
144
- }
145
- }
146
- setCache(result) {
147
- const pkField = this.pkField;
148
- let nonTempPkItems = [];
149
- result.forEach((item) => {
150
- let pk = item[pkField];
151
- if (typeof pk === "string" && containsTempPk(pk)) {
152
- pk = replaceTempPks(item[pkField]);
153
- if (isNil(pk) || isEmpty(trim(pk))) {
154
- return;
155
- }
156
- }
157
- if (item && typeof item.serialize === "function") {
158
- // Pass includeRepr=true to preserve repr field in cache
159
- const serializedItem = item.serialize(true);
160
- serializedItem[pkField] = pk;
161
- nonTempPkItems.push(serializedItem);
162
- }
163
- else {
164
- item[pkField] = pk;
165
- nonTempPkItems.push(item);
166
- }
167
- });
168
- this.modelCache.set(this.cacheKey, nonTempPkItems);
169
- }
170
- clearCache() {
171
- this.modelCache.delete(this.cacheKey);
172
- }
173
- updateCache(items, requestedPks) {
174
- const pkField = this.pkField;
175
- let nonTempPkItems = [];
176
- items.forEach((item) => {
177
- let pk = item[pkField];
178
- if (typeof pk === "string" && containsTempPk(pk)) {
179
- pk = replaceTempPks(item[pkField]);
180
- if (isNil(pk) || isEmpty(trim(pk))) {
181
- return;
182
- }
183
- }
184
- item[pkField] = pk;
185
- nonTempPkItems.push(item);
186
- });
187
- // If rendering ALL items (requestedPks is null), simply replace the cache
188
- if (requestedPks === null) {
189
- this.setCache(nonTempPkItems);
190
- return;
191
- }
192
- // Otherwise, we're rendering specific items - update only those items
193
- const currentCache = this.modelCache.get(this.cacheKey) || [];
194
- // Filter out items that were requested but not in the result (they were deleted)
195
- const filteredCache = currentCache.filter((item) => item &&
196
- typeof item === "object" &&
197
- pkField in item &&
198
- (!requestedPks.has(item[pkField]) ||
199
- nonTempPkItems.some((newItem) => newItem[pkField] === item[pkField])));
200
- // Create a map for faster lookups
201
- const cacheMap = new Map(filteredCache.map((item) => [item[pkField], item]));
202
- // Add or update items from the result
203
- for (const item of nonTempPkItems) {
204
- if (item && typeof item === "object" && pkField in item) {
205
- cacheMap.set(item[pkField], item);
206
- }
207
- }
208
- // Update the cache
209
- const updatedCache = Array.from(cacheMap.values());
210
- this.setCache(updatedCache);
211
- }
212
- // Main modelStore methods
213
- get operations() {
214
- return Array.from(this.operationsMap.values());
215
- }
216
- get pkField() {
217
- return this.modelClass.primaryKeyField;
218
- }
219
- // Commit optimistic updates
220
- addOperation(operation) {
221
- this.operationsMap.set(operation.operationId, operation);
222
- if (this.operationsMap.size > this.pruneThreshold) {
223
- this.prune();
224
- }
225
- emitEvents(this, EventData.fromOperation(operation));
226
- }
227
- updateOperation(operation) {
228
- if (!this.operationsMap.has(operation.operationId))
229
- return false;
230
- this.operationsMap.set(operation.operationId, operation);
231
- emitEvents(this, EventData.fromOperation(operation));
232
- return true;
233
- }
234
- confirm(operation) {
235
- if (!this.operationsMap.has(operation.operationId))
236
- return;
237
- this.operationsMap.set(operation.operationId, operation);
238
- emitEvents(this, EventData.fromOperation(operation));
239
- }
240
- reject(operation) {
241
- if (!this.operationsMap.has(operation.operationId))
242
- return;
243
- this.operationsMap.set(operation.operationId, operation);
244
- emitEvents(this, EventData.fromOperation(operation));
245
- }
246
- setOperations(operations = []) {
247
- const prevOps = this.operations;
248
- this.operationsMap.clear();
249
- operations.forEach((op) => {
250
- this.operationsMap.set(op.operationId, op);
251
- });
252
- const allOps = [...prevOps, ...this.operations];
253
- emitEvents(this, EventData.fromOperations(allOps));
254
- }
255
- // Ground truth data methods
256
- setGroundTruth(groundTruth) {
257
- let prevGroundTruth = this.groundTruthArray;
258
- this.groundTruthArray = Array.isArray(groundTruth) ? groundTruth : [];
259
- // reactivity - gather all ops
260
- const allOps = [...prevGroundTruth, ...this.groundTruthArray];
261
- emitEvents(this, EventData.fromInstances(allOps, this.modelClass));
262
- }
263
- getGroundTruth() {
264
- return this.groundTruthArray;
265
- }
266
- get groundTruthPks() {
267
- const pk = this.pkField;
268
- return this.groundTruthArray
269
- .filter((instance) => instance && typeof instance === "object" && pk in instance)
270
- .map((instance) => instance[pk]);
271
- }
272
- addToGroundTruth(instances) {
273
- if (!Array.isArray(instances) || instances.length === 0)
274
- return;
275
- const pkField = this.pkField;
276
- const pkMap = new Map();
277
- instances.forEach((inst) => {
278
- if (inst && typeof inst === "object" && pkField in inst) {
279
- pkMap.set(inst[pkField], inst);
280
- }
281
- else {
282
- console.warn(`[ModelStore ${this.modelClass.modelName}] Skipping invalid instance in addToGroundTruth:`, inst);
283
- }
284
- });
285
- if (pkMap.size === 0)
286
- return;
287
- const updatedGroundTruth = [];
288
- const processedPks = new Set();
289
- const checkpointInstances = []; // Track instances that need CHECKPOINT operations
290
- for (const existingItem of this.groundTruthArray) {
291
- if (!existingItem ||
292
- typeof existingItem !== "object" ||
293
- !(pkField in existingItem)) {
294
- continue;
295
- }
296
- const pk = existingItem[pkField];
297
- if (pkMap.has(pk)) {
298
- const updatedInstance = { ...existingItem, ...pkMap.get(pk) };
299
- updatedGroundTruth.push(updatedInstance);
300
- processedPks.add(pk);
301
- // This instance already existed - add it to checkpoint list
302
- checkpointInstances.push(updatedInstance);
303
- pkMap.delete(pk);
304
- }
305
- else {
306
- updatedGroundTruth.push(existingItem);
307
- }
308
- }
309
- // Add completely new instances (these don't need checkpoint operations)
310
- updatedGroundTruth.push(...Array.from(pkMap.values()));
311
- this.groundTruthArray = updatedGroundTruth;
312
- // Create CHECKPOINT operation for instances that already existed
313
- if (checkpointInstances.length > 0) {
314
- const checkpointOperation = new Operation({
315
- operationId: `checkpoint_${Date.now()}_${Math.random()
316
- .toString(36)
317
- .substr(2, 9)}`,
318
- type: Type.CHECKPOINT,
319
- instances: checkpointInstances,
320
- status: Status.CONFIRMED,
321
- timestamp: Date.now(),
322
- queryset: this.modelClass.objects.all(),
323
- });
324
- this.operationsMap.set(checkpointOperation.operationId, checkpointOperation);
325
- console.log(`[ModelStore ${this.modelClass.modelName}] Created CHECKPOINT operation for ${checkpointInstances.length} existing instances`);
326
- }
327
- // reactivity - use all the newly added instances (both new and updated)
328
- emitEvents(this, EventData.fromInstances([...checkpointInstances, ...Array.from(pkMap.values())], this.modelClass));
329
- }
330
- _filteredOperations(pks, operations) {
331
- if (!pks)
332
- return operations;
333
- const pkField = this.pkField;
334
- let filteredOps = [];
335
- for (const op of operations) {
336
- let relevantInstances = op.instances.filter((instance) => pks.has(instance[pkField] || instance));
337
- if (relevantInstances.length > 0) {
338
- filteredOps.push({
339
- operationId: op.operationId,
340
- instances: relevantInstances,
341
- timestamp: op.timestamp,
342
- queryset: op.queryset,
343
- type: op.type,
344
- status: op.status,
345
- args: op.args,
346
- });
347
- }
348
- }
349
- return filteredOps;
350
- }
351
- _filteredGroundTruth(pks, groundTruthArray) {
352
- const pkField = this.pkField;
353
- let groundTruthMap = new Map();
354
- for (const instance of groundTruthArray) {
355
- if (!instance || typeof instance !== "object" || !(pkField in instance)) {
356
- continue;
357
- }
358
- const pk = instance[pkField];
359
- if (!pks || pks.has(pk)) {
360
- groundTruthMap.set(pk, instance);
361
- }
362
- }
363
- return groundTruthMap;
364
- }
365
- applyOperation(operation, currentInstances) {
366
- const pkField = this.pkField;
367
- for (const instance of operation.instances) {
368
- if (!instance || typeof instance !== "object" || !(pkField in instance)) {
369
- console.warn(`[ModelStore ${this.modelClass.modelName}] Skipping instance ${instance} in operation ${operation.operationId} during applyOperation due to missing PK field '${String(pkField)}' or invalid format.`);
370
- continue;
371
- }
372
- let pk = instance[pkField];
373
- switch (operation.type) {
374
- case Type.CREATE:
375
- case Type.BULK_CREATE:
376
- if (!currentInstances.has(pk)) {
377
- currentInstances.set(pk, instance);
378
- }
379
- break;
380
- case Type.CHECKPOINT:
381
- case Type.UPDATE_INSTANCE:
382
- case Type.UPDATE: {
383
- const existing = currentInstances.get(pk);
384
- if (existing) {
385
- currentInstances.set(pk, { ...existing, ...instance });
386
- }
387
- else {
388
- const wasDeletedLocally = this.operations.some((op) => op.type === Type.DELETE &&
389
- op.status !== Status.REJECTED &&
390
- op.instances.some((inst) => inst && inst[pkField] === pk));
391
- if (!wasDeletedLocally) {
392
- currentInstances.set(pk, instance);
393
- }
394
- }
395
- break;
396
- }
397
- case Type.DELETE_INSTANCE:
398
- case Type.DELETE:
399
- currentInstances.delete(pk);
400
- break;
401
- default:
402
- console.error(`[ModelStore ${this.modelClass.modelName}] Unknown operation type: ${operation.type}`);
403
- }
404
- }
405
- return currentInstances;
406
- }
407
- getTrimmedOperations() {
408
- const twoMinutesAgo = Date.now() - 1000 * 60 * 2;
409
- return this.operations.filter((operation) => operation.timestamp > twoMinutesAgo);
410
- }
411
- getInflightOperations() {
412
- return this.operations.filter((operation) => operation.status != Status.CONFIRMED &&
413
- operation.status != Status.REJECTED);
414
- }
415
- // Pruning
416
- prune() {
417
- let renderedPks = this.render(null, false);
418
- this.setGroundTruth(renderedPks);
419
- this.setOperations(this.getInflightOperations());
420
- this.setCache(renderedPks);
421
- }
422
- /**
423
- * Prune model instances that aren't referenced by any queryset store.
424
- * This prevents unbounded cache growth from included nested models.
425
- *
426
- * @param {QuerysetStoreRegistry} querysetStoreRegistry - The registry to check for queryset references
427
- */
428
- pruneUnreferencedInstances(querysetStoreRegistry) {
429
- const pkField = this.pkField;
430
- const modelName = this.modelClass.modelName;
431
- // Collect all PKs that are needed by ANY queryset (permanent or temporary)
432
- const neededPks = new Set();
433
- for (const [semanticKey, store] of querysetStoreRegistry._stores.entries()) {
434
- // Check top-level PKs (groundTruthPks)
435
- if (store.modelClass.modelName === modelName) {
436
- store.groundTruthPks.forEach(pk => neededPks.add(pk));
437
- }
438
- // Check included PKs (nested models)
439
- if (store.includedPks.has(modelName)) {
440
- const includedPkSet = store.includedPks.get(modelName);
441
- includedPkSet.forEach(pk => neededPks.add(pk));
442
- }
443
- }
444
- // Filter ground truth to only keep needed PKs
445
- const filteredGroundTruth = this.groundTruthArray.filter(instance => {
446
- if (!instance || typeof instance !== 'object' || !(pkField in instance)) {
447
- return false;
448
- }
449
- return neededPks.has(instance[pkField]);
450
- });
451
- const removedCount = this.groundTruthArray.length - filteredGroundTruth.length;
452
- if (removedCount > 0) {
453
- console.log(`[ModelStore ${modelName}] Pruned ${removedCount} unreferenced instances (${filteredGroundTruth.length} remaining)`);
454
- this.groundTruthArray = filteredGroundTruth;
455
- // Update the cache to reflect the pruned data
456
- this.setCache(filteredGroundTruth);
457
- }
458
- }
459
- // Render methods
460
- render(pks = null, optimistic = true, useCache = true) {
461
- // When rendering specific pks, check cache first
462
- if (useCache && pks !== null) {
463
- const pksArray = Array.isArray(pks) ? pks : [pks];
464
- // Resolve temp pks to real pks for cache lookup
465
- const resolvedPks = pksArray.map(pk => resolveToRealPk(pk));
466
- const uncachedPks = [];
467
- for (const pk of resolvedPks) {
468
- if (!this._lastRenderedData.has(pk)) {
469
- uncachedPks.push(pk);
470
- }
471
- }
472
- // All pks were cached - return from cache
473
- if (uncachedPks.length === 0) {
474
- return this._renderFromCache(resolvedPks);
475
- }
476
- // Some or all pks need fresh render
477
- const pkField = this.pkField;
478
- if (uncachedPks.length < resolvedPks.length) {
479
- // Partial cache hit - get cached and render uncached
480
- const cachedPks = resolvedPks.filter(pk => this._lastRenderedData.has(pk));
481
- const cached = this._renderFromCache(cachedPks);
482
- const fresh = this._renderFresh(uncachedPks, optimistic);
483
- // Update cache for freshly rendered items
484
- for (const item of fresh) {
485
- if (item && item[pkField] != null) {
486
- this._lastRenderedData.set(item[pkField], item);
487
- }
488
- }
489
- return [...cached, ...fresh];
490
- }
491
- else {
492
- // All pks uncached - render fresh and update cache
493
- const fresh = this._renderFresh(resolvedPks, optimistic);
494
- // Update cache for freshly rendered items
495
- for (const item of fresh) {
496
- if (item && item[pkField] != null) {
497
- this._lastRenderedData.set(item[pkField], item);
498
- }
499
- }
500
- return fresh;
501
- }
502
- }
503
- // Full render (no cache, useCache=false, or pks=null for all)
504
- return this._renderFresh(pks, optimistic);
505
- }
506
- _renderFromCache(pks) {
507
- // Returns cached rendered data for the given pks
508
- // This method can be spied on in tests to track cache hits
509
- return pks
510
- .map(pk => this._lastRenderedData.get(pk))
511
- .filter(item => item !== null && item !== undefined);
512
- }
513
- _renderFresh(pks = null, optimistic = true) {
514
- const pksSet = pks === null
515
- ? null
516
- : pks instanceof Set
517
- ? pks
518
- : new Set(Array.isArray(pks) ? pks : [pks]);
519
- const renderedInstancesMap = this._filteredGroundTruth(pksSet, this.groundTruthArray);
520
- const relevantOperations = this._filteredOperations(pksSet, this.operations);
521
- for (const op of relevantOperations) {
522
- if (op.status !== Status.REJECTED &&
523
- (optimistic || op.status === Status.CONFIRMED)) {
524
- this.applyOperation(op, renderedInstancesMap);
525
- }
526
- }
527
- let result = Array.from(renderedInstancesMap.values());
528
- if (pks)
529
- this.updateCache(result, pksSet);
530
- if (isNil(pks))
531
- this.setCache(result);
532
- return result;
533
- }
534
- async sync(pks = null) {
535
- const storeIdForLog = this.modelClass.modelName;
536
- if (this.isSyncing)
537
- return;
538
- this.isSyncing = true;
539
- try {
540
- const currentPks = pks || this.groundTruthPks;
541
- if (currentPks.length === 0) {
542
- const trimmedOps = this.getTrimmedOperations();
543
- this.setOperations(trimmedOps);
544
- return;
545
- }
546
- const newGroundTruth = await this.fetchFn({
547
- pks: currentPks,
548
- modelClass: this.modelClass,
549
- });
550
- if (pks) {
551
- this.addToGroundTruth(newGroundTruth);
552
- return;
553
- }
554
- this.setGroundTruth(newGroundTruth);
555
- const trimmedOps = this.getTrimmedOperations();
556
- this.setOperations(trimmedOps);
557
- }
558
- catch (error) {
559
- console.error(`[ModelStore ${storeIdForLog}] Failed to sync ground truth:`, error);
560
- }
561
- finally {
562
- this.isSyncing = false;
563
- }
564
- }
565
- }