@abloatai/ablo 0.36.0 → 0.37.1

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 (597) hide show
  1. package/AGENTS.md +2 -2
  2. package/CHANGELOG.md +55 -2014
  3. package/NOTICE +2 -2
  4. package/README.md +45 -63
  5. package/assets/banner.png +0 -0
  6. package/dist/auth.d.ts +2 -0
  7. package/dist/auth.d.ts.map +1 -0
  8. package/dist/auth.js +2 -0
  9. package/dist/auth.js.map +1 -0
  10. package/dist/client.d.ts +3 -0
  11. package/dist/client.d.ts.map +1 -0
  12. package/dist/client.js +3 -0
  13. package/dist/client.js.map +1 -0
  14. package/dist/coordination.d.ts +2 -0
  15. package/dist/coordination.d.ts.map +1 -0
  16. package/dist/coordination.js +2 -0
  17. package/dist/coordination.js.map +1 -0
  18. package/dist/index.d.ts +3 -114
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +3 -163
  21. package/dist/index.js.map +1 -0
  22. package/dist/react.d.ts +4 -0
  23. package/dist/react.d.ts.map +1 -0
  24. package/dist/react.js +3 -0
  25. package/dist/react.js.map +1 -0
  26. package/dist/schema.d.ts +2 -0
  27. package/dist/schema.d.ts.map +1 -0
  28. package/dist/schema.js +2 -0
  29. package/dist/schema.js.map +1 -0
  30. package/dist/server.d.ts +2 -0
  31. package/dist/server.d.ts.map +1 -0
  32. package/dist/server.js +2 -0
  33. package/dist/server.js.map +1 -0
  34. package/dist/source-conformance.d.ts +2 -0
  35. package/dist/source-conformance.d.ts.map +1 -0
  36. package/dist/source-conformance.js +2 -0
  37. package/dist/source-conformance.js.map +1 -0
  38. package/dist/source-drizzle.d.ts +2 -0
  39. package/dist/source-drizzle.d.ts.map +1 -0
  40. package/dist/source-drizzle.js +2 -0
  41. package/dist/source-drizzle.js.map +1 -0
  42. package/dist/source-kysely.d.ts +2 -0
  43. package/dist/source-kysely.d.ts.map +1 -0
  44. package/dist/source-kysely.js +2 -0
  45. package/dist/source-kysely.js.map +1 -0
  46. package/dist/source-next.d.ts +2 -0
  47. package/dist/source-next.d.ts.map +1 -0
  48. package/dist/source-next.js +2 -0
  49. package/dist/source-next.js.map +1 -0
  50. package/dist/source.d.ts +2 -0
  51. package/dist/source.d.ts.map +1 -0
  52. package/dist/source.js +2 -0
  53. package/dist/source.js.map +1 -0
  54. package/dist/wire.d.ts +2 -0
  55. package/dist/wire.d.ts.map +1 -0
  56. package/dist/wire.js +2 -0
  57. package/dist/wire.js.map +1 -0
  58. package/docs/agents.md +1 -1
  59. package/docs/api-keys.md +7 -6
  60. package/docs/api.md +10 -10
  61. package/docs/client-behavior.md +5 -5
  62. package/docs/coordination.md +52 -62
  63. package/docs/data-sources.md +1 -1
  64. package/docs/examples/agent-human.md +4 -4
  65. package/docs/examples/ai-sdk-tool.md +1 -1
  66. package/docs/examples/existing-python-backend.md +15 -4
  67. package/docs/examples/nextjs.md +27 -6
  68. package/docs/examples/server-agent.md +2 -2
  69. package/docs/how-it-works.md +4 -4
  70. package/docs/identity.md +2 -1
  71. package/docs/integration-guide.md +24 -13
  72. package/docs/internal/README.md +18 -0
  73. package/docs/internal/agent-fleet-coordination-design.md +171 -0
  74. package/docs/internal/agent-orchestration.md +58 -0
  75. package/docs/internal/commit-identifiers.md +91 -0
  76. package/docs/internal/concurrency-open-decisions.md +37 -0
  77. package/docs/internal/data-source-reverse-channel.md +150 -0
  78. package/docs/internal/per-field-conflict-detection.md +165 -0
  79. package/docs/internal/postgres-replication.md +64 -0
  80. package/docs/internal/serializable-schema.md +119 -0
  81. package/docs/internal/structure.md +32 -0
  82. package/docs/mcp.md +2 -2
  83. package/docs/migration.md +3 -3
  84. package/docs/quickstart.md +2 -2
  85. package/docs/react.md +5 -5
  86. package/docs/schema-contract.md +3 -3
  87. package/docs/sessions.md +91 -37
  88. package/examples/README.md +2 -2
  89. package/examples/data-source/README.md +1 -1
  90. package/examples/data-source/ablo-driver.ts +1 -1
  91. package/examples/data-source/customer-server.ts +1 -1
  92. package/examples/data-source/run.ts +1 -1
  93. package/examples/data-source/schema.ts +1 -1
  94. package/examples/quickstart.ts +2 -2
  95. package/llms.txt +8 -8
  96. package/package.json +63 -166
  97. package/bin/ablo.cjs +0 -39
  98. package/dist/BaseSyncedStore.d.ts +0 -843
  99. package/dist/BaseSyncedStore.js +0 -1971
  100. package/dist/Database.d.ts +0 -323
  101. package/dist/Database.js +0 -1502
  102. package/dist/InstanceCache.d.ts +0 -237
  103. package/dist/InstanceCache.js +0 -1166
  104. package/dist/LazyReferenceCollection.d.ts +0 -177
  105. package/dist/LazyReferenceCollection.js +0 -461
  106. package/dist/Model.d.ts +0 -454
  107. package/dist/Model.js +0 -919
  108. package/dist/ModelRegistry.d.ts +0 -225
  109. package/dist/ModelRegistry.js +0 -539
  110. package/dist/NetworkMonitor.d.ts +0 -28
  111. package/dist/NetworkMonitor.js +0 -79
  112. package/dist/RuntimeContext.d.ts +0 -52
  113. package/dist/RuntimeContext.js +0 -80
  114. package/dist/SyncClient.d.ts +0 -541
  115. package/dist/SyncClient.js +0 -2202
  116. package/dist/adapters/alwaysOnline.d.ts +0 -14
  117. package/dist/adapters/alwaysOnline.js +0 -17
  118. package/dist/adapters/inMemoryStorage.d.ts +0 -31
  119. package/dist/adapters/inMemoryStorage.js +0 -110
  120. package/dist/ai-sdk/coordinatedTool.d.ts +0 -120
  121. package/dist/ai-sdk/coordinatedTool.js +0 -134
  122. package/dist/ai-sdk/coordinationContext.d.ts +0 -46
  123. package/dist/ai-sdk/coordinationContext.js +0 -106
  124. package/dist/ai-sdk/index.d.ts +0 -121
  125. package/dist/ai-sdk/index.js +0 -121
  126. package/dist/ai-sdk/wrap.d.ts +0 -65
  127. package/dist/ai-sdk/wrap.js +0 -39
  128. package/dist/auth/index.d.ts +0 -1
  129. package/dist/auth/index.js +0 -8
  130. package/dist/batching/index.d.ts +0 -55
  131. package/dist/batching/index.js +0 -147
  132. package/dist/client/Ablo.d.ts +0 -231
  133. package/dist/client/Ablo.js +0 -160
  134. package/dist/client/abloClient.d.ts +0 -309
  135. package/dist/client/abloClient.js +0 -13
  136. package/dist/client/clientPrelude.d.ts +0 -52
  137. package/dist/client/clientPrelude.js +0 -60
  138. package/dist/client/consoleLogger.d.ts +0 -35
  139. package/dist/client/consoleLogger.js +0 -44
  140. package/dist/client/coreClient.d.ts +0 -60
  141. package/dist/client/coreClient.js +0 -118
  142. package/dist/client/createInternalComponents.d.ts +0 -50
  143. package/dist/client/createInternalComponents.js +0 -98
  144. package/dist/client/createModelProxy.d.ts +0 -248
  145. package/dist/client/createModelProxy.js +0 -884
  146. package/dist/client/humans.d.ts +0 -69
  147. package/dist/client/humans.js +0 -78
  148. package/dist/client/modelRegistration.d.ts +0 -10
  149. package/dist/client/modelRegistration.js +0 -312
  150. package/dist/client/options.d.ts +0 -461
  151. package/dist/client/options.js +0 -7
  152. package/dist/client/reactiveEngine.d.ts +0 -53
  153. package/dist/client/reactiveEngine.js +0 -688
  154. package/dist/client/resourceTypes.d.ts +0 -12
  155. package/dist/client/resourceTypes.js +0 -10
  156. package/dist/client/schemaConfig.d.ts +0 -44
  157. package/dist/client/schemaConfig.js +0 -185
  158. package/dist/client/storeCluster.d.ts +0 -47
  159. package/dist/client/storeCluster.js +0 -118
  160. package/dist/client/storeLifecycle.d.ts +0 -61
  161. package/dist/client/storeLifecycle.js +0 -231
  162. package/dist/client/validateAbloOptions.d.ts +0 -42
  163. package/dist/client/validateAbloOptions.js +0 -43
  164. package/dist/client/wsMutationExecutor.d.ts +0 -27
  165. package/dist/client/wsMutationExecutor.js +0 -72
  166. package/dist/context.d.ts +0 -42
  167. package/dist/context.js +0 -81
  168. package/dist/coordination/ClaimLog.d.ts +0 -26
  169. package/dist/coordination/ClaimLog.js +0 -32
  170. package/dist/coordination/index.d.ts +0 -1
  171. package/dist/coordination/index.js +0 -8
  172. package/dist/core/index.d.ts +0 -33
  173. package/dist/core/index.js +0 -48
  174. package/dist/docs/catalog.d.ts +0 -72
  175. package/dist/docs/catalog.js +0 -230
  176. package/dist/docs/index.d.ts +0 -10
  177. package/dist/docs/index.js +0 -10
  178. package/dist/environment.d.ts +0 -1
  179. package/dist/environment.js +0 -8
  180. package/dist/interfaces/index.d.ts +0 -311
  181. package/dist/interfaces/index.js +0 -9
  182. package/dist/keys/index.d.ts +0 -1
  183. package/dist/keys/index.js +0 -8
  184. package/dist/mutators/RecordingMutation.d.ts +0 -36
  185. package/dist/mutators/RecordingMutation.js +0 -182
  186. package/dist/mutators/Transaction.d.ts +0 -40
  187. package/dist/mutators/Transaction.js +0 -58
  188. package/dist/mutators/UndoManager.d.ts +0 -258
  189. package/dist/mutators/UndoManager.js +0 -658
  190. package/dist/mutators/defineMutators.d.ts +0 -60
  191. package/dist/mutators/defineMutators.js +0 -18
  192. package/dist/mutators/inverseOp.d.ts +0 -126
  193. package/dist/mutators/inverseOp.js +0 -71
  194. package/dist/mutators/mutateActions.d.ts +0 -45
  195. package/dist/mutators/mutateActions.js +0 -105
  196. package/dist/mutators/readerActions.d.ts +0 -33
  197. package/dist/mutators/readerActions.js +0 -57
  198. package/dist/mutators/undoApply.d.ts +0 -51
  199. package/dist/mutators/undoApply.js +0 -117
  200. package/dist/policy/index.d.ts +0 -21
  201. package/dist/policy/index.js +0 -20
  202. package/dist/query/QueryProcessor.d.ts +0 -75
  203. package/dist/query/QueryProcessor.js +0 -255
  204. package/dist/query/client.d.ts +0 -64
  205. package/dist/query/client.js +0 -138
  206. package/dist/query/types.d.ts +0 -85
  207. package/dist/query/types.js +0 -16
  208. package/dist/react/AbloProvider.d.ts +0 -242
  209. package/dist/react/AbloProvider.js +0 -458
  210. package/dist/react/ClientSideSuspense.d.ts +0 -36
  211. package/dist/react/ClientSideSuspense.js +0 -17
  212. package/dist/react/DefaultFallback.d.ts +0 -24
  213. package/dist/react/DefaultFallback.js +0 -43
  214. package/dist/react/context.d.ts +0 -55
  215. package/dist/react/context.js +0 -29
  216. package/dist/react/createAbloReact.d.ts +0 -56
  217. package/dist/react/createAbloReact.js +0 -51
  218. package/dist/react/index.d.ts +0 -62
  219. package/dist/react/index.js +0 -69
  220. package/dist/react/internalContext.d.ts +0 -33
  221. package/dist/react/internalContext.js +0 -3
  222. package/dist/react/useAblo.d.ts +0 -82
  223. package/dist/react/useAblo.js +0 -120
  224. package/dist/react/useCurrentUserId.d.ts +0 -22
  225. package/dist/react/useCurrentUserId.js +0 -34
  226. package/dist/react/useErrorListener.d.ts +0 -20
  227. package/dist/react/useErrorListener.js +0 -38
  228. package/dist/react/useMutationFailureListener.d.ts +0 -26
  229. package/dist/react/useMutationFailureListener.js +0 -38
  230. package/dist/react/useMutators.d.ts +0 -56
  231. package/dist/react/useMutators.js +0 -84
  232. package/dist/react/useReactive.d.ts +0 -35
  233. package/dist/react/useReactive.js +0 -123
  234. package/dist/react/useSyncStatus.d.ts +0 -59
  235. package/dist/react/useSyncStatus.js +0 -76
  236. package/dist/react/useUndoScope.d.ts +0 -34
  237. package/dist/react/useUndoScope.js +0 -81
  238. package/dist/schema/coordination.d.ts +0 -112
  239. package/dist/schema/coordination.js +0 -133
  240. package/dist/schema/ddl.d.ts +0 -97
  241. package/dist/schema/ddl.js +0 -491
  242. package/dist/schema/ddlLock.d.ts +0 -35
  243. package/dist/schema/ddlLock.js +0 -46
  244. package/dist/schema/diff.d.ts +0 -225
  245. package/dist/schema/diff.js +0 -289
  246. package/dist/schema/generate.d.ts +0 -19
  247. package/dist/schema/generate.js +0 -86
  248. package/dist/schema/index.d.ts +0 -42
  249. package/dist/schema/index.js +0 -80
  250. package/dist/schema/queries.d.ts +0 -201
  251. package/dist/schema/queries.js +0 -144
  252. package/dist/schema/select.d.ts +0 -40
  253. package/dist/schema/select.js +0 -90
  254. package/dist/schema/serialize.d.ts +0 -115
  255. package/dist/schema/serialize.js +0 -265
  256. package/dist/schema/sugar.d.ts +0 -109
  257. package/dist/schema/sugar.js +0 -83
  258. package/dist/schema/syncDeltaRow.d.ts +0 -6
  259. package/dist/schema/syncDeltaRow.js +0 -6
  260. package/dist/server/adapter.d.ts +0 -173
  261. package/dist/server/adapter.js +0 -18
  262. package/dist/server/commit.d.ts +0 -107
  263. package/dist/server/commit.js +0 -1
  264. package/dist/server/index.d.ts +0 -14
  265. package/dist/server/index.js +0 -2
  266. package/dist/server/readConfig.d.ts +0 -80
  267. package/dist/server/readConfig.js +0 -8
  268. package/dist/server/storageMode.d.ts +0 -23
  269. package/dist/server/storageMode.js +0 -17
  270. package/dist/source/adapter.d.ts +0 -83
  271. package/dist/source/adapter.js +0 -24
  272. package/dist/source/adapters/drizzle.d.ts +0 -48
  273. package/dist/source/adapters/drizzle.js +0 -219
  274. package/dist/source/adapters/kysely.d.ts +0 -42
  275. package/dist/source/adapters/kysely.js +0 -205
  276. package/dist/source/adapters/kyselyMutationCore.d.ts +0 -76
  277. package/dist/source/adapters/kyselyMutationCore.js +0 -125
  278. package/dist/source/adapters/memory.d.ts +0 -13
  279. package/dist/source/adapters/memory.js +0 -130
  280. package/dist/source/adapters/prisma.d.ts +0 -63
  281. package/dist/source/adapters/prisma.js +0 -202
  282. package/dist/source/conformance.d.ts +0 -37
  283. package/dist/source/conformance.js +0 -215
  284. package/dist/source/connector.d.ts +0 -95
  285. package/dist/source/connector.js +0 -266
  286. package/dist/source/connectorProtocol.d.ts +0 -154
  287. package/dist/source/connectorProtocol.js +0 -163
  288. package/dist/source/contract.d.ts +0 -195
  289. package/dist/source/contract.js +0 -164
  290. package/dist/source/factory.d.ts +0 -92
  291. package/dist/source/factory.js +0 -286
  292. package/dist/source/idempotency.d.ts +0 -61
  293. package/dist/source/idempotency.js +0 -144
  294. package/dist/source/index.d.ts +0 -23
  295. package/dist/source/index.js +0 -30
  296. package/dist/source/migrations.d.ts +0 -21
  297. package/dist/source/migrations.js +0 -103
  298. package/dist/source/next.d.ts +0 -32
  299. package/dist/source/next.js +0 -25
  300. package/dist/source/pushQueue.d.ts +0 -134
  301. package/dist/source/pushQueue.js +0 -256
  302. package/dist/source/signing.d.ts +0 -92
  303. package/dist/source/signing.js +0 -162
  304. package/dist/source/types.d.ts +0 -401
  305. package/dist/source/types.js +0 -59
  306. package/dist/storeContract.d.ts +0 -145
  307. package/dist/storeContract.js +0 -12
  308. package/dist/stores/DatabaseManager.d.ts +0 -107
  309. package/dist/stores/DatabaseManager.js +0 -388
  310. package/dist/stores/ObjectStore.d.ts +0 -115
  311. package/dist/stores/ObjectStore.js +0 -393
  312. package/dist/stores/ObjectStoreContract.d.ts +0 -38
  313. package/dist/stores/ObjectStoreContract.js +0 -1
  314. package/dist/stores/StoreManager.d.ts +0 -114
  315. package/dist/stores/StoreManager.js +0 -304
  316. package/dist/stores/SyncActionStore.d.ts +0 -99
  317. package/dist/stores/SyncActionStore.js +0 -506
  318. package/dist/stores/openIDBWithTimeout.d.ts +0 -65
  319. package/dist/stores/openIDBWithTimeout.js +0 -153
  320. package/dist/stores/syncAction.d.ts +0 -26
  321. package/dist/stores/syncAction.js +0 -16
  322. package/dist/surface.d.ts +0 -36
  323. package/dist/surface.js +0 -75
  324. package/dist/sync/BootstrapFetcher.d.ts +0 -284
  325. package/dist/sync/BootstrapFetcher.js +0 -964
  326. package/dist/sync/ConnectionManager.d.ts +0 -8
  327. package/dist/sync/ConnectionManager.js +0 -8
  328. package/dist/sync/OnDemandLoader.d.ts +0 -231
  329. package/dist/sync/OnDemandLoader.js +0 -743
  330. package/dist/sync/SubscriptionManager.d.ts +0 -159
  331. package/dist/sync/SubscriptionManager.js +0 -243
  332. package/dist/sync/SyncWebSocket.d.ts +0 -173
  333. package/dist/sync/SyncWebSocket.js +0 -438
  334. package/dist/sync/awaitClaimGrant.d.ts +0 -6
  335. package/dist/sync/awaitClaimGrant.js +0 -6
  336. package/dist/sync/bootstrapApply.d.ts +0 -73
  337. package/dist/sync/bootstrapApply.js +0 -73
  338. package/dist/sync/commitFrames.d.ts +0 -8
  339. package/dist/sync/commitFrames.js +0 -8
  340. package/dist/sync/contextPorts.d.ts +0 -18
  341. package/dist/sync/contextPorts.js +0 -31
  342. package/dist/sync/createClaimStream.d.ts +0 -7
  343. package/dist/sync/createClaimStream.js +0 -7
  344. package/dist/sync/createPresenceStream.d.ts +0 -69
  345. package/dist/sync/createPresenceStream.js +0 -200
  346. package/dist/sync/createSnapshot.d.ts +0 -29
  347. package/dist/sync/createSnapshot.js +0 -118
  348. package/dist/sync/credentialLifecycle.d.ts +0 -7
  349. package/dist/sync/credentialLifecycle.js +0 -7
  350. package/dist/sync/deltaPipeline.d.ts +0 -114
  351. package/dist/sync/deltaPipeline.js +0 -278
  352. package/dist/sync/groupChange.d.ts +0 -116
  353. package/dist/sync/groupChange.js +0 -244
  354. package/dist/sync/participants.d.ts +0 -132
  355. package/dist/sync/participants.js +0 -346
  356. package/dist/sync/persistedPrefix.d.ts +0 -12
  357. package/dist/sync/persistedPrefix.js +0 -22
  358. package/dist/sync/schemaDrift.d.ts +0 -55
  359. package/dist/sync/schemaDrift.js +0 -53
  360. package/dist/sync/schemas.d.ts +0 -71
  361. package/dist/sync/schemas.js +0 -94
  362. package/dist/sync/syncCursor.d.ts +0 -40
  363. package/dist/sync/syncCursor.js +0 -55
  364. package/dist/sync/syncPlan.d.ts +0 -54
  365. package/dist/sync/syncPlan.js +0 -50
  366. package/dist/sync/wsFrameHandlers.d.ts +0 -8
  367. package/dist/sync/wsFrameHandlers.js +0 -8
  368. package/dist/syncLog/contract.d.ts +0 -20
  369. package/dist/syncLog/contract.js +0 -19
  370. package/dist/syncLog/index.d.ts +0 -1
  371. package/dist/syncLog/index.js +0 -1
  372. package/dist/transaction/ablo.d.ts +0 -88
  373. package/dist/transaction/ablo.js +0 -33
  374. package/dist/transaction/auth/apiKey.d.ts +0 -152
  375. package/dist/transaction/auth/apiKey.js +0 -419
  376. package/dist/transaction/auth/bootstrapScope.d.ts +0 -15
  377. package/dist/transaction/auth/bootstrapScope.js +0 -1
  378. package/dist/transaction/auth/capability.d.ts +0 -212
  379. package/dist/transaction/auth/capability.js +0 -224
  380. package/dist/transaction/auth/credentialEndpoint.d.ts +0 -61
  381. package/dist/transaction/auth/credentialEndpoint.js +0 -86
  382. package/dist/transaction/auth/credentialPolicy.d.ts +0 -148
  383. package/dist/transaction/auth/credentialPolicy.js +0 -125
  384. package/dist/transaction/auth/credentialSource.d.ts +0 -30
  385. package/dist/transaction/auth/credentialSource.js +0 -55
  386. package/dist/transaction/auth/hostedEndpoints.d.ts +0 -21
  387. package/dist/transaction/auth/hostedEndpoints.js +0 -21
  388. package/dist/transaction/auth/identity.d.ts +0 -55
  389. package/dist/transaction/auth/identity.js +0 -210
  390. package/dist/transaction/auth/index.d.ts +0 -162
  391. package/dist/transaction/auth/index.js +0 -304
  392. package/dist/transaction/auth/schemas.d.ts +0 -59
  393. package/dist/transaction/auth/schemas.js +0 -85
  394. package/dist/transaction/auth/sessionMint.d.ts +0 -28
  395. package/dist/transaction/auth/sessionMint.js +0 -85
  396. package/dist/transaction/coordination/awaitClaimGrant.d.ts +0 -56
  397. package/dist/transaction/coordination/awaitClaimGrant.js +0 -124
  398. package/dist/transaction/coordination/claimHeartbeatLoop.d.ts +0 -84
  399. package/dist/transaction/coordination/claimHeartbeatLoop.js +0 -108
  400. package/dist/transaction/coordination/claimMeta.d.ts +0 -49
  401. package/dist/transaction/coordination/claimMeta.js +0 -52
  402. package/dist/transaction/coordination/createClaimStream.d.ts +0 -64
  403. package/dist/transaction/coordination/createClaimStream.js +0 -475
  404. package/dist/transaction/coordination/events.d.ts +0 -74
  405. package/dist/transaction/coordination/events.js +0 -7
  406. package/dist/transaction/coordination/index.d.ts +0 -19
  407. package/dist/transaction/coordination/index.js +0 -45
  408. package/dist/transaction/coordination/locator.d.ts +0 -104
  409. package/dist/transaction/coordination/locator.js +0 -102
  410. package/dist/transaction/coordination/schema.d.ts +0 -1536
  411. package/dist/transaction/coordination/schema.js +0 -1177
  412. package/dist/transaction/coordination/targetConflict.d.ts +0 -2
  413. package/dist/transaction/coordination/targetConflict.js +0 -107
  414. package/dist/transaction/coordination/trace.d.ts +0 -78
  415. package/dist/transaction/coordination/trace.js +0 -138
  416. package/dist/transaction/durableWrites.d.ts +0 -62
  417. package/dist/transaction/durableWrites.js +0 -71
  418. package/dist/transaction/environment.d.ts +0 -105
  419. package/dist/transaction/environment.js +0 -108
  420. package/dist/transaction/errorCodes.d.ts +0 -403
  421. package/dist/transaction/errorCodes.js +0 -484
  422. package/dist/transaction/errors.d.ts +0 -428
  423. package/dist/transaction/errors.js +0 -686
  424. package/dist/transaction/footprint.d.ts +0 -111
  425. package/dist/transaction/footprint.js +0 -0
  426. package/dist/transaction/index.d.ts +0 -20
  427. package/dist/transaction/index.js +0 -20
  428. package/dist/transaction/keys/index.d.ts +0 -87
  429. package/dist/transaction/keys/index.js +0 -207
  430. package/dist/transaction/log/syncDeltaRow.d.ts +0 -158
  431. package/dist/transaction/log/syncDeltaRow.js +0 -95
  432. package/dist/transaction/logPosition.d.ts +0 -97
  433. package/dist/transaction/logPosition.js +0 -125
  434. package/dist/transaction/logger.d.ts +0 -16
  435. package/dist/transaction/logger.js +0 -7
  436. package/dist/transaction/observability.d.ts +0 -53
  437. package/dist/transaction/observability.js +0 -19
  438. package/dist/transaction/persistence.d.ts +0 -12
  439. package/dist/transaction/persistence.js +0 -11
  440. package/dist/transaction/plugin.d.ts +0 -285
  441. package/dist/transaction/plugin.js +0 -106
  442. package/dist/transaction/policy/types.d.ts +0 -217
  443. package/dist/transaction/policy/types.js +0 -126
  444. package/dist/transaction/resources/functionalUpdate.d.ts +0 -79
  445. package/dist/transaction/resources/functionalUpdate.js +0 -87
  446. package/dist/transaction/resources/httpResources.d.ts +0 -321
  447. package/dist/transaction/resources/httpResources.js +0 -7
  448. package/dist/transaction/resources/modelOperations.d.ts +0 -427
  449. package/dist/transaction/resources/modelOperations.js +0 -12
  450. package/dist/transaction/resources/mutationOptions.d.ts +0 -66
  451. package/dist/transaction/resources/mutationOptions.js +0 -9
  452. package/dist/transaction/resources/where.d.ts +0 -101
  453. package/dist/transaction/resources/where.js +0 -115
  454. package/dist/transaction/resources/writeOptionsSchema.d.ts +0 -47
  455. package/dist/transaction/resources/writeOptionsSchema.js +0 -73
  456. package/dist/transaction/schema/field.d.ts +0 -120
  457. package/dist/transaction/schema/field.js +0 -265
  458. package/dist/transaction/schema/fieldRef.d.ts +0 -38
  459. package/dist/transaction/schema/fieldRef.js +0 -11
  460. package/dist/transaction/schema/loadStrategy.d.ts +0 -45
  461. package/dist/transaction/schema/loadStrategy.js +0 -46
  462. package/dist/transaction/schema/model.d.ts +0 -379
  463. package/dist/transaction/schema/model.js +0 -123
  464. package/dist/transaction/schema/openapi.d.ts +0 -58
  465. package/dist/transaction/schema/openapi.js +0 -501
  466. package/dist/transaction/schema/relation.d.ts +0 -204
  467. package/dist/transaction/schema/relation.js +0 -104
  468. package/dist/transaction/schema/residency.d.ts +0 -29
  469. package/dist/transaction/schema/residency.js +0 -25
  470. package/dist/transaction/schema/roles.d.ts +0 -249
  471. package/dist/transaction/schema/roles.js +0 -230
  472. package/dist/transaction/schema/schema.d.ts +0 -351
  473. package/dist/transaction/schema/schema.js +0 -325
  474. package/dist/transaction/schema/tenancy.d.ts +0 -139
  475. package/dist/transaction/schema/tenancy.js +0 -190
  476. package/dist/transaction/transactionLayer.d.ts +0 -82
  477. package/dist/transaction/transactionLayer.js +0 -24
  478. package/dist/transaction/transactions/settlement/commitEnvelope.d.ts +0 -143
  479. package/dist/transaction/transactions/settlement/commitEnvelope.js +0 -161
  480. package/dist/transaction/transactions/settlement/httpCommitEnvelope.d.ts +0 -53
  481. package/dist/transaction/transactions/settlement/httpCommitEnvelope.js +0 -207
  482. package/dist/transaction/transactions/settlement/idempotencyKey.d.ts +0 -10
  483. package/dist/transaction/transactions/settlement/idempotencyKey.js +0 -9
  484. package/dist/transaction/transactions/settlement/pendingWrite.d.ts +0 -112
  485. package/dist/transaction/transactions/settlement/pendingWrite.js +0 -20
  486. package/dist/transaction/transport/commitFrames.d.ts +0 -90
  487. package/dist/transaction/transport/commitFrames.js +0 -134
  488. package/dist/transaction/transport/connectionManager.d.ts +0 -215
  489. package/dist/transaction/transport/connectionManager.js +0 -673
  490. package/dist/transaction/transport/credentialLifecycle.d.ts +0 -177
  491. package/dist/transaction/transport/credentialLifecycle.js +0 -324
  492. package/dist/transaction/transport/heartbeat.d.ts +0 -65
  493. package/dist/transaction/transport/heartbeat.js +0 -93
  494. package/dist/transaction/transport/httpClient.d.ts +0 -131
  495. package/dist/transaction/transport/httpClient.js +0 -146
  496. package/dist/transaction/transport/httpOptions.d.ts +0 -33
  497. package/dist/transaction/transport/httpOptions.js +0 -12
  498. package/dist/transaction/transport/httpTransport.d.ts +0 -8
  499. package/dist/transaction/transport/httpTransport.js +0 -1388
  500. package/dist/transaction/transport/networkProbe.d.ts +0 -84
  501. package/dist/transaction/transport/networkProbe.js +0 -207
  502. package/dist/transaction/transport/wsFrameHandlers.d.ts +0 -128
  503. package/dist/transaction/transport/wsFrameHandlers.js +0 -429
  504. package/dist/transaction/transport/wsTransport.d.ts +0 -574
  505. package/dist/transaction/transport/wsTransport.js +0 -1023
  506. package/dist/transaction/types/assertExact.d.ts +0 -17
  507. package/dist/transaction/types/assertExact.js +0 -1
  508. package/dist/transaction/types/global.d.ts +0 -107
  509. package/dist/transaction/types/global.js +0 -40
  510. package/dist/transaction/types/index.d.ts +0 -205
  511. package/dist/transaction/types/index.js +0 -56
  512. package/dist/transaction/types/modelData.d.ts +0 -10
  513. package/dist/transaction/types/modelData.js +0 -9
  514. package/dist/transaction/types/participant.d.ts +0 -20
  515. package/dist/transaction/types/participant.js +0 -10
  516. package/dist/transaction/types/streams.d.ts +0 -550
  517. package/dist/transaction/types/streams.js +0 -11
  518. package/dist/transaction/utils/asyncIterator.d.ts +0 -34
  519. package/dist/transaction/utils/asyncIterator.js +0 -135
  520. package/dist/transaction/utils/duration.d.ts +0 -50
  521. package/dist/transaction/utils/duration.js +0 -77
  522. package/dist/transaction/utils/json.d.ts +0 -57
  523. package/dist/transaction/utils/json.js +0 -276
  524. package/dist/transaction/wire/accountResponses.d.ts +0 -420
  525. package/dist/transaction/wire/accountResponses.js +0 -290
  526. package/dist/transaction/wire/auth.d.ts +0 -56
  527. package/dist/transaction/wire/auth.js +0 -63
  528. package/dist/transaction/wire/bootstrapReason.d.ts +0 -9
  529. package/dist/transaction/wire/bootstrapReason.js +0 -8
  530. package/dist/transaction/wire/claimEvent.d.ts +0 -76
  531. package/dist/transaction/wire/claimEvent.js +0 -73
  532. package/dist/transaction/wire/claims.d.ts +0 -530
  533. package/dist/transaction/wire/claims.js +0 -327
  534. package/dist/transaction/wire/commit.d.ts +0 -603
  535. package/dist/transaction/wire/commit.js +0 -321
  536. package/dist/transaction/wire/delta.d.ts +0 -250
  537. package/dist/transaction/wire/delta.js +0 -147
  538. package/dist/transaction/wire/errorEnvelope.d.ts +0 -72
  539. package/dist/transaction/wire/errorEnvelope.js +0 -123
  540. package/dist/transaction/wire/feedCursor.d.ts +0 -60
  541. package/dist/transaction/wire/feedCursor.js +0 -82
  542. package/dist/transaction/wire/feedEvent.d.ts +0 -204
  543. package/dist/transaction/wire/feedEvent.js +0 -65
  544. package/dist/transaction/wire/frames.d.ts +0 -194
  545. package/dist/transaction/wire/frames.js +0 -50
  546. package/dist/transaction/wire/inboundFrames.d.ts +0 -562
  547. package/dist/transaction/wire/inboundFrames.js +0 -116
  548. package/dist/transaction/wire/index.d.ts +0 -54
  549. package/dist/transaction/wire/index.js +0 -83
  550. package/dist/transaction/wire/listEnvelope.d.ts +0 -37
  551. package/dist/transaction/wire/listEnvelope.js +0 -42
  552. package/dist/transaction/wire/modelMutations.d.ts +0 -31
  553. package/dist/transaction/wire/modelMutations.js +0 -52
  554. package/dist/transaction/wire/modelResponses.d.ts +0 -85
  555. package/dist/transaction/wire/modelResponses.js +0 -43
  556. package/dist/transaction/wire/modelShape.d.ts +0 -78
  557. package/dist/transaction/wire/modelShape.js +0 -74
  558. package/dist/transaction/wire/protocol.d.ts +0 -38
  559. package/dist/transaction/wire/protocol.js +0 -38
  560. package/dist/transaction/wire/protocolVersion.d.ts +0 -73
  561. package/dist/transaction/wire/protocolVersion.js +0 -83
  562. package/dist/transactions/mutations/MutationQueue.d.ts +0 -661
  563. package/dist/transactions/mutations/MutationQueue.js +0 -2807
  564. package/dist/transactions/mutations/MutationStore.d.ts +0 -20
  565. package/dist/transactions/mutations/MutationStore.js +0 -53
  566. package/dist/transactions/mutations/UnconfirmedWrites.d.ts +0 -82
  567. package/dist/transactions/mutations/UnconfirmedWrites.js +0 -104
  568. package/dist/transactions/mutations/coalesceRules.d.ts +0 -58
  569. package/dist/transactions/mutations/coalesceRules.js +0 -140
  570. package/dist/transactions/mutations/commitLatency.d.ts +0 -52
  571. package/dist/transactions/mutations/commitLatency.js +0 -130
  572. package/dist/transactions/mutations/commitOutboxStore.d.ts +0 -28
  573. package/dist/transactions/mutations/commitOutboxStore.js +0 -26
  574. package/dist/transactions/mutations/commitPayload.d.ts +0 -165
  575. package/dist/transactions/mutations/commitPayload.js +0 -152
  576. package/dist/transactions/mutations/deltaConfirmation.d.ts +0 -63
  577. package/dist/transactions/mutations/deltaConfirmation.js +0 -235
  578. package/dist/transactions/mutations/durableWriteStore.d.ts +0 -14
  579. package/dist/transactions/mutations/durableWriteStore.js +0 -12
  580. package/dist/transactions/mutations/optimisticApply.d.ts +0 -49
  581. package/dist/transactions/mutations/optimisticApply.js +0 -65
  582. package/dist/transactions/mutations/replayValidation.d.ts +0 -187
  583. package/dist/transactions/mutations/replayValidation.js +0 -164
  584. package/dist/utils/mobxSetup.d.ts +0 -53
  585. package/dist/utils/mobxSetup.js +0 -330
  586. package/dist/views/QueryView.d.ts +0 -79
  587. package/dist/views/QueryView.js +0 -218
  588. package/dist/views/ViewRegistry.d.ts +0 -20
  589. package/dist/views/ViewRegistry.js +0 -55
  590. package/dist/views/incrementalView.d.ts +0 -45
  591. package/dist/views/incrementalView.js +0 -69
  592. package/dist/webhooks/events.d.ts +0 -43
  593. package/dist/webhooks/events.js +0 -42
  594. package/dist/webhooks/index.d.ts +0 -8
  595. package/dist/webhooks/index.js +0 -8
  596. package/dist/wire/index.d.ts +0 -1
  597. package/dist/wire/index.js +0 -8
