@abloatai/ablo 0.35.0 → 0.37.0

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 (622) hide show
  1. package/AGENTS.md +2 -2
  2. package/CHANGELOG.md +71 -1929
  3. package/NOTICE +2 -2
  4. package/README.md +23 -532
  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 -112
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +3 -161
  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 +2 -2
  59. package/docs/api-keys.md +13 -12
  60. package/docs/api.md +15 -53
  61. package/docs/audit.md +4 -3
  62. package/docs/cli.md +11 -11
  63. package/docs/client-behavior.md +9 -9
  64. package/docs/concurrency-convention.md +28 -42
  65. package/docs/coordination.md +228 -86
  66. package/docs/data-sources.md +5 -5
  67. package/docs/debugging.md +34 -12
  68. package/docs/deployment.md +8 -8
  69. package/docs/examples/agent-human.md +4 -4
  70. package/docs/examples/ai-sdk-tool.md +1 -1
  71. package/docs/examples/existing-python-backend.md +15 -4
  72. package/docs/examples/nextjs.md +27 -6
  73. package/docs/examples/scoped-agent.md +3 -3
  74. package/docs/examples/server-agent.md +2 -2
  75. package/docs/groups.md +57 -3
  76. package/docs/guarantees.md +37 -10
  77. package/docs/how-it-works.md +32 -8
  78. package/docs/idempotency.md +6 -6
  79. package/docs/identity.md +24 -24
  80. package/docs/index.md +8 -8
  81. package/docs/integration-guide.md +38 -16
  82. package/docs/internal/README.md +18 -0
  83. package/docs/internal/agent-fleet-coordination-design.md +171 -0
  84. package/docs/internal/agent-orchestration.md +58 -0
  85. package/docs/internal/commit-identifiers.md +91 -0
  86. package/docs/internal/concurrency-open-decisions.md +37 -0
  87. package/docs/internal/data-source-reverse-channel.md +150 -0
  88. package/docs/internal/per-field-conflict-detection.md +165 -0
  89. package/docs/internal/postgres-replication.md +64 -0
  90. package/docs/internal/serializable-schema.md +119 -0
  91. package/docs/internal/structure.md +32 -0
  92. package/docs/mcp.md +9 -9
  93. package/docs/migration.md +37 -18
  94. package/docs/projects.md +1 -1
  95. package/docs/quickstart.md +2 -2
  96. package/docs/react.md +24 -13
  97. package/docs/schema-contract.md +3 -3
  98. package/docs/sessions.md +91 -37
  99. package/docs/webhooks.md +9 -9
  100. package/examples/README.md +2 -2
  101. package/examples/data-source/README.md +1 -1
  102. package/examples/data-source/ablo-driver.ts +1 -1
  103. package/examples/data-source/customer-server.ts +1 -1
  104. package/examples/data-source/run.ts +1 -1
  105. package/examples/data-source/schema.ts +1 -1
  106. package/examples/quickstart.ts +2 -2
  107. package/llms.txt +12 -12
  108. package/package.json +64 -174
  109. package/dist/BaseSyncedStore.d.ts +0 -823
  110. package/dist/BaseSyncedStore.js +0 -1955
  111. package/dist/Database.d.ts +0 -335
  112. package/dist/Database.js +0 -1500
  113. package/dist/InstanceCache.d.ts +0 -233
  114. package/dist/InstanceCache.js +0 -1164
  115. package/dist/LazyReferenceCollection.d.ts +0 -177
  116. package/dist/LazyReferenceCollection.js +0 -461
  117. package/dist/Model.d.ts +0 -444
  118. package/dist/Model.js +0 -909
  119. package/dist/ModelRegistry.d.ts +0 -221
  120. package/dist/ModelRegistry.js +0 -537
  121. package/dist/NetworkMonitor.d.ts +0 -26
  122. package/dist/NetworkMonitor.js +0 -77
  123. package/dist/RuntimeContext.d.ts +0 -52
  124. package/dist/RuntimeContext.js +0 -80
  125. package/dist/SyncClient.d.ts +0 -551
  126. package/dist/SyncClient.js +0 -2199
  127. package/dist/adapters/alwaysOnline.d.ts +0 -14
  128. package/dist/adapters/alwaysOnline.js +0 -17
  129. package/dist/adapters/inMemoryStorage.d.ts +0 -31
  130. package/dist/adapters/inMemoryStorage.js +0 -110
  131. package/dist/ai-sdk/coordinatedTool.d.ts +0 -120
  132. package/dist/ai-sdk/coordinatedTool.js +0 -134
  133. package/dist/ai-sdk/coordinationContext.d.ts +0 -46
  134. package/dist/ai-sdk/coordinationContext.js +0 -106
  135. package/dist/ai-sdk/index.d.ts +0 -121
  136. package/dist/ai-sdk/index.js +0 -121
  137. package/dist/ai-sdk/wrap.d.ts +0 -65
  138. package/dist/ai-sdk/wrap.js +0 -39
  139. package/dist/auth/index.d.ts +0 -1
  140. package/dist/auth/index.js +0 -8
  141. package/dist/batching/index.d.ts +0 -55
  142. package/dist/batching/index.js +0 -147
  143. package/dist/cli.cjs +0 -288600
  144. package/dist/client/Ablo.d.ts +0 -231
  145. package/dist/client/Ablo.js +0 -149
  146. package/dist/client/abloClient.d.ts +0 -309
  147. package/dist/client/abloClient.js +0 -13
  148. package/dist/client/clientPrelude.d.ts +0 -52
  149. package/dist/client/clientPrelude.js +0 -60
  150. package/dist/client/consoleLogger.d.ts +0 -35
  151. package/dist/client/consoleLogger.js +0 -44
  152. package/dist/client/coreClient.d.ts +0 -60
  153. package/dist/client/coreClient.js +0 -118
  154. package/dist/client/createInternalComponents.d.ts +0 -46
  155. package/dist/client/createInternalComponents.js +0 -92
  156. package/dist/client/createModelProxy.d.ts +0 -228
  157. package/dist/client/createModelProxy.js +0 -818
  158. package/dist/client/humans.d.ts +0 -48
  159. package/dist/client/humans.js +0 -52
  160. package/dist/client/modelRegistration.d.ts +0 -10
  161. package/dist/client/modelRegistration.js +0 -312
  162. package/dist/client/options.d.ts +0 -461
  163. package/dist/client/options.js +0 -7
  164. package/dist/client/reactiveEngine.d.ts +0 -48
  165. package/dist/client/reactiveEngine.js +0 -910
  166. package/dist/client/resourceTypes.d.ts +0 -12
  167. package/dist/client/resourceTypes.js +0 -10
  168. package/dist/client/schemaConfig.d.ts +0 -44
  169. package/dist/client/schemaConfig.js +0 -185
  170. package/dist/client/validateAbloOptions.d.ts +0 -42
  171. package/dist/client/validateAbloOptions.js +0 -43
  172. package/dist/client/wsMutationExecutor.d.ts +0 -27
  173. package/dist/client/wsMutationExecutor.js +0 -72
  174. package/dist/context.d.ts +0 -29
  175. package/dist/context.js +0 -58
  176. package/dist/coordination/ClaimLog.d.ts +0 -26
  177. package/dist/coordination/ClaimLog.js +0 -32
  178. package/dist/coordination/index.d.ts +0 -1
  179. package/dist/coordination/index.js +0 -8
  180. package/dist/core/DatabaseManager.d.ts +0 -105
  181. package/dist/core/DatabaseManager.js +0 -387
  182. package/dist/core/QueryProcessor.d.ts +0 -75
  183. package/dist/core/QueryProcessor.js +0 -255
  184. package/dist/core/QueryView.d.ts +0 -79
  185. package/dist/core/QueryView.js +0 -218
  186. package/dist/core/StoreManager.d.ts +0 -112
  187. package/dist/core/StoreManager.js +0 -302
  188. package/dist/core/ViewRegistry.d.ts +0 -20
  189. package/dist/core/ViewRegistry.js +0 -55
  190. package/dist/core/index.d.ts +0 -33
  191. package/dist/core/index.js +0 -48
  192. package/dist/core/openIDBWithTimeout.d.ts +0 -65
  193. package/dist/core/openIDBWithTimeout.js +0 -153
  194. package/dist/core/queryUtils.d.ts +0 -45
  195. package/dist/core/queryUtils.js +0 -69
  196. package/dist/core/storeContract.d.ts +0 -145
  197. package/dist/core/storeContract.js +0 -12
  198. package/dist/docs/catalog.d.ts +0 -72
  199. package/dist/docs/catalog.js +0 -227
  200. package/dist/docs/index.d.ts +0 -10
  201. package/dist/docs/index.js +0 -10
  202. package/dist/environment.d.ts +0 -1
  203. package/dist/environment.js +0 -8
  204. package/dist/interfaces/index.d.ts +0 -311
  205. package/dist/interfaces/index.js +0 -9
  206. package/dist/keys/index.d.ts +0 -1
  207. package/dist/keys/index.js +0 -8
  208. package/dist/mutators/RecordingMutation.d.ts +0 -36
  209. package/dist/mutators/RecordingMutation.js +0 -182
  210. package/dist/mutators/Transaction.d.ts +0 -40
  211. package/dist/mutators/Transaction.js +0 -58
  212. package/dist/mutators/UndoManager.d.ts +0 -258
  213. package/dist/mutators/UndoManager.js +0 -658
  214. package/dist/mutators/defineMutators.d.ts +0 -60
  215. package/dist/mutators/defineMutators.js +0 -18
  216. package/dist/mutators/inverseOp.d.ts +0 -126
  217. package/dist/mutators/inverseOp.js +0 -71
  218. package/dist/mutators/mutateActions.d.ts +0 -45
  219. package/dist/mutators/mutateActions.js +0 -105
  220. package/dist/mutators/readerActions.d.ts +0 -33
  221. package/dist/mutators/readerActions.js +0 -57
  222. package/dist/mutators/undoApply.d.ts +0 -51
  223. package/dist/mutators/undoApply.js +0 -117
  224. package/dist/policy/index.d.ts +0 -21
  225. package/dist/policy/index.js +0 -20
  226. package/dist/query/client.d.ts +0 -61
  227. package/dist/query/client.js +0 -137
  228. package/dist/query/types.d.ts +0 -85
  229. package/dist/query/types.js +0 -16
  230. package/dist/react/AbloProvider.d.ts +0 -230
  231. package/dist/react/AbloProvider.js +0 -455
  232. package/dist/react/ClientSideSuspense.d.ts +0 -36
  233. package/dist/react/ClientSideSuspense.js +0 -17
  234. package/dist/react/DefaultFallback.d.ts +0 -24
  235. package/dist/react/DefaultFallback.js +0 -43
  236. package/dist/react/context.d.ts +0 -55
  237. package/dist/react/context.js +0 -29
  238. package/dist/react/index.d.ts +0 -61
  239. package/dist/react/index.js +0 -66
  240. package/dist/react/internalContext.d.ts +0 -33
  241. package/dist/react/internalContext.js +0 -3
  242. package/dist/react/useAblo.d.ts +0 -75
  243. package/dist/react/useAblo.js +0 -102
  244. package/dist/react/useCurrentUserId.d.ts +0 -22
  245. package/dist/react/useCurrentUserId.js +0 -34
  246. package/dist/react/useErrorListener.d.ts +0 -20
  247. package/dist/react/useErrorListener.js +0 -38
  248. package/dist/react/useMutationFailureListener.d.ts +0 -26
  249. package/dist/react/useMutationFailureListener.js +0 -38
  250. package/dist/react/useMutators.d.ts +0 -56
  251. package/dist/react/useMutators.js +0 -84
  252. package/dist/react/useReactive.d.ts +0 -35
  253. package/dist/react/useReactive.js +0 -123
  254. package/dist/react/useSyncStatus.d.ts +0 -59
  255. package/dist/react/useSyncStatus.js +0 -76
  256. package/dist/react/useUndoScope.d.ts +0 -34
  257. package/dist/react/useUndoScope.js +0 -81
  258. package/dist/schema/coordination.d.ts +0 -112
  259. package/dist/schema/coordination.js +0 -129
  260. package/dist/schema/ddl.d.ts +0 -97
  261. package/dist/schema/ddl.js +0 -491
  262. package/dist/schema/ddlLock.d.ts +0 -35
  263. package/dist/schema/ddlLock.js +0 -46
  264. package/dist/schema/diff.d.ts +0 -225
  265. package/dist/schema/diff.js +0 -289
  266. package/dist/schema/generate.d.ts +0 -19
  267. package/dist/schema/generate.js +0 -86
  268. package/dist/schema/index.d.ts +0 -41
  269. package/dist/schema/index.js +0 -76
  270. package/dist/schema/queries.d.ts +0 -201
  271. package/dist/schema/queries.js +0 -144
  272. package/dist/schema/select.d.ts +0 -40
  273. package/dist/schema/select.js +0 -87
  274. package/dist/schema/serialize.d.ts +0 -115
  275. package/dist/schema/serialize.js +0 -262
  276. package/dist/schema/sugar.d.ts +0 -109
  277. package/dist/schema/sugar.js +0 -83
  278. package/dist/schema/syncDeltaRow.d.ts +0 -6
  279. package/dist/schema/syncDeltaRow.js +0 -6
  280. package/dist/server/adapter.d.ts +0 -173
  281. package/dist/server/adapter.js +0 -18
  282. package/dist/server/commit.d.ts +0 -107
  283. package/dist/server/commit.js +0 -1
  284. package/dist/server/index.d.ts +0 -14
  285. package/dist/server/index.js +0 -2
  286. package/dist/server/readConfig.d.ts +0 -80
  287. package/dist/server/readConfig.js +0 -8
  288. package/dist/server/storageMode.d.ts +0 -23
  289. package/dist/server/storageMode.js +0 -17
  290. package/dist/source/adapter.d.ts +0 -81
  291. package/dist/source/adapter.js +0 -22
  292. package/dist/source/adapters/drizzle.d.ts +0 -48
  293. package/dist/source/adapters/drizzle.js +0 -219
  294. package/dist/source/adapters/kysely.d.ts +0 -42
  295. package/dist/source/adapters/kysely.js +0 -205
  296. package/dist/source/adapters/kyselyMutationCore.d.ts +0 -76
  297. package/dist/source/adapters/kyselyMutationCore.js +0 -125
  298. package/dist/source/adapters/memory.d.ts +0 -13
  299. package/dist/source/adapters/memory.js +0 -130
  300. package/dist/source/adapters/prisma.d.ts +0 -63
  301. package/dist/source/adapters/prisma.js +0 -202
  302. package/dist/source/conformance.d.ts +0 -37
  303. package/dist/source/conformance.js +0 -215
  304. package/dist/source/connector.d.ts +0 -95
  305. package/dist/source/connector.js +0 -266
  306. package/dist/source/connectorProtocol.d.ts +0 -154
  307. package/dist/source/connectorProtocol.js +0 -163
  308. package/dist/source/contract.d.ts +0 -195
  309. package/dist/source/contract.js +0 -164
  310. package/dist/source/factory.d.ts +0 -92
  311. package/dist/source/factory.js +0 -286
  312. package/dist/source/footprint.d.ts +0 -111
  313. package/dist/source/footprint.js +0 -0
  314. package/dist/source/idempotency.d.ts +0 -61
  315. package/dist/source/idempotency.js +0 -144
  316. package/dist/source/index.d.ts +0 -23
  317. package/dist/source/index.js +0 -30
  318. package/dist/source/migrations.d.ts +0 -21
  319. package/dist/source/migrations.js +0 -103
  320. package/dist/source/next.d.ts +0 -32
  321. package/dist/source/next.js +0 -25
  322. package/dist/source/pushQueue.d.ts +0 -134
  323. package/dist/source/pushQueue.js +0 -256
  324. package/dist/source/signing.d.ts +0 -92
  325. package/dist/source/signing.js +0 -162
  326. package/dist/source/types.d.ts +0 -401
  327. package/dist/source/types.js +0 -59
  328. package/dist/stores/ObjectStore.d.ts +0 -115
  329. package/dist/stores/ObjectStore.js +0 -393
  330. package/dist/stores/ObjectStoreContract.d.ts +0 -38
  331. package/dist/stores/ObjectStoreContract.js +0 -1
  332. package/dist/stores/SyncActionStore.d.ts +0 -97
  333. package/dist/stores/SyncActionStore.js +0 -504
  334. package/dist/stores/syncAction.d.ts +0 -26
  335. package/dist/stores/syncAction.js +0 -16
  336. package/dist/surface.d.ts +0 -36
  337. package/dist/surface.js +0 -75
  338. package/dist/sync/BootstrapFetcher.d.ts +0 -280
  339. package/dist/sync/BootstrapFetcher.js +0 -962
  340. package/dist/sync/ConnectionManager.d.ts +0 -8
  341. package/dist/sync/ConnectionManager.js +0 -8
  342. package/dist/sync/OnDemandLoader.d.ts +0 -228
  343. package/dist/sync/OnDemandLoader.js +0 -742
  344. package/dist/sync/SubscriptionManager.d.ts +0 -159
  345. package/dist/sync/SubscriptionManager.js +0 -243
  346. package/dist/sync/SyncWebSocket.d.ts +0 -173
  347. package/dist/sync/SyncWebSocket.js +0 -438
  348. package/dist/sync/awaitClaimGrant.d.ts +0 -6
  349. package/dist/sync/awaitClaimGrant.js +0 -6
  350. package/dist/sync/bootstrapApply.d.ts +0 -70
  351. package/dist/sync/bootstrapApply.js +0 -73
  352. package/dist/sync/commitFrames.d.ts +0 -8
  353. package/dist/sync/commitFrames.js +0 -8
  354. package/dist/sync/contextPorts.d.ts +0 -18
  355. package/dist/sync/contextPorts.js +0 -31
  356. package/dist/sync/createClaimStream.d.ts +0 -7
  357. package/dist/sync/createClaimStream.js +0 -7
  358. package/dist/sync/createPresenceStream.d.ts +0 -69
  359. package/dist/sync/createPresenceStream.js +0 -200
  360. package/dist/sync/createSnapshot.d.ts +0 -29
  361. package/dist/sync/createSnapshot.js +0 -118
  362. package/dist/sync/credentialLifecycle.d.ts +0 -7
  363. package/dist/sync/credentialLifecycle.js +0 -7
  364. package/dist/sync/deltaPipeline.d.ts +0 -113
  365. package/dist/sync/deltaPipeline.js +0 -261
  366. package/dist/sync/groupChange.d.ts +0 -113
  367. package/dist/sync/groupChange.js +0 -242
  368. package/dist/sync/participants.d.ts +0 -115
  369. package/dist/sync/participants.js +0 -344
  370. package/dist/sync/persistedPrefix.d.ts +0 -12
  371. package/dist/sync/persistedPrefix.js +0 -22
  372. package/dist/sync/schemaDrift.d.ts +0 -55
  373. package/dist/sync/schemaDrift.js +0 -53
  374. package/dist/sync/schemas.d.ts +0 -70
  375. package/dist/sync/schemas.js +0 -94
  376. package/dist/sync/syncCursor.d.ts +0 -40
  377. package/dist/sync/syncCursor.js +0 -55
  378. package/dist/sync/syncPlan.d.ts +0 -54
  379. package/dist/sync/syncPlan.js +0 -50
  380. package/dist/sync/wsFrameHandlers.d.ts +0 -8
  381. package/dist/sync/wsFrameHandlers.js +0 -8
  382. package/dist/testing/fixtures/bootstrap.d.ts +0 -49
  383. package/dist/testing/fixtures/bootstrap.js +0 -59
  384. package/dist/testing/fixtures/deltas.d.ts +0 -83
  385. package/dist/testing/fixtures/deltas.js +0 -136
  386. package/dist/testing/fixtures/httpResponses.d.ts +0 -70
  387. package/dist/testing/fixtures/httpResponses.js +0 -90
  388. package/dist/testing/fixtures/models.d.ts +0 -83
  389. package/dist/testing/fixtures/models.js +0 -272
  390. package/dist/testing/helpers/reactWrapper.d.ts +0 -69
  391. package/dist/testing/helpers/reactWrapper.js +0 -67
  392. package/dist/testing/helpers/syncEngineHarness.d.ts +0 -54
  393. package/dist/testing/helpers/syncEngineHarness.js +0 -73
  394. package/dist/testing/helpers/wait.d.ts +0 -30
  395. package/dist/testing/helpers/wait.js +0 -49
  396. package/dist/testing/index.d.ts +0 -23
  397. package/dist/testing/index.js +0 -33
  398. package/dist/testing/mocks/FakeDatabase.d.ts +0 -18
  399. package/dist/testing/mocks/FakeDatabase.js +0 -10
  400. package/dist/testing/mocks/MockMutationExecutor.d.ts +0 -87
  401. package/dist/testing/mocks/MockMutationExecutor.js +0 -186
  402. package/dist/testing/mocks/MockNetworkMonitor.d.ts +0 -20
  403. package/dist/testing/mocks/MockNetworkMonitor.js +0 -46
  404. package/dist/testing/mocks/MockSyncContext.d.ts +0 -51
  405. package/dist/testing/mocks/MockSyncContext.js +0 -72
  406. package/dist/testing/mocks/MockSyncStore.d.ts +0 -88
  407. package/dist/testing/mocks/MockSyncStore.js +0 -171
  408. package/dist/testing/mocks/MockWebSocket.d.ts +0 -71
  409. package/dist/testing/mocks/MockWebSocket.js +0 -118
  410. package/dist/transaction/ablo.d.ts +0 -88
  411. package/dist/transaction/ablo.js +0 -33
  412. package/dist/transaction/auth/apiKey.d.ts +0 -152
  413. package/dist/transaction/auth/apiKey.js +0 -419
  414. package/dist/transaction/auth/bootstrapScope.d.ts +0 -15
  415. package/dist/transaction/auth/bootstrapScope.js +0 -1
  416. package/dist/transaction/auth/capability.d.ts +0 -177
  417. package/dist/transaction/auth/capability.js +0 -199
  418. package/dist/transaction/auth/credentialEndpoint.d.ts +0 -61
  419. package/dist/transaction/auth/credentialEndpoint.js +0 -86
  420. package/dist/transaction/auth/credentialPolicy.d.ts +0 -148
  421. package/dist/transaction/auth/credentialPolicy.js +0 -125
  422. package/dist/transaction/auth/credentialSource.d.ts +0 -30
  423. package/dist/transaction/auth/credentialSource.js +0 -55
  424. package/dist/transaction/auth/hostedEndpoints.d.ts +0 -21
  425. package/dist/transaction/auth/hostedEndpoints.js +0 -21
  426. package/dist/transaction/auth/identity.d.ts +0 -55
  427. package/dist/transaction/auth/identity.js +0 -210
  428. package/dist/transaction/auth/index.d.ts +0 -162
  429. package/dist/transaction/auth/index.js +0 -304
  430. package/dist/transaction/auth/schemas.d.ts +0 -59
  431. package/dist/transaction/auth/schemas.js +0 -85
  432. package/dist/transaction/auth/sessionMint.d.ts +0 -28
  433. package/dist/transaction/auth/sessionMint.js +0 -85
  434. package/dist/transaction/coordination/awaitClaimGrant.d.ts +0 -49
  435. package/dist/transaction/coordination/awaitClaimGrant.js +0 -112
  436. package/dist/transaction/coordination/claimHeartbeatLoop.d.ts +0 -50
  437. package/dist/transaction/coordination/claimHeartbeatLoop.js +0 -88
  438. package/dist/transaction/coordination/claimMeta.d.ts +0 -49
  439. package/dist/transaction/coordination/claimMeta.js +0 -52
  440. package/dist/transaction/coordination/createClaimStream.d.ts +0 -64
  441. package/dist/transaction/coordination/createClaimStream.js +0 -475
  442. package/dist/transaction/coordination/events.d.ts +0 -74
  443. package/dist/transaction/coordination/events.js +0 -7
  444. package/dist/transaction/coordination/index.d.ts +0 -19
  445. package/dist/transaction/coordination/index.js +0 -44
  446. package/dist/transaction/coordination/locator.d.ts +0 -83
  447. package/dist/transaction/coordination/locator.js +0 -82
  448. package/dist/transaction/coordination/schema.d.ts +0 -1473
  449. package/dist/transaction/coordination/schema.js +0 -1013
  450. package/dist/transaction/coordination/targetConflict.d.ts +0 -2
  451. package/dist/transaction/coordination/targetConflict.js +0 -103
  452. package/dist/transaction/coordination/trace.d.ts +0 -78
  453. package/dist/transaction/coordination/trace.js +0 -138
  454. package/dist/transaction/durableWrites.d.ts +0 -62
  455. package/dist/transaction/durableWrites.js +0 -71
  456. package/dist/transaction/environment.d.ts +0 -105
  457. package/dist/transaction/environment.js +0 -108
  458. package/dist/transaction/errorCodes.d.ts +0 -403
  459. package/dist/transaction/errorCodes.js +0 -480
  460. package/dist/transaction/errors.d.ts +0 -428
  461. package/dist/transaction/errors.js +0 -686
  462. package/dist/transaction/index.d.ts +0 -20
  463. package/dist/transaction/index.js +0 -20
  464. package/dist/transaction/keys/index.d.ts +0 -87
  465. package/dist/transaction/keys/index.js +0 -207
  466. package/dist/transaction/log/syncDeltaRow.d.ts +0 -158
  467. package/dist/transaction/log/syncDeltaRow.js +0 -95
  468. package/dist/transaction/logPosition.d.ts +0 -97
  469. package/dist/transaction/logPosition.js +0 -125
  470. package/dist/transaction/logger.d.ts +0 -16
  471. package/dist/transaction/logger.js +0 -7
  472. package/dist/transaction/observability.d.ts +0 -53
  473. package/dist/transaction/observability.js +0 -19
  474. package/dist/transaction/persistence.d.ts +0 -12
  475. package/dist/transaction/persistence.js +0 -11
  476. package/dist/transaction/plugin.d.ts +0 -192
  477. package/dist/transaction/plugin.js +0 -87
  478. package/dist/transaction/policy/types.d.ts +0 -217
  479. package/dist/transaction/policy/types.js +0 -126
  480. package/dist/transaction/resources/functionalUpdate.d.ts +0 -79
  481. package/dist/transaction/resources/functionalUpdate.js +0 -87
  482. package/dist/transaction/resources/httpResources.d.ts +0 -266
  483. package/dist/transaction/resources/httpResources.js +0 -7
  484. package/dist/transaction/resources/modelOperations.d.ts +0 -319
  485. package/dist/transaction/resources/modelOperations.js +0 -12
  486. package/dist/transaction/resources/mutationOptions.d.ts +0 -66
  487. package/dist/transaction/resources/mutationOptions.js +0 -9
  488. package/dist/transaction/resources/where.d.ts +0 -85
  489. package/dist/transaction/resources/where.js +0 -70
  490. package/dist/transaction/resources/writeOptionsSchema.d.ts +0 -47
  491. package/dist/transaction/resources/writeOptionsSchema.js +0 -73
  492. package/dist/transaction/schema/field.d.ts +0 -126
  493. package/dist/transaction/schema/field.js +0 -265
  494. package/dist/transaction/schema/loadStrategy.d.ts +0 -45
  495. package/dist/transaction/schema/loadStrategy.js +0 -46
  496. package/dist/transaction/schema/model.d.ts +0 -379
  497. package/dist/transaction/schema/model.js +0 -123
  498. package/dist/transaction/schema/openapi.d.ts +0 -57
  499. package/dist/transaction/schema/openapi.js +0 -340
  500. package/dist/transaction/schema/relation.d.ts +0 -199
  501. package/dist/transaction/schema/relation.js +0 -104
  502. package/dist/transaction/schema/residency.d.ts +0 -29
  503. package/dist/transaction/schema/residency.js +0 -25
  504. package/dist/transaction/schema/roles.d.ts +0 -249
  505. package/dist/transaction/schema/roles.js +0 -230
  506. package/dist/transaction/schema/schema.d.ts +0 -324
  507. package/dist/transaction/schema/schema.js +0 -305
  508. package/dist/transaction/schema/tenancy.d.ts +0 -139
  509. package/dist/transaction/schema/tenancy.js +0 -190
  510. package/dist/transaction/transactionLayer.d.ts +0 -82
  511. package/dist/transaction/transactionLayer.js +0 -24
  512. package/dist/transaction/transactions/settlement/commitEnvelope.d.ts +0 -143
  513. package/dist/transaction/transactions/settlement/commitEnvelope.js +0 -161
  514. package/dist/transaction/transactions/settlement/httpCommitEnvelope.d.ts +0 -53
  515. package/dist/transaction/transactions/settlement/httpCommitEnvelope.js +0 -207
  516. package/dist/transaction/transactions/settlement/idempotencyKey.d.ts +0 -10
  517. package/dist/transaction/transactions/settlement/idempotencyKey.js +0 -9
  518. package/dist/transaction/transactions/settlement/pendingWrite.d.ts +0 -112
  519. package/dist/transaction/transactions/settlement/pendingWrite.js +0 -20
  520. package/dist/transaction/transport/commitFrames.d.ts +0 -90
  521. package/dist/transaction/transport/commitFrames.js +0 -134
  522. package/dist/transaction/transport/connectionManager.d.ts +0 -215
  523. package/dist/transaction/transport/connectionManager.js +0 -673
  524. package/dist/transaction/transport/credentialLifecycle.d.ts +0 -177
  525. package/dist/transaction/transport/credentialLifecycle.js +0 -324
  526. package/dist/transaction/transport/heartbeat.d.ts +0 -65
  527. package/dist/transaction/transport/heartbeat.js +0 -93
  528. package/dist/transaction/transport/httpClient.d.ts +0 -123
  529. package/dist/transaction/transport/httpClient.js +0 -145
  530. package/dist/transaction/transport/httpOptions.d.ts +0 -33
  531. package/dist/transaction/transport/httpOptions.js +0 -12
  532. package/dist/transaction/transport/httpTransport.d.ts +0 -8
  533. package/dist/transaction/transport/httpTransport.js +0 -1276
  534. package/dist/transaction/transport/networkProbe.d.ts +0 -84
  535. package/dist/transaction/transport/networkProbe.js +0 -207
  536. package/dist/transaction/transport/wsFrameHandlers.d.ts +0 -128
  537. package/dist/transaction/transport/wsFrameHandlers.js +0 -429
  538. package/dist/transaction/transport/wsTransport.d.ts +0 -576
  539. package/dist/transaction/transport/wsTransport.js +0 -1017
  540. package/dist/transaction/types/assertExact.d.ts +0 -17
  541. package/dist/transaction/types/assertExact.js +0 -1
  542. package/dist/transaction/types/global.d.ts +0 -107
  543. package/dist/transaction/types/global.js +0 -40
  544. package/dist/transaction/types/index.d.ts +0 -205
  545. package/dist/transaction/types/index.js +0 -56
  546. package/dist/transaction/types/modelData.d.ts +0 -10
  547. package/dist/transaction/types/modelData.js +0 -9
  548. package/dist/transaction/types/participant.d.ts +0 -20
  549. package/dist/transaction/types/participant.js +0 -10
  550. package/dist/transaction/types/streams.d.ts +0 -540
  551. package/dist/transaction/types/streams.js +0 -11
  552. package/dist/transaction/utils/asyncIterator.d.ts +0 -34
  553. package/dist/transaction/utils/asyncIterator.js +0 -135
  554. package/dist/transaction/utils/duration.d.ts +0 -25
  555. package/dist/transaction/utils/duration.js +0 -45
  556. package/dist/transaction/utils/json.d.ts +0 -57
  557. package/dist/transaction/utils/json.js +0 -276
  558. package/dist/transaction/wire/accountResponses.d.ts +0 -351
  559. package/dist/transaction/wire/accountResponses.js +0 -255
  560. package/dist/transaction/wire/auth.d.ts +0 -49
  561. package/dist/transaction/wire/auth.js +0 -57
  562. package/dist/transaction/wire/bootstrapReason.d.ts +0 -9
  563. package/dist/transaction/wire/bootstrapReason.js +0 -8
  564. package/dist/transaction/wire/claimEvent.d.ts +0 -76
  565. package/dist/transaction/wire/claimEvent.js +0 -73
  566. package/dist/transaction/wire/claims.d.ts +0 -463
  567. package/dist/transaction/wire/claims.js +0 -229
  568. package/dist/transaction/wire/commit.d.ts +0 -603
  569. package/dist/transaction/wire/commit.js +0 -321
  570. package/dist/transaction/wire/delta.d.ts +0 -250
  571. package/dist/transaction/wire/delta.js +0 -147
  572. package/dist/transaction/wire/errorEnvelope.d.ts +0 -72
  573. package/dist/transaction/wire/errorEnvelope.js +0 -123
  574. package/dist/transaction/wire/feedCursor.d.ts +0 -60
  575. package/dist/transaction/wire/feedCursor.js +0 -82
  576. package/dist/transaction/wire/feedEvent.d.ts +0 -177
  577. package/dist/transaction/wire/feedEvent.js +0 -39
  578. package/dist/transaction/wire/frames.d.ts +0 -194
  579. package/dist/transaction/wire/frames.js +0 -50
  580. package/dist/transaction/wire/inboundFrames.d.ts +0 -552
  581. package/dist/transaction/wire/inboundFrames.js +0 -116
  582. package/dist/transaction/wire/index.d.ts +0 -50
  583. package/dist/transaction/wire/index.js +0 -74
  584. package/dist/transaction/wire/listEnvelope.d.ts +0 -37
  585. package/dist/transaction/wire/listEnvelope.js +0 -42
  586. package/dist/transaction/wire/modelResponses.d.ts +0 -85
  587. package/dist/transaction/wire/modelResponses.js +0 -43
  588. package/dist/transaction/wire/protocol.d.ts +0 -38
  589. package/dist/transaction/wire/protocol.js +0 -38
  590. package/dist/transaction/wire/protocolVersion.d.ts +0 -73
  591. package/dist/transaction/wire/protocolVersion.js +0 -83
  592. package/dist/transactions/mutations/MutationQueue.d.ts +0 -655
  593. package/dist/transactions/mutations/MutationQueue.js +0 -2797
  594. package/dist/transactions/mutations/MutationStore.d.ts +0 -20
  595. package/dist/transactions/mutations/MutationStore.js +0 -53
  596. package/dist/transactions/mutations/UnconfirmedWrites.d.ts +0 -82
  597. package/dist/transactions/mutations/UnconfirmedWrites.js +0 -104
  598. package/dist/transactions/mutations/coalesceRules.d.ts +0 -58
  599. package/dist/transactions/mutations/coalesceRules.js +0 -140
  600. package/dist/transactions/mutations/commitLatency.d.ts +0 -52
  601. package/dist/transactions/mutations/commitLatency.js +0 -130
  602. package/dist/transactions/mutations/commitOutboxStore.d.ts +0 -28
  603. package/dist/transactions/mutations/commitOutboxStore.js +0 -26
  604. package/dist/transactions/mutations/commitPayload.d.ts +0 -164
  605. package/dist/transactions/mutations/commitPayload.js +0 -152
  606. package/dist/transactions/mutations/deltaConfirmation.d.ts +0 -59
  607. package/dist/transactions/mutations/deltaConfirmation.js +0 -233
  608. package/dist/transactions/mutations/durableWriteStore.d.ts +0 -14
  609. package/dist/transactions/mutations/durableWriteStore.js +0 -12
  610. package/dist/transactions/mutations/optimisticApply.d.ts +0 -49
  611. package/dist/transactions/mutations/optimisticApply.js +0 -65
  612. package/dist/transactions/mutations/replayValidation.d.ts +0 -186
  613. package/dist/transactions/mutations/replayValidation.js +0 -163
  614. package/dist/utils/mobxSetup.d.ts +0 -53
  615. package/dist/utils/mobxSetup.js +0 -330
  616. package/dist/webhooks/events.d.ts +0 -43
  617. package/dist/webhooks/events.js +0 -42
  618. package/dist/webhooks/index.d.ts +0 -8
  619. package/dist/webhooks/index.js +0 -8
  620. package/dist/wire/index.d.ts +0 -1
  621. package/dist/wire/index.js +0 -8
  622. package/docs/interaction-model.md +0 -99