@@ -1,743 +0,0 @@
1
- /**
2
- * Loads model rows on demand — the lazy-load path of the sync engine. When
3
- * something needs an entity that the initial bootstrap did not fetch,
4
- * {@link OnDemandLoader.fetch | fetch} finds it and populates the
5
- * in-memory {@link InstanceCache} so the rest of the engine can read it normally.
6
- *
7
- * A fetch resolves against three tiers in order, stopping at the first that can
8
- * answer:
9
- * 1. The object pool — if rows already in memory match the query, return them.
10
- * 2. Local storage — if matching rows exist there, hydrate the pool and return.
11
- * 3. The network — post the query to `/sync/query`, then hydrate both the pool
12
- * and local storage.
13
- *
14
- * Concurrent calls with the same query key share one in-flight promise, so a
15
- * burst of components mounting and asking for the same data on first paint
16
- * triggers a single fetch rather than one each.
17
- *
18
- * The coordinator does not replace the bootstrap (which fully syncs instantly
19
- * loaded models) or the live delta stream (pushed over the WebSocket). It only
20
- * fills the gap for lazily loaded models read by id or filter after the engine
21
- * is ready.
22
- */
23
- import { ModelScope } from '../InstanceCache.js';
24
- import { AbloValidationError } from '../transaction/errors.js';
25
- import { postQuery } from '../query/client.js';
26
- function timestampMs(value) {
27
- if (value instanceof Date) {
28
- const timestamp = value.getTime();
29
- return Number.isFinite(timestamp) ? timestamp : undefined;
30
- }
31
- if (typeof value === 'number' && Number.isFinite(value))
32
- return value;
33
- if (typeof value !== 'string')
34
- return undefined;
35
- const parsed = Date.parse(value);
36
- return Number.isNaN(parsed) ? undefined : parsed;
37
- }
38
- /**
39
- * A query response is a snapshot, not an ordered delta. It may have started
40
- * before a local optimistic write and completed after it. Only treat the row
41
- * as authoritative over an existing model when its server timestamp is newer;
42
- * missing timestamps retain the legacy merge behavior for custom sources that
43
- * do not expose `updatedAt`.
44
- */
45
- function snapshotDoesNotAdvanceModel(data, model) {
46
- const incoming = timestampMs(data.updatedAt);
47
- const resident = timestampMs(model.updatedAt);
48
- return incoming !== undefined && resident !== undefined && incoming <= resident;
49
- }
50
- export class OnDemandLoader {
51
- opts;
52
- inFlight = new Map();
53
- /**
54
- * Query keys with a background confirm currently in flight. Distinct from
55
- * {@link inFlight} (which dedupes *blocking* callers awaiting the same
56
- * fetch): this set dedupes the fire-and-forget network confirm kicked off
57
- * after a local-first read returns cached data, so a burst of mounts that
58
- * all hit the warm pool/IDB don't each spawn their own redundant fetch.
59
- */
60
- revalidating = new Set();
61
- /**
62
- * Query keys that have been satisfied from the server at least once this
63
- * session. Once a key is here, repeat reads serve purely from the pool with
64
- * no network round-trip: the WebSocket delta stream keeps those pool rows
65
- * fresh, so re-running the HTTP query would be redundant polling. This ledger
66
- * is what stops an already-open view from re-querying on every navigation.
67
- *
68
- * Cleared on reconnect (see {@link invalidate}) so that, after a connection
69
- * drop where deltas may have been missed, the next read re-confirms once.
70
- */
71
- hydratedKeys = new Set();
72
- authTokenProvider = null;
73
- /**
74
- * The credential-recovery hook (the store's `recoverFromAuthRejection`),
75
- * late-bound like {@link setAuthTokenProvider} because the store does not
76
- * exist yet when the coordinator is constructed. Handed to `postQuery` so a
77
- * 401 on the lazy lane re-mints through the same single-flight path the
78
- * WebSocket probe uses, then replays the query once — instead of silently
79
- * returning empty rows against an expired key.
80
- */
81
- credentialRecovery = null;
82
- constructor(opts) {
83
- this.opts = opts;
84
- // Reading the deprecated `getCapabilityToken` is deliberate: it's the
85
- // back-compat shim that keeps older callers who still pass it working
86
- // until they migrate to `getAuthToken`.
87
- // eslint-disable-next-line @typescript-eslint/no-deprecated
88
- this.authTokenProvider = opts.getAuthToken ?? opts.getCapabilityToken ?? null;
89
- }
90
- /**
91
- * Late-bind the auth token getter. Browser cookie consumers can omit this;
92
- * bearer consumers need it so lazy HTTP queries use the same credential as
93
- * bootstrap and the WebSocket.
94
- */
95
- setAuthTokenProvider(provider) {
96
- this.authTokenProvider = provider;
97
- }
98
- /** Late-bind the auth-recovery backbone. See {@link credentialRecovery}. */
99
- setCredentialRecovery(recover) {
100
- this.credentialRecovery = recover;
101
- }
102
- /** @deprecated Use `setAuthTokenProvider`. */
103
- setCapabilityTokenProvider(provider) {
104
- this.setAuthTokenProvider(provider);
105
- }
106
- /**
107
- * Fetch matching rows for a model, hydrating the pool from IDB or
108
- * network if not already present. Idempotent and single-flight
109
- * deduped on the (modelName, where, orderBy, limit) tuple.
110
- */
111
- async fetch(modelName, options) {
112
- const typename = this.resolveTypename(modelName);
113
- const ModelClass = this.opts.registry.getModelByName(typename)
114
- ?? this.opts.registry.getModelByName(modelName);
115
- if (!ModelClass) {
116
- throw new AbloValidationError(`OnDemandLoader.fetch: unknown model "${modelName}" — ` +
117
- `not registered in the schema.`, { code: 'model_not_registered' });
118
- }
119
- const clauses = normalizeWhere(options?.where);
120
- const queryKey = stableKey(modelName, clauses, options?.orderBy, options?.limit, options?.expand);
121
- // Single-flight: an identical hydration is already in flight.
122
- const inFlight = this.inFlight.get(queryKey);
123
- if (inFlight)
124
- return inFlight;
125
- const work = this.runFetch(modelName, typename, ModelClass, clauses, options, queryKey);
126
- this.inFlight.set(queryKey, work);
127
- // The rejection (if any) reaches callers via the returned `work`; this
128
- // side-chain only clears the single-flight slot. Without the trailing
129
- // catch, `.finally()` mirrors the rejection into a second, unhandled
130
- // promise even when every caller handles theirs.
131
- void work
132
- .finally(() => {
133
- this.inFlight.delete(queryKey);
134
- })
135
- .catch(() => undefined);
136
- return work;
137
- }
138
- async runFetch(modelName, typename, ModelClass, clauses, options, queryKey) {
139
- // `{ type: 'complete' }` is the only way to force a server round-trip:
140
- // read-after-write certainty. Every other read is local-first.
141
- const explicitComplete = options?.type === 'complete';
142
- const expand = options?.expand;
143
- const hasExpand = !!(expand && expand.length > 0);
144
- // Fast path — this exact query was already satisfied from the server this
145
- // session. The WebSocket delta stream has kept the pool fresh since, so a
146
- // repeat read needs no network: serve straight from local. This is what
147
- // stops an already-open view from re-querying on every navigation when no
148
- // new deltas have arrived.
149
- if (!explicitComplete && this.hydratedKeys.has(queryKey)) {
150
- return applyLimit(await this.readLocal(modelName, typename, ModelClass, clauses, hasExpand, expand), options?.limit);
151
- }
152
- // Not yet hydrated (or an explicit complete read). For a non-complete read
153
- // without expand, if there is anything local to show (a warm pool, or local
154
- // storage after a reload), hand it back immediately and confirm with the
155
- // server once in the background — then mark the key hydrated so subsequent
156
- // reads are purely local. First paint never blocks on the network.
157
- //
158
- // Expand queries are deliberately excluded here: the presence of a primary
159
- // row says nothing about whether its relations are loaded. Returning the
160
- // parent now would surface it with empty children, letting a readiness flag
161
- // flip before the children exist. So an un-hydrated expand query falls
162
- // through to the blocking fetch that brings parent and children together;
163
- // the second open is served by the fast path.
164
- if (!explicitComplete && !hasExpand) {
165
- const local = await this.readLocal(modelName, typename, ModelClass, clauses, hasExpand, expand);
166
- if (local.length > 0) {
167
- this.scheduleHydratingFetch(queryKey, modelName, typename, clauses, options);
168
- return applyLimit(local, options?.limit);
169
- }
170
- }
171
- // Cold cache, or caller demanded server-confirmed state: block on the
172
- // network, then mark this query hydrated so future reads serve local.
173
- const networkModels = await this.fetchFromNetwork(modelName, typename, clauses, options);
174
- this.hydratedKeys.add(queryKey);
175
- if (networkModels.length > 0)
176
- return applyLimit(networkModels, options?.limit);
177
- // Network returned nothing — fall back to whatever's local (e.g. a
178
- // complete read whose server result was empty but IDB still holds rows).
179
- return applyLimit(await this.readLocal(modelName, typename, ModelClass, clauses, hasExpand, expand), options?.limit);
180
- }
181
- /**
182
- * Read a query's rows from local storage only — pool first, then IndexedDB
183
- * on a pool miss (cold start after reload, or LRU eviction), hydrating the
184
- * pool from IDB as a side effect. Resolves requested `expand` relations from
185
- * their own local stores too. Never touches the network.
186
- */
187
- async readLocal(modelName, typename, ModelClass, clauses, hasExpand, expand) {
188
- let local = scanPool(this.opts.objectPool, ModelClass, clauses);
189
- if (local.length === 0) {
190
- const fromIdb = await scanIdb(this.opts.database, typename, clauses);
191
- const idbModels = fromIdb
192
- .map((raw) => this.hydrateOne(raw, typename))
193
- .filter((m) => m !== null);
194
- if (idbModels.length > 0) {
195
- this.opts.objectPool.addBatch(idbModels, ModelScope.live);
196
- local = idbModels;
197
- }
198
- }
199
- if (hasExpand && expand && local.length > 0) {
200
- await this.hydrateExpandedFromLocal(modelName, local.map((m) => m.id), expand);
201
- }
202
- return local;
203
- }
204
- /**
205
- * Drop the hydration ledger so the next read of each query re-confirms with
206
- * the server. Called on reconnect — after a connection drop, deltas may have
207
- * been missed, so the "WS keeps the pool fresh" assumption no longer holds
208
- * until a fresh fetch (or the engine's delta catch-up) reconciles.
209
- */
210
- invalidate() {
211
- this.hydratedKeys.clear();
212
- }
213
- /**
214
- * Run the network leg of a fetch: query the server, hydrate primary rows
215
- * (and any expanded relations) into the pool, and persist them to IDB.
216
- * Shared by the blocking path (`runFetch` step 3) and the background
217
- * revalidation kicked off after an `'unknown'` local hit.
218
- */
219
- async fetchFromNetwork(modelName, typename, clauses, options) {
220
- const networkRows = await this.queryNetwork(modelName, clauses, options);
221
- const networkModels = networkRows
222
- // Strict: a row the server returned whose type name this client never
223
- // registered is a genuine schema collision (the pushed schema differs
224
- // from the local one). Throw here, naming the cause, rather than silently
225
- // dropping the row and failing downstream as `entity_not_found`.
226
- .map((raw) => this.hydrateOne(raw, typename, { strict: true }))
227
- .filter((m) => m !== null);
228
- if (networkModels.length > 0) {
229
- this.opts.objectPool.addBatch(networkModels, ModelScope.live);
230
- // Background IDB write — don't block the caller. Expanded children are
231
- // persisted to their own stores inside `queryNetwork`/`hydrateExpanded`.
232
- void this.persistToIdb(modelName, networkRows);
233
- }
234
- return networkModels;
235
- }
236
- /**
237
- * Fires the single background confirm for a query that was just served from
238
- * local cache but is not hydrated yet. On success the key is marked hydrated,
239
- * so every later read serves purely from local with no network until a
240
- * reconnect invalidates the ledger. Deduped per query key so a render burst
241
- * does not stampede. Errors are swallowed — the caller already has a usable
242
- * local snapshot, and a failed confirm leaves the key un-hydrated so the next
243
- * read simply tries again.
244
- */
245
- scheduleHydratingFetch(queryKey, modelName, typename, clauses, options) {
246
- if (this.revalidating.has(queryKey))
247
- return;
248
- this.revalidating.add(queryKey);
249
- void this.fetchFromNetwork(modelName, typename, clauses, options)
250
- .then(() => {
251
- this.hydratedKeys.add(queryKey);
252
- })
253
- .catch(() => undefined)
254
- .finally(() => {
255
- this.revalidating.delete(queryKey);
256
- });
257
- }
258
- /**
259
- * Hydrate a parent's `hasMany`/`hasOne` relations from their OWN local
260
- * stores (pool first, then IndexedDB by the FK secondary index) into the
261
- * pool. The mirror of {@link hydrateExpanded} for the local read path:
262
- * `hydrateExpanded` walks server-JOINed nested rows, this walks the child
263
- * model's own store keyed by the relation's foreign key.
264
- *
265
- * Fully schema-driven via the relation's `target` + `foreignKey` — no
266
- * per-model special-casing. `belongsTo` relations are skipped: those point
267
- * at a single parent (the inverse direction), already covered by the
268
- * primary scan when that parent is itself the fetched model.
269
- */
270
- async hydrateExpandedFromLocal(parentModelName, parentIds, relationNames) {
271
- if (parentIds.length === 0)
272
- return;
273
- const parentDef = this.getModelDef(parentModelName);
274
- if (!parentDef?.relations)
275
- return;
276
- for (const rel of relationNames) {
277
- const relDef = parentDef.relations[rel];
278
- if (!relDef)
279
- continue;
280
- if (relDef.type !== 'hasMany' && relDef.type !== 'hasOne')
281
- continue;
282
- const targetKey = relDef.target;
283
- const foreignKey = relDef.foreignKey;
284
- if (!targetKey || !foreignKey)
285
- continue;
286
- const targetTypename = this.resolveTypename(targetKey);
287
- // Skip parents whose children are already pool-resident (O(1) when the
288
- // FK is indexed). Falls through to a local read for the rest.
289
- const missing = parentIds.filter((pid) => this.opts.objectPool.getByForeignKey(targetTypename, foreignKey, pid).length === 0);
290
- if (missing.length === 0)
291
- continue;
292
- const rows = await this.readChildrenLocal(targetTypename, foreignKey, missing);
293
- const models = rows
294
- .map((raw) => this.hydrateOne(this.stampTypename(raw, targetTypename), targetTypename))
295
- .filter((m) => m !== null);
296
- if (models.length > 0) {
297
- this.opts.objectPool.addBatch(models, ModelScope.live);
298
- }
299
- }
300
- }
301
- /**
302
- * Read a child model's rows from local storage by foreign key.
303
- *
304
- * Uses the FK secondary index (O(matches) per parent) only when the schema
305
- * declares one — `getAllFromIndex` resolves `[]` for a missing index rather
306
- * than throwing, so the decision is made up front from the registry, not by
307
- * catching. Unindexed FKs — and in-memory stores, which carry no secondary
308
- * indexes at all — fall back to a single full-store scan filtered in JS.
309
- */
310
- async readChildrenLocal(childTypename, foreignKey, parentIds) {
311
- const store = this.opts.database.getStore(childTypename);
312
- if (!store)
313
- return [];
314
- const isIndexed = this.opts.registry.getIndexedProperties(childTypename).includes(foreignKey);
315
- if (isIndexed) {
316
- const collected = [];
317
- for (const pid of parentIds) {
318
- const rows = await store.getAllFromIndex(foreignKey, pid);
319
- if (Array.isArray(rows))
320
- collected.push(...rows);
321
- }
322
- // A non-empty result means the index is live (browser IDB). Empty can
323
- // mean "no children" OR "no physical index" (in-memory) — fall through
324
- // to the scan so the in-memory/SSR path stays correct.
325
- if (collected.length > 0)
326
- return collected;
327
- }
328
- try {
329
- const all = await store.getAll();
330
- if (!Array.isArray(all))
331
- return [];
332
- const idSet = new Set(parentIds);
333
- return all.filter((r) => idSet.has((r)[foreignKey]));
334
- }
335
- catch {
336
- return [];
337
- }
338
- }
339
- /** Typed accessor for a model's schema definition (typename + relations). */
340
- getModelDef(modelName) {
341
- return this.opts.schema.models?.[modelName];
342
- }
343
- hydrateOne(raw, typename, opts) {
344
- if (!raw || typeof raw !== 'object')
345
- return null;
346
- const obj = raw;
347
- if (typeof obj.id !== 'string')
348
- return null;
349
- if (this.opts.objectPool.has(obj.id)) {
350
- // Keep the existing instance alive when a query refreshes it. A query
351
- // can carry fresher server state after a missed delta, but unlike the
352
- // ordered delta stream it can also finish late with an older snapshot;
353
- // the reconciliation below distinguishes those cases before applying.
354
- const existing = this.opts.objectPool.get(obj.id);
355
- if (existing) {
356
- const stamped = this.stampTypename(obj, typename);
357
- // Network queries are unordered snapshots. A request that began before
358
- // an optimistic resize can return afterward with the old row; applying
359
- // it here would visibly snap the live model back, and the matching
360
- // authoritative delta cannot repair it because own echoes are
361
- // intentionally suppressed. Keep a newer resident row intact.
362
- if (snapshotDoesNotAdvanceModel(stamped, existing))
363
- return existing;
364
- // If the source has no comparable timestamp, retain pending local
365
- // fields while accepting unrelated server fields. This is the same
366
- // local-first merge contract used by SyncClient's delta resolver.
367
- const localChanges = existing.getChanges();
368
- existing.updateFromData(Object.keys(localChanges).length > 0
369
- ? { ...stamped, ...localChanges, updatedAt: existing.updatedAt }
370
- : stamped);
371
- return existing;
372
- }
373
- return null;
374
- }
375
- // Stamp the known relation typename onto the row when the source
376
- // (IndexedDB rows, sometimes network rows) didn't carry one. Without
377
- // this, InstanceCache.createFromData falls through to the 'Unknown'
378
- // model-name branch and emits the
379
- // "InstanceCache.createFromData: No model identifier found" warning,
380
- // failing to hydrate the entity from cache (network path then has to
381
- // re-populate it). The typename comes from the schema relation
382
- // (`'Block'`, `'Section'`, etc.) so no guessing involved.
383
- const stamped = this.stampTypename(obj, typename);
384
- return this.opts.objectPool.createFromData(stamped, undefined, opts);
385
- }
386
- /**
387
- * Stamp `__typename` onto a row when it's known (from the schema's
388
- * relation target). Strips the mangled `_Typename` key the
389
- * `postgres.camel` driver leaves behind when the server's SQL
390
- * bakes `__typename` into a JSONB literal — the driver's
391
- * snake↔camel transform misreads `__typename` as `_typename` with
392
- * a leading underscore and produces `_Typename`. InstanceCache only
393
- * recognises `__typename`, so without this step nested rows fall
394
- * through to the 'Unknown' branch and never instantiate.
395
- */
396
- stampTypename(item, typename) {
397
- if (!item || typeof item !== 'object' || !typename)
398
- return item;
399
- const obj = item;
400
- if (obj.__typename === typename)
401
- return obj;
402
- // Drop the driver-mangled `_Typename` AND any row-carried `__typename`
403
- // that disagrees with the schema's: these rows were returned FOR this
404
- // model's query, so the schema typename is correct by construction — and
405
- // without stripping it, the spread would put the row's variant (a server
406
- // echoing the schema KEY `tasks` instead of the typename `Task`) back on
407
- // top of the stamp, sending hydration to the strict unknown-model error.
408
- const { _Typename: _dropMangled, __typename: _dropRowVariant, ...rest } = obj;
409
- void _dropMangled;
410
- void _dropRowVariant;
411
- return { __typename: typename, ...rest };
412
- }
413
- async queryNetwork(modelName, clauses, options) {
414
- const typename = this.resolveTypename(modelName);
415
- const orderEntries = options?.orderBy ? Object.entries(options.orderBy) : [];
416
- const firstOrder = orderEntries[0];
417
- const query = {
418
- model: typename,
419
- where: clauses.map((c) => this.columnizeClause(modelName, c)),
420
- ...(firstOrder
421
- ? {
422
- orderBy: this.columnizeField(modelName, firstOrder[0]),
423
- order: firstOrder[1] ?? 'asc',
424
- }
425
- : {}),
426
- ...(options?.limit ? { limit: options.limit } : {}),
427
- ...(options?.expand && options.expand.length > 0
428
- ? { related: options.expand }
429
- : {}),
430
- };
431
- const result = await postQuery({
432
- baseUrl: this.opts.baseUrl,
433
- getAuthToken: this.authTokenProvider ?? undefined,
434
- recoverCredential: this.credentialRecovery ?? undefined,
435
- runtime: this.opts.runtime,
436
- }, { queries: [query] });
437
- const rows = Array.isArray(result.results[0]) ? result.results[0] : [];
438
- // Normalize: wire rows lack `__typename` when the server elides it.
439
- const normalized = rows.map((row) => {
440
- if (row && typeof row === 'object' && !('__typename' in row)) {
441
- return { __typename: typename, ...row };
442
- }
443
- return row;
444
- });
445
- // Expand: server returns related entities nested under each row
446
- // (`row.blocks = [{...}, ...]`). Walk the nested shape, stamp the
447
- // typename from the schema's relation metadata (the server bakes
448
- // `__typename` into the JSONB but the postgres.camel driver
449
- // mangles it to `_Typename` mid-flight, so client-side stamping
450
- // is the only reliable path), hydrate each related row into its
451
- // own typed pool, then leave the nested arrays in place on the
452
- // primary row.
453
- if (options?.expand && options.expand.length > 0) {
454
- this.hydrateExpanded(modelName, normalized, options.expand);
455
- }
456
- return normalized;
457
- }
458
- /**
459
- * Hydrate nested expanded rows. Resolves each relation's target
460
- * typename via the schema and stamps `__typename` on every nested
461
- * row before passing to `hydrateOne` — the server's JSONB
462
- * `__typename` field gets mangled by `postgres.camel` (`__typename`
463
- * → `_Typename`), so the SDK can't trust whatever string lands.
464
- */
465
- hydrateExpanded(parentModelName, rows, relationNames) {
466
- const parentDef = this.getModelDef(parentModelName);
467
- for (const row of rows) {
468
- if (!row || typeof row !== 'object')
469
- continue;
470
- const obj = row;
471
- for (const rel of relationNames) {
472
- const nested = obj[rel];
473
- if (!nested)
474
- continue;
475
- // Resolve target typename via parent's relations map.
476
- const relDef = parentDef?.relations?.[rel];
477
- const targetKey = relDef?.target;
478
- const targetTypename = targetKey ? this.resolveTypename(targetKey) : undefined;
479
- const items = Array.isArray(nested) ? nested : [nested];
480
- const models = [];
481
- const stampedItems = [];
482
- for (const item of items) {
483
- const stamped = this.stampTypename(item, targetTypename);
484
- stampedItems.push(stamped);
485
- const m = this.hydrateOne(stamped);
486
- if (m)
487
- models.push(m);
488
- }
489
- if (models.length > 0) {
490
- this.opts.objectPool.addBatch(models, ModelScope.live);
491
- }
492
- // Persist expanded children to their OWN typed store so they survive
493
- // reload and can be re-served by `hydrateExpandedFromLocal` — without
494
- // this, expand-fetched relations live only inside the parent's row
495
- // and are lost to a lazy child query after a cold start.
496
- if (stampedItems.length > 0 && targetKey) {
497
- void this.persistToIdb(targetKey, stampedItems);
498
- }
499
- }
500
- }
501
- }
502
- async persistToIdb(modelName, rows) {
503
- const store = this.opts.database.getStore(this.resolveTypename(modelName));
504
- if (!store)
505
- return;
506
- for (const row of rows) {
507
- try {
508
- await store.put(row);
509
- }
510
- catch {
511
- // IDB writes are best-effort — a transient quota/transaction
512
- // failure shouldn't break the hydration's primary purpose.
513
- }
514
- }
515
- }
516
- resolveTypename(modelName) {
517
- // Schema is the source of truth for wire typenames. The model proxy
518
- // is keyed by camelCase plural (`blocks`) but the wire query +
519
- // InstanceCache typeIndex use the typename (`Block`).
520
- const def = this.opts.schema
521
- .models?.[modelName];
522
- return def?.typename ?? modelName;
523
- }
524
- columnizeField(modelName, field) {
525
- const fields = this.opts.schema.models?.[modelName]?.fields;
526
- if (fields) {
527
- const direct = fields[field]?.column;
528
- if (direct)
529
- return direct;
530
- for (const [fieldName, meta] of Object.entries(fields)) {
531
- const conventional = columnize(fieldName);
532
- if (field === fieldName || field === conventional || field === meta.column) {
533
- return meta.column ?? conventional;
534
- }
535
- }
536
- }
537
- return /[A-Z]/.test(field) ? columnize(field) : field;
538
- }
539
- columnizeClause(modelName, clause) {
540
- const finalCol = this.columnizeField(modelName, clause[0]);
541
- if (clause.length === 2)
542
- return [finalCol, clause[1]];
543
- return [finalCol, clause[1], clause[2]];
544
- }
545
- }
546
- // ── Helpers ────────────────────────────────────────────────────────────
547
- function stableKey(modelName, clauses, orderBy, limit, expand) {
548
- // Sort clauses by their stringified form so caller order doesn't
549
- // produce different dedup keys for semantically identical queries.
550
- const sorted = [...clauses].map((c) => [...c]).sort((a, b) => {
551
- const ka = JSON.stringify(a);
552
- const kb = JSON.stringify(b);
553
- return ka < kb ? -1 : ka > kb ? 1 : 0;
554
- });
555
- // Expand is part of the query identity: `sections where report=r1` and the same
556
- // with `expand:['blocks']` hydrate different data, so they must not share a
557
- // ledger/dedup key. Sorted so relation order doesn't fork the key.
558
- const expandKey = expand && expand.length > 0 ? [...expand].sort() : undefined;
559
- return JSON.stringify({ modelName, where: sorted, orderBy, limit, expand: expandKey });
560
- }
561
- function applyLimit(arr, limit) {
562
- return typeof limit === 'number' ? arr.slice(0, limit) : arr;
563
- }
564
- function scanPool(pool, ModelClass, clauses) {
565
- const all = pool.getByType(ModelClass);
566
- if (clauses.length === 0)
567
- return all;
568
- return all.filter((entity) => matchesClauses(entity, clauses));
569
- }
570
- async function scanIdb(database, modelName, clauses) {
571
- const store = database.getStore(modelName);
572
- if (!store)
573
- return [];
574
- // Fast path: a single equality `id` lookup hits the primary key.
575
- const eqClauses = extractEqClauses(clauses);
576
- if (clauses.length === 1 && eqClauses.id !== undefined && typeof eqClauses.id === 'string') {
577
- try {
578
- const row = await store.get(eqClauses.id);
579
- return row ? [row] : [];
580
- }
581
- catch {
582
- return [];
583
- }
584
- }
585
- // Index-aware path: when every clause is equality and exactly one
586
- // non-id string column is constrained, hit that column's index for
587
- // an O(matches) read. Anything involving LIKE/ILIKE/ranges falls
588
- // through to full-scan + filter.
589
- if (clausesAreAllEquality(clauses)) {
590
- const indexedKeys = Object.keys(eqClauses).filter((k) => k !== 'id' && typeof eqClauses[k] === 'string');
591
- const idxKey = indexedKeys.length === 1 ? indexedKeys[0] : undefined;
592
- if (idxKey !== undefined) {
593
- try {
594
- const rows = await store.getAllFromIndex(idxKey, eqClauses[idxKey]);
595
- if (Array.isArray(rows)) {
596
- return rows.filter((r) => matchesClauses(r, clauses));
597
- }
598
- }
599
- catch {
600
- // index doesn't exist — fall through to full-scan path.
601
- }
602
- }
603
- }
604
- try {
605
- const rows = await store.getAll();
606
- return Array.isArray(rows)
607
- ? rows.filter((r) => matchesClauses(r, clauses))
608
- : [];
609
- }
610
- catch {
611
- return [];
612
- }
613
- }
614
- /**
615
- * Normalize `LoadWhere<T>` input to the canonical `readonly WhereClause[]`
616
- * tuple form used throughout `runFetch`. Tuple inputs pass through; object
617
- * inputs become one `['col', '=', val]` or `['col', 'IN', vals]` per key.
618
- *
619
- * Detection: an array whose first element is itself an array is treated
620
- * as tuple form. Object form is the fallback.
621
- *
622
- * Exported so callers can pre-normalize (e.g., for tests, or to inspect
623
- * the canonical clauses before passing them to `load`/`subscribe`).
624
- */
625
- export function normalizeWhere(where) {
626
- if (where == null)
627
- return [];
628
- if (Array.isArray(where)) {
629
- // Tuple form — assumed to already use server-side column names.
630
- return where;
631
- }
632
- if (typeof where === 'object') {
633
- const obj = where;
634
- return Object.entries(obj).map(([key, value]) => {
635
- if (Array.isArray(value)) {
636
- return [key, 'IN', value];
637
- }
638
- return [key, value];
639
- });
640
- }
641
- return [];
642
- }
643
- /** Equality-only subset of clauses, keyed by column. Used by IDB fast paths. */
644
- function extractEqClauses(clauses) {
645
- const out = {};
646
- for (const c of clauses) {
647
- if (c.length === 2) {
648
- out[c[0]] = c[1];
649
- }
650
- else if (c[1] === '=') {
651
- out[c[0]] = c[2];
652
- }
653
- }
654
- return out;
655
- }
656
- function clausesAreAllEquality(clauses) {
657
- return clauses.every((c) => c.length === 2 || c[1] === '=');
658
- }
659
- /**
660
- * Operator-aware predicate. Mirrors the server's WhereOp semantics for
661
- * local matching against pool/IDB rows. LIKE/ILIKE use SQL wildcards
662
- * (`%` = any chars, `_` = one char) translated to a JS regex.
663
- *
664
- * Exported so callers can apply the same predicate to in-memory
665
- * collections (tests, batch operations) using the canonical clauses.
666
- */
667
- export function matchesClauses(entity, clauses) {
668
- for (const clause of clauses) {
669
- const col = clause[0];
670
- const op = clause.length === 2 ? '=' : clause[1];
671
- const expected = clause.length === 2 ? clause[1] : clause[2];
672
- const v = entity[col];
673
- if (!matchOp(v, op, expected))
674
- return false;
675
- }
676
- return true;
677
- }
678
- function matchOp(actual, op, expected) {
679
- switch (op) {
680
- case '=':
681
- return actual === expected;
682
- case '!=':
683
- return actual !== expected;
684
- case '<':
685
- return compareOrdered(actual, expected, (a, b) => a < b);
686
- case '<=':
687
- return compareOrdered(actual, expected, (a, b) => a <= b);
688
- case '>':
689
- return compareOrdered(actual, expected, (a, b) => a > b);
690
- case '>=':
691
- return compareOrdered(actual, expected, (a, b) => a >= b);
692
- case 'IN':
693
- return Array.isArray(expected) && expected.some((alt) => alt === actual);
694
- case 'NOT IN':
695
- return Array.isArray(expected) && !expected.some((alt) => alt === actual);
696
- case 'IS':
697
- // SQL `IS` is null-equality; the only meaningful right-hand side here is null.
698
- return actual === expected;
699
- case 'IS NOT':
700
- return actual !== expected;
701
- case 'LIKE':
702
- return typeof actual === 'string' && typeof expected === 'string' && likeRegex(expected, false).test(actual);
703
- case 'NOT LIKE':
704
- return typeof actual === 'string' && typeof expected === 'string' && !likeRegex(expected, false).test(actual);
705
- case 'ILIKE':
706
- return typeof actual === 'string' && typeof expected === 'string' && likeRegex(expected, true).test(actual);
707
- case 'NOT ILIKE':
708
- return typeof actual === 'string' && typeof expected === 'string' && !likeRegex(expected, true).test(actual);
709
- }
710
- }
711
- /**
712
- * Ordered comparison helper. Both operands must be non-null and the same
713
- * comparable primitive (string-vs-string or number-vs-number). Mixed
714
- * types fall back to JS's loose ordering, which would be confusing — so
715
- * we reject early to match SQL semantics (a NULL operand yields false).
716
- */
717
- function compareOrdered(actual, expected, cmp) {
718
- if (actual == null || expected == null)
719
- return false;
720
- if (typeof actual === 'number' && typeof expected === 'number') {
721
- return cmp(actual, expected);
722
- }
723
- if (typeof actual === 'string' && typeof expected === 'string') {
724
- return cmp(actual, expected);
725
- }
726
- return false;
727
- }
728
- /** Translate a SQL LIKE/ILIKE pattern to a JS regex (`%` → `.*`, `_` → `.`). */
729
- function likeRegex(pattern, insensitive) {
730
- // Escape regex specials *except* `%` and `_`, then translate those.
731
- const escaped = pattern.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&');
732
- const body = escaped.replace(/%/g, '.*').replace(/_/g, '.');
733
- return new RegExp(`^${body}$`, insensitive ? 'i' : '');
734
- }
735
- /**
736
- * Schema fields are camelCase (`sectionId`); the wire query expects
737
- * the server-side column name. The query server's input resolver
738
- * casing-folds, but we send snake_case to match the convention used
739
- * by the existing loaders' postQuery calls (`'section_id'` etc.).
740
- */
741
- function columnize(field) {
742
- return field.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);
743
- }