@@ -1,742 +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
- }, { queries: [query] });
436
- const rows = Array.isArray(result.results[0]) ? result.results[0] : [];
437
- // Normalize: wire rows lack `__typename` when the server elides it.
438
- const normalized = rows.map((row) => {
439
- if (row && typeof row === 'object' && !('__typename' in row)) {
440
- return { __typename: typename, ...row };
441
- }
442
- return row;
443
- });
444
- // Expand: server returns related entities nested under each row
445
- // (`row.blocks = [{...}, ...]`). Walk the nested shape, stamp the
446
- // typename from the schema's relation metadata (the server bakes
447
- // `__typename` into the JSONB but the postgres.camel driver
448
- // mangles it to `_Typename` mid-flight, so client-side stamping
449
- // is the only reliable path), hydrate each related row into its
450
- // own typed pool, then leave the nested arrays in place on the
451
- // primary row.
452
- if (options?.expand && options.expand.length > 0) {
453
- this.hydrateExpanded(modelName, normalized, options.expand);
454
- }
455
- return normalized;
456
- }
457
- /**
458
- * Hydrate nested expanded rows. Resolves each relation's target
459
- * typename via the schema and stamps `__typename` on every nested
460
- * row before passing to `hydrateOne` — the server's JSONB
461
- * `__typename` field gets mangled by `postgres.camel` (`__typename`
462
- * → `_Typename`), so the SDK can't trust whatever string lands.
463
- */
464
- hydrateExpanded(parentModelName, rows, relationNames) {
465
- const parentDef = this.getModelDef(parentModelName);
466
- for (const row of rows) {
467
- if (!row || typeof row !== 'object')
468
- continue;
469
- const obj = row;
470
- for (const rel of relationNames) {
471
- const nested = obj[rel];
472
- if (!nested)
473
- continue;
474
- // Resolve target typename via parent's relations map.
475
- const relDef = parentDef?.relations?.[rel];
476
- const targetKey = relDef?.target;
477
- const targetTypename = targetKey ? this.resolveTypename(targetKey) : undefined;
478
- const items = Array.isArray(nested) ? nested : [nested];
479
- const models = [];
480
- const stampedItems = [];
481
- for (const item of items) {
482
- const stamped = this.stampTypename(item, targetTypename);
483
- stampedItems.push(stamped);
484
- const m = this.hydrateOne(stamped);
485
- if (m)
486
- models.push(m);
487
- }
488
- if (models.length > 0) {
489
- this.opts.objectPool.addBatch(models, ModelScope.live);
490
- }
491
- // Persist expanded children to their OWN typed store so they survive
492
- // reload and can be re-served by `hydrateExpandedFromLocal` — without
493
- // this, expand-fetched relations live only inside the parent's row
494
- // and are lost to a lazy child query after a cold start.
495
- if (stampedItems.length > 0 && targetKey) {
496
- void this.persistToIdb(targetKey, stampedItems);
497
- }
498
- }
499
- }
500
- }
501
- async persistToIdb(modelName, rows) {
502
- const store = this.opts.database.getStore(this.resolveTypename(modelName));
503
- if (!store)
504
- return;
505
- for (const row of rows) {
506
- try {
507
- await store.put(row);
508
- }
509
- catch {
510
- // IDB writes are best-effort — a transient quota/transaction
511
- // failure shouldn't break the hydration's primary purpose.
512
- }
513
- }
514
- }
515
- resolveTypename(modelName) {
516
- // Schema is the source of truth for wire typenames. The model proxy
517
- // is keyed by camelCase plural (`blocks`) but the wire query +
518
- // InstanceCache typeIndex use the typename (`Block`).
519
- const def = this.opts.schema
520
- .models?.[modelName];
521
- return def?.typename ?? modelName;
522
- }
523
- columnizeField(modelName, field) {
524
- const fields = this.opts.schema.models?.[modelName]?.fields;
525
- if (fields) {
526
- const direct = fields[field]?.column;
527
- if (direct)
528
- return direct;
529
- for (const [fieldName, meta] of Object.entries(fields)) {
530
- const conventional = columnize(fieldName);
531
- if (field === fieldName || field === conventional || field === meta.column) {
532
- return meta.column ?? conventional;
533
- }
534
- }
535
- }
536
- return /[A-Z]/.test(field) ? columnize(field) : field;
537
- }
538
- columnizeClause(modelName, clause) {
539
- const finalCol = this.columnizeField(modelName, clause[0]);
540
- if (clause.length === 2)
541
- return [finalCol, clause[1]];
542
- return [finalCol, clause[1], clause[2]];
543
- }
544
- }
545
- // ── Helpers ────────────────────────────────────────────────────────────
546
- function stableKey(modelName, clauses, orderBy, limit, expand) {
547
- // Sort clauses by their stringified form so caller order doesn't
548
- // produce different dedup keys for semantically identical queries.
549
- const sorted = [...clauses].map((c) => [...c]).sort((a, b) => {
550
- const ka = JSON.stringify(a);
551
- const kb = JSON.stringify(b);
552
- return ka < kb ? -1 : ka > kb ? 1 : 0;
553
- });
554
- // Expand is part of the query identity: `sections where report=r1` and the same
555
- // with `expand:['blocks']` hydrate different data, so they must not share a
556
- // ledger/dedup key. Sorted so relation order doesn't fork the key.
557
- const expandKey = expand && expand.length > 0 ? [...expand].sort() : undefined;
558
- return JSON.stringify({ modelName, where: sorted, orderBy, limit, expand: expandKey });
559
- }
560
- function applyLimit(arr, limit) {
561
- return typeof limit === 'number' ? arr.slice(0, limit) : arr;
562
- }
563
- function scanPool(pool, ModelClass, clauses) {
564
- const all = pool.getByType(ModelClass);
565
- if (clauses.length === 0)
566
- return all;
567
- return all.filter((entity) => matchesClauses(entity, clauses));
568
- }
569
- async function scanIdb(database, modelName, clauses) {
570
- const store = database.getStore(modelName);
571
- if (!store)
572
- return [];
573
- // Fast path: a single equality `id` lookup hits the primary key.
574
- const eqClauses = extractEqClauses(clauses);
575
- if (clauses.length === 1 && eqClauses.id !== undefined && typeof eqClauses.id === 'string') {
576
- try {
577
- const row = await store.get(eqClauses.id);
578
- return row ? [row] : [];
579
- }
580
- catch {
581
- return [];
582
- }
583
- }
584
- // Index-aware path: when every clause is equality and exactly one
585
- // non-id string column is constrained, hit that column's index for
586
- // an O(matches) read. Anything involving LIKE/ILIKE/ranges falls
587
- // through to full-scan + filter.
588
- if (clausesAreAllEquality(clauses)) {
589
- const indexedKeys = Object.keys(eqClauses).filter((k) => k !== 'id' && typeof eqClauses[k] === 'string');
590
- const idxKey = indexedKeys.length === 1 ? indexedKeys[0] : undefined;
591
- if (idxKey !== undefined) {
592
- try {
593
- const rows = await store.getAllFromIndex(idxKey, eqClauses[idxKey]);
594
- if (Array.isArray(rows)) {
595
- return rows.filter((r) => matchesClauses(r, clauses));
596
- }
597
- }
598
- catch {
599
- // index doesn't exist — fall through to full-scan path.
600
- }
601
- }
602
- }
603
- try {
604
- const rows = await store.getAll();
605
- return Array.isArray(rows)
606
- ? rows.filter((r) => matchesClauses(r, clauses))
607
- : [];
608
- }
609
- catch {
610
- return [];
611
- }
612
- }
613
- /**
614
- * Normalize `LoadWhere<T>` input to the canonical `readonly WhereClause[]`
615
- * tuple form used throughout `runFetch`. Tuple inputs pass through; object
616
- * inputs become one `['col', '=', val]` or `['col', 'IN', vals]` per key.
617
- *
618
- * Detection: an array whose first element is itself an array is treated
619
- * as tuple form. Object form is the fallback.
620
- *
621
- * Exported so callers can pre-normalize (e.g., for tests, or to inspect
622
- * the canonical clauses before passing them to `load`/`subscribe`).
623
- */
624
- export function normalizeWhere(where) {
625
- if (where == null)
626
- return [];
627
- if (Array.isArray(where)) {
628
- // Tuple form — assumed to already use server-side column names.
629
- return where;
630
- }
631
- if (typeof where === 'object') {
632
- const obj = where;
633
- return Object.entries(obj).map(([key, value]) => {
634
- if (Array.isArray(value)) {
635
- return [key, 'IN', value];
636
- }
637
- return [key, value];
638
- });
639
- }
640
- return [];
641
- }
642
- /** Equality-only subset of clauses, keyed by column. Used by IDB fast paths. */
643
- function extractEqClauses(clauses) {
644
- const out = {};
645
- for (const c of clauses) {
646
- if (c.length === 2) {
647
- out[c[0]] = c[1];
648
- }
649
- else if (c[1] === '=') {
650
- out[c[0]] = c[2];
651
- }
652
- }
653
- return out;
654
- }
655
- function clausesAreAllEquality(clauses) {
656
- return clauses.every((c) => c.length === 2 || c[1] === '=');
657
- }
658
- /**
659
- * Operator-aware predicate. Mirrors the server's WhereOp semantics for
660
- * local matching against pool/IDB rows. LIKE/ILIKE use SQL wildcards
661
- * (`%` = any chars, `_` = one char) translated to a JS regex.
662
- *
663
- * Exported so callers can apply the same predicate to in-memory
664
- * collections (tests, batch operations) using the canonical clauses.
665
- */
666
- export function matchesClauses(entity, clauses) {
667
- for (const clause of clauses) {
668
- const col = clause[0];
669
- const op = clause.length === 2 ? '=' : clause[1];
670
- const expected = clause.length === 2 ? clause[1] : clause[2];
671
- const v = entity[col];
672
- if (!matchOp(v, op, expected))
673
- return false;
674
- }
675
- return true;
676
- }
677
- function matchOp(actual, op, expected) {
678
- switch (op) {
679
- case '=':
680
- return actual === expected;
681
- case '!=':
682
- return actual !== expected;
683
- case '<':
684
- return compareOrdered(actual, expected, (a, b) => a < b);
685
- case '<=':
686
- return compareOrdered(actual, expected, (a, b) => a <= b);
687
- case '>':
688
- return compareOrdered(actual, expected, (a, b) => a > b);
689
- case '>=':
690
- return compareOrdered(actual, expected, (a, b) => a >= b);
691
- case 'IN':
692
- return Array.isArray(expected) && expected.some((alt) => alt === actual);
693
- case 'NOT IN':
694
- return Array.isArray(expected) && !expected.some((alt) => alt === actual);
695
- case 'IS':
696
- // SQL `IS` is null-equality; the only meaningful right-hand side here is null.
697
- return actual === expected;
698
- case 'IS NOT':
699
- return actual !== expected;
700
- case 'LIKE':
701
- return typeof actual === 'string' && typeof expected === 'string' && likeRegex(expected, false).test(actual);
702
- case 'NOT LIKE':
703
- return typeof actual === 'string' && typeof expected === 'string' && !likeRegex(expected, false).test(actual);
704
- case 'ILIKE':
705
- return typeof actual === 'string' && typeof expected === 'string' && likeRegex(expected, true).test(actual);
706
- case 'NOT ILIKE':
707
- return typeof actual === 'string' && typeof expected === 'string' && !likeRegex(expected, true).test(actual);
708
- }
709
- }
710
- /**
711
- * Ordered comparison helper. Both operands must be non-null and the same
712
- * comparable primitive (string-vs-string or number-vs-number). Mixed
713
- * types fall back to JS's loose ordering, which would be confusing — so
714
- * we reject early to match SQL semantics (a NULL operand yields false).
715
- */
716
- function compareOrdered(actual, expected, cmp) {
717
- if (actual == null || expected == null)
718
- return false;
719
- if (typeof actual === 'number' && typeof expected === 'number') {
720
- return cmp(actual, expected);
721
- }
722
- if (typeof actual === 'string' && typeof expected === 'string') {
723
- return cmp(actual, expected);
724
- }
725
- return false;
726
- }
727
- /** Translate a SQL LIKE/ILIKE pattern to a JS regex (`%` → `.*`, `_` → `.`). */
728
- function likeRegex(pattern, insensitive) {
729
- // Escape regex specials *except* `%` and `_`, then translate those.
730
- const escaped = pattern.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&');
731
- const body = escaped.replace(/%/g, '.*').replace(/_/g, '.');
732
- return new RegExp(`^${body}$`, insensitive ? 'i' : '');
733
- }
734
- /**
735
- * Schema fields are camelCase (`sectionId`); the wire query expects
736
- * the server-side column name. The query server's input resolver
737
- * casing-folds, but we send snake_case to match the convention used
738
- * by the existing loaders' postQuery calls (`'section_id'` etc.).
739
- */
740
- function columnize(field) {
741
- return field.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);
742
- }