@abloatai/ablo 0.25.0 → 0.27.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 (425) hide show
  1. package/AGENTS.md +5 -3
  2. package/CHANGELOG.md +34 -0
  3. package/README.md +104 -88
  4. package/dist/BaseSyncedStore.d.ts +140 -266
  5. package/dist/BaseSyncedStore.js +338 -739
  6. package/dist/Database.d.ts +62 -77
  7. package/dist/Database.js +106 -127
  8. package/dist/{ObjectPool.d.ts → InstanceCache.d.ts} +10 -13
  9. package/dist/{ObjectPool.js → InstanceCache.js} +91 -83
  10. package/dist/LazyReferenceCollection.d.ts +11 -15
  11. package/dist/LazyReferenceCollection.js +16 -15
  12. package/dist/Model.d.ts +37 -52
  13. package/dist/Model.js +52 -69
  14. package/dist/ModelRegistry.d.ts +46 -25
  15. package/dist/ModelRegistry.js +32 -30
  16. package/dist/NetworkMonitor.d.ts +5 -6
  17. package/dist/NetworkMonitor.js +6 -7
  18. package/dist/SyncClient.d.ts +119 -109
  19. package/dist/SyncClient.js +303 -224
  20. package/dist/SyncEngineContext.d.ts +1 -3
  21. package/dist/SyncEngineContext.js +1 -2
  22. package/dist/adapters/alwaysOnline.d.ts +6 -8
  23. package/dist/adapters/alwaysOnline.js +6 -8
  24. package/dist/adapters/inMemoryStorage.d.ts +9 -9
  25. package/dist/adapters/inMemoryStorage.js +9 -9
  26. package/dist/agent/Agent.d.ts +39 -31
  27. package/dist/agent/Agent.js +35 -23
  28. package/dist/agent/index.d.ts +4 -4
  29. package/dist/agent/index.js +5 -5
  30. package/dist/agent/session.d.ts +47 -44
  31. package/dist/agent/session.js +37 -48
  32. package/dist/agent/types.d.ts +26 -31
  33. package/dist/agent/types.js +6 -7
  34. package/dist/ai-sdk/coordinatedTool.d.ts +108 -0
  35. package/dist/ai-sdk/{coordinated-tool.js → coordinatedTool.js} +44 -38
  36. package/dist/ai-sdk/coordinationContext.d.ts +46 -0
  37. package/dist/ai-sdk/{coordination-context.js → coordinationContext.js} +30 -31
  38. package/dist/ai-sdk/index.d.ts +25 -22
  39. package/dist/ai-sdk/index.js +25 -22
  40. package/dist/ai-sdk/wrap.d.ts +7 -8
  41. package/dist/ai-sdk/wrap.js +2 -2
  42. package/dist/auth/credentialPolicy.d.ts +74 -71
  43. package/dist/auth/credentialPolicy.js +51 -56
  44. package/dist/auth/credentialSource.d.ts +7 -18
  45. package/dist/auth/credentialSource.js +10 -18
  46. package/dist/auth/index.d.ts +59 -58
  47. package/dist/auth/index.js +34 -40
  48. package/dist/auth/schemas.d.ts +5 -4
  49. package/dist/auth/schemas.js +5 -4
  50. package/dist/batching/index.d.ts +19 -21
  51. package/dist/batching/index.js +14 -17
  52. package/dist/cli.cjs +483 -369
  53. package/dist/client/Ablo.d.ts +107 -836
  54. package/dist/client/Ablo.js +174 -833
  55. package/dist/client/ApiClient.d.ts +44 -20
  56. package/dist/client/ApiClient.js +193 -44
  57. package/dist/client/auth.d.ts +51 -60
  58. package/dist/client/auth.js +137 -110
  59. package/dist/client/claimHeartbeatLoop.d.ts +50 -0
  60. package/dist/client/claimHeartbeatLoop.js +88 -0
  61. package/dist/client/consoleLogger.d.ts +35 -0
  62. package/dist/client/consoleLogger.js +44 -0
  63. package/dist/client/createInternalComponents.d.ts +14 -17
  64. package/dist/client/createInternalComponents.js +26 -31
  65. package/dist/client/createModelProxy.d.ts +130 -120
  66. package/dist/client/createModelProxy.js +158 -124
  67. package/dist/client/credentialEndpoint.d.ts +61 -0
  68. package/dist/client/credentialEndpoint.js +86 -0
  69. package/dist/client/functionalUpdate.d.ts +29 -27
  70. package/dist/client/functionalUpdate.js +21 -21
  71. package/dist/client/hostedEndpoints.d.ts +21 -0
  72. package/dist/client/hostedEndpoints.js +21 -0
  73. package/dist/client/httpClient.d.ts +58 -54
  74. package/dist/client/httpClient.js +29 -31
  75. package/dist/client/identity.d.ts +15 -20
  76. package/dist/client/identity.js +49 -59
  77. package/dist/client/modelRegistration.d.ts +10 -0
  78. package/dist/client/modelRegistration.js +301 -0
  79. package/dist/client/options.d.ts +373 -0
  80. package/dist/client/options.js +6 -0
  81. package/dist/client/registerDataSource.d.ts +9 -9
  82. package/dist/client/registerDataSource.js +15 -16
  83. package/dist/client/resourceTypes.d.ts +333 -0
  84. package/dist/client/resourceTypes.js +7 -0
  85. package/dist/client/schemaConfig.d.ts +44 -0
  86. package/dist/client/schemaConfig.js +176 -0
  87. package/dist/client/sessionMint.d.ts +17 -13
  88. package/dist/client/sessionMint.js +26 -31
  89. package/dist/client/validateAbloOptions.d.ts +12 -14
  90. package/dist/client/validateAbloOptions.js +9 -10
  91. package/dist/client/writeOptionsSchema.d.ts +18 -16
  92. package/dist/client/writeOptionsSchema.js +23 -20
  93. package/dist/client/wsMutationExecutor.d.ts +28 -0
  94. package/dist/client/wsMutationExecutor.js +71 -0
  95. package/dist/context.d.ts +6 -4
  96. package/dist/context.js +6 -7
  97. package/dist/coordination/index.d.ts +13 -4
  98. package/dist/coordination/index.js +29 -4
  99. package/dist/coordination/schema.d.ts +176 -128
  100. package/dist/coordination/schema.js +197 -133
  101. package/dist/coordination/trace.d.ts +9 -11
  102. package/dist/coordination/trace.js +13 -15
  103. package/dist/core/DatabaseManager.d.ts +5 -8
  104. package/dist/core/DatabaseManager.js +38 -40
  105. package/dist/core/QueryProcessor.d.ts +7 -9
  106. package/dist/core/QueryProcessor.js +27 -34
  107. package/dist/core/QueryView.d.ts +17 -5
  108. package/dist/core/QueryView.js +6 -7
  109. package/dist/core/StoreManager.d.ts +14 -16
  110. package/dist/core/StoreManager.js +26 -25
  111. package/dist/core/ViewRegistry.d.ts +5 -5
  112. package/dist/core/ViewRegistry.js +4 -4
  113. package/dist/core/index.d.ts +18 -13
  114. package/dist/core/index.js +32 -26
  115. package/dist/core/openIDBWithTimeout.d.ts +38 -36
  116. package/dist/core/openIDBWithTimeout.js +57 -54
  117. package/dist/core/queryUtils.d.ts +45 -0
  118. package/dist/core/queryUtils.js +69 -0
  119. package/dist/core/storeContract.d.ts +145 -0
  120. package/dist/core/storeContract.js +12 -0
  121. package/dist/environment.d.ts +28 -0
  122. package/dist/environment.js +21 -0
  123. package/dist/errorCodes.d.ts +118 -101
  124. package/dist/errorCodes.js +277 -260
  125. package/dist/errors.d.ts +170 -165
  126. package/dist/errors.js +161 -151
  127. package/dist/index.d.ts +30 -27
  128. package/dist/index.js +90 -82
  129. package/dist/interfaces/index.d.ts +108 -133
  130. package/dist/interfaces/index.js +5 -4
  131. package/dist/keys/index.d.ts +27 -29
  132. package/dist/keys/index.js +59 -49
  133. package/dist/mutators/RecordingTransaction.d.ts +16 -16
  134. package/dist/mutators/RecordingTransaction.js +31 -37
  135. package/dist/mutators/Transaction.d.ts +18 -26
  136. package/dist/mutators/Transaction.js +14 -20
  137. package/dist/mutators/UndoManager.d.ts +122 -131
  138. package/dist/mutators/UndoManager.js +149 -155
  139. package/dist/mutators/defineMutators.d.ts +24 -37
  140. package/dist/mutators/defineMutators.js +14 -20
  141. package/dist/mutators/inverseOp.d.ts +12 -15
  142. package/dist/mutators/inverseOp.js +12 -15
  143. package/dist/mutators/mutateActions.d.ts +10 -9
  144. package/dist/mutators/mutateActions.js +1 -1
  145. package/dist/mutators/readerActions.d.ts +9 -8
  146. package/dist/mutators/readerActions.js +2 -2
  147. package/dist/mutators/undoApply.d.ts +31 -27
  148. package/dist/mutators/undoApply.js +26 -24
  149. package/dist/policy/index.d.ts +5 -3
  150. package/dist/policy/index.js +5 -3
  151. package/dist/policy/types.d.ts +105 -101
  152. package/dist/policy/types.js +67 -66
  153. package/dist/query/client.d.ts +32 -16
  154. package/dist/query/client.js +103 -72
  155. package/dist/query/types.d.ts +37 -60
  156. package/dist/query/types.js +13 -33
  157. package/dist/react/AbloProvider.d.ts +7 -11
  158. package/dist/react/AbloProvider.js +24 -17
  159. package/dist/react/context.d.ts +27 -146
  160. package/dist/react/context.js +9 -10
  161. package/dist/react/index.d.ts +41 -42
  162. package/dist/react/index.js +37 -38
  163. package/dist/react/internalContext.d.ts +17 -19
  164. package/dist/react/useAblo.d.ts +23 -22
  165. package/dist/react/useAblo.js +17 -15
  166. package/dist/react/useCurrentUserId.d.ts +8 -7
  167. package/dist/react/useCurrentUserId.js +8 -7
  168. package/dist/react/useErrorListener.d.ts +7 -7
  169. package/dist/react/useErrorListener.js +11 -12
  170. package/dist/react/useMutationFailureListener.d.ts +8 -8
  171. package/dist/react/useMutationFailureListener.js +9 -9
  172. package/dist/react/useMutators.d.ts +11 -11
  173. package/dist/react/useMutators.js +10 -4
  174. package/dist/react/useReactive.js +2 -3
  175. package/dist/react/useSyncStatus.d.ts +4 -6
  176. package/dist/react/useUndoScope.d.ts +7 -9
  177. package/dist/react/useUndoScope.js +3 -3
  178. package/dist/schema/coordination.d.ts +21 -25
  179. package/dist/schema/coordination.js +21 -25
  180. package/dist/schema/ddl.d.ts +43 -39
  181. package/dist/schema/ddl.js +75 -68
  182. package/dist/schema/ddlLock.d.ts +35 -0
  183. package/dist/schema/ddlLock.js +46 -0
  184. package/dist/schema/diff.d.ts +99 -61
  185. package/dist/schema/diff.js +43 -34
  186. package/dist/schema/field.d.ts +37 -42
  187. package/dist/schema/field.js +36 -49
  188. package/dist/schema/generate.d.ts +12 -12
  189. package/dist/schema/generate.js +12 -12
  190. package/dist/schema/index.d.ts +5 -4
  191. package/dist/schema/index.js +29 -21
  192. package/dist/schema/model.d.ts +121 -146
  193. package/dist/schema/model.js +24 -35
  194. package/dist/schema/openapi.d.ts +10 -9
  195. package/dist/schema/openapi.js +7 -1
  196. package/dist/schema/queries.d.ts +30 -32
  197. package/dist/schema/queries.js +24 -25
  198. package/dist/schema/relation.d.ts +89 -99
  199. package/dist/schema/relation.js +13 -13
  200. package/dist/schema/residency.d.ts +38 -0
  201. package/dist/schema/residency.js +30 -0
  202. package/dist/schema/roles.d.ts +45 -27
  203. package/dist/schema/roles.js +52 -21
  204. package/dist/schema/schema.d.ts +36 -45
  205. package/dist/schema/schema.js +42 -39
  206. package/dist/schema/select.d.ts +13 -13
  207. package/dist/schema/select.js +13 -13
  208. package/dist/schema/serialize.d.ts +36 -39
  209. package/dist/schema/serialize.js +27 -31
  210. package/dist/schema/sugar.d.ts +17 -32
  211. package/dist/schema/sugar.js +14 -29
  212. package/dist/schema/{sync-delta-row.d.ts → syncDeltaRow.d.ts} +27 -50
  213. package/dist/schema/syncDeltaRow.js +89 -0
  214. package/dist/schema/tenancy.d.ts +44 -46
  215. package/dist/schema/tenancy.js +46 -48
  216. package/dist/server/adapter.d.ts +58 -58
  217. package/dist/server/adapter.js +13 -14
  218. package/dist/server/commit.d.ts +60 -64
  219. package/dist/server/index.d.ts +9 -10
  220. package/dist/server/index.js +1 -1
  221. package/dist/server/readConfig.d.ts +70 -0
  222. package/dist/server/readConfig.js +8 -0
  223. package/dist/server/storageMode.d.ts +23 -0
  224. package/dist/server/storageMode.js +17 -0
  225. package/dist/source/adapter.d.ts +31 -26
  226. package/dist/source/adapter.js +10 -10
  227. package/dist/source/adapters/drizzle.d.ts +28 -23
  228. package/dist/source/adapters/drizzle.js +34 -28
  229. package/dist/source/adapters/kysely.d.ts +27 -25
  230. package/dist/source/adapters/kysely.js +28 -26
  231. package/dist/source/adapters/memory.d.ts +8 -7
  232. package/dist/source/adapters/memory.js +10 -9
  233. package/dist/source/adapters/prisma.d.ts +13 -12
  234. package/dist/source/adapters/prisma.js +27 -29
  235. package/dist/source/conformance.d.ts +18 -11
  236. package/dist/source/conformance.js +27 -19
  237. package/dist/source/connector.d.ts +31 -32
  238. package/dist/source/connector.js +30 -28
  239. package/dist/source/connectorProtocol.d.ts +160 -0
  240. package/dist/source/connectorProtocol.js +162 -0
  241. package/dist/source/contract.d.ts +26 -27
  242. package/dist/source/contract.js +28 -29
  243. package/dist/source/factory.d.ts +94 -0
  244. package/dist/source/factory.js +268 -0
  245. package/dist/source/index.d.ts +10 -462
  246. package/dist/source/index.js +17 -421
  247. package/dist/source/migrations.d.ts +9 -9
  248. package/dist/source/migrations.js +9 -9
  249. package/dist/source/next.d.ts +10 -11
  250. package/dist/source/next.js +7 -8
  251. package/dist/source/pushQueue.d.ts +70 -48
  252. package/dist/source/pushQueue.js +36 -29
  253. package/dist/source/signing.d.ts +88 -0
  254. package/dist/source/signing.js +159 -0
  255. package/dist/source/types.d.ts +351 -0
  256. package/dist/source/types.js +43 -0
  257. package/dist/stores/ObjectStore.d.ts +11 -12
  258. package/dist/stores/ObjectStore.js +34 -35
  259. package/dist/stores/ObjectStoreContract.d.ts +12 -15
  260. package/dist/stores/SyncActionStore.d.ts +8 -12
  261. package/dist/stores/SyncActionStore.js +77 -46
  262. package/dist/surface.d.ts +28 -21
  263. package/dist/surface.js +28 -20
  264. package/dist/sync/{BootstrapHelper.d.ts → BootstrapFetcher.d.ts} +37 -45
  265. package/dist/sync/{BootstrapHelper.js → BootstrapFetcher.js} +101 -80
  266. package/dist/sync/ConnectionManager.d.ts +47 -50
  267. package/dist/sync/ConnectionManager.js +74 -70
  268. package/dist/sync/NetworkProbe.d.ts +27 -31
  269. package/dist/sync/NetworkProbe.js +67 -72
  270. package/dist/sync/{HydrationCoordinator.d.ts → OnDemandLoader.d.ts} +49 -36
  271. package/dist/sync/{HydrationCoordinator.js → OnDemandLoader.js} +79 -54
  272. package/dist/sync/{AreaOfInterestManager.d.ts → SubscriptionManager.d.ts} +45 -59
  273. package/dist/sync/{AreaOfInterestManager.js → SubscriptionManager.js} +44 -52
  274. package/dist/sync/SyncWebSocket.d.ts +175 -250
  275. package/dist/sync/SyncWebSocket.js +431 -769
  276. package/dist/sync/awaitClaimGrant.d.ts +18 -18
  277. package/dist/sync/awaitClaimGrant.js +38 -30
  278. package/dist/sync/bootstrapApply.d.ts +70 -0
  279. package/dist/sync/bootstrapApply.js +73 -0
  280. package/dist/sync/commitFrames.d.ts +44 -0
  281. package/dist/sync/commitFrames.js +94 -0
  282. package/dist/sync/createClaimStream.d.ts +23 -22
  283. package/dist/sync/createClaimStream.js +108 -25
  284. package/dist/sync/createPresenceStream.d.ts +19 -18
  285. package/dist/sync/createPresenceStream.js +25 -26
  286. package/dist/sync/createSnapshot.d.ts +13 -17
  287. package/dist/sync/createSnapshot.js +20 -26
  288. package/dist/sync/credentialLifecycle.d.ts +175 -0
  289. package/dist/sync/credentialLifecycle.js +322 -0
  290. package/dist/sync/deltaPipeline.d.ts +113 -0
  291. package/dist/sync/deltaPipeline.js +261 -0
  292. package/dist/sync/groupChange.d.ts +113 -0
  293. package/dist/sync/groupChange.js +242 -0
  294. package/dist/sync/heartbeat.d.ts +63 -0
  295. package/dist/sync/heartbeat.js +91 -0
  296. package/dist/sync/participants.d.ts +27 -27
  297. package/dist/sync/schemas.d.ts +3 -2
  298. package/dist/sync/schemas.js +14 -10
  299. package/dist/sync/syncCursor.d.ts +40 -0
  300. package/dist/sync/syncCursor.js +55 -0
  301. package/dist/sync/syncPlan.d.ts +54 -0
  302. package/dist/sync/syncPlan.js +50 -0
  303. package/dist/sync/syncPosition.d.ts +54 -49
  304. package/dist/sync/syncPosition.js +57 -52
  305. package/dist/sync/wsFrameHandlers.d.ts +116 -0
  306. package/dist/sync/wsFrameHandlers.js +374 -0
  307. package/dist/testing/fixtures/bootstrap.d.ts +21 -17
  308. package/dist/testing/fixtures/bootstrap.js +12 -6
  309. package/dist/testing/fixtures/deltas.d.ts +31 -34
  310. package/dist/testing/fixtures/deltas.js +30 -33
  311. package/dist/testing/fixtures/models.d.ts +11 -10
  312. package/dist/testing/fixtures/models.js +12 -10
  313. package/dist/testing/helpers/{react-wrapper.d.ts → reactWrapper.d.ts} +13 -10
  314. package/dist/testing/helpers/{react-wrapper.js → reactWrapper.js} +15 -12
  315. package/dist/testing/helpers/{sync-engine-harness.d.ts → syncEngineHarness.d.ts} +17 -18
  316. package/dist/testing/helpers/{sync-engine-harness.js → syncEngineHarness.js} +14 -11
  317. package/dist/testing/helpers/wait.d.ts +13 -8
  318. package/dist/testing/helpers/wait.js +13 -8
  319. package/dist/testing/index.d.ts +4 -4
  320. package/dist/testing/index.js +3 -3
  321. package/dist/testing/mocks/MockMutationExecutor.d.ts +18 -17
  322. package/dist/testing/mocks/MockMutationExecutor.js +15 -14
  323. package/dist/testing/mocks/MockNetworkMonitor.d.ts +8 -8
  324. package/dist/testing/mocks/MockNetworkMonitor.js +8 -8
  325. package/dist/testing/mocks/MockSyncContext.d.ts +21 -34
  326. package/dist/testing/mocks/MockSyncContext.js +16 -45
  327. package/dist/testing/mocks/MockSyncStore.d.ts +14 -14
  328. package/dist/testing/mocks/MockSyncStore.js +11 -11
  329. package/dist/testing/mocks/MockWebSocket.d.ts +28 -24
  330. package/dist/testing/mocks/MockWebSocket.js +22 -21
  331. package/dist/transactions/TransactionQueue.d.ts +190 -221
  332. package/dist/transactions/TransactionQueue.js +424 -822
  333. package/dist/transactions/TransactionStore.d.ts +20 -0
  334. package/dist/transactions/TransactionStore.js +53 -0
  335. package/dist/transactions/UnconfirmedWrites.d.ts +82 -0
  336. package/dist/transactions/UnconfirmedWrites.js +104 -0
  337. package/dist/transactions/coalesceRules.d.ts +58 -0
  338. package/dist/transactions/coalesceRules.js +140 -0
  339. package/dist/transactions/commitPayload.d.ts +130 -0
  340. package/dist/transactions/commitPayload.js +143 -0
  341. package/dist/transactions/deltaConfirmation.d.ts +58 -0
  342. package/dist/transactions/deltaConfirmation.js +215 -0
  343. package/dist/transactions/optimisticApply.d.ts +49 -0
  344. package/dist/transactions/optimisticApply.js +65 -0
  345. package/dist/transactions/replayValidation.d.ts +99 -0
  346. package/dist/transactions/replayValidation.js +111 -0
  347. package/dist/types/global.d.ts +46 -41
  348. package/dist/types/global.js +20 -19
  349. package/dist/types/index.d.ts +74 -80
  350. package/dist/types/index.js +22 -27
  351. package/dist/types/modelData.d.ts +10 -0
  352. package/dist/types/modelData.js +9 -0
  353. package/dist/types/participant.d.ts +20 -0
  354. package/dist/types/participant.js +10 -0
  355. package/dist/types/streams.d.ts +216 -209
  356. package/dist/types/streams.js +7 -7
  357. package/dist/utils/asyncIterator.d.ts +25 -32
  358. package/dist/utils/asyncIterator.js +25 -32
  359. package/dist/utils/duration.d.ts +12 -15
  360. package/dist/utils/duration.js +12 -15
  361. package/dist/utils/mobxSetup.d.ts +53 -0
  362. package/dist/utils/{mobx-setup.js → mobxSetup.js} +44 -100
  363. package/dist/webhooks/events.d.ts +21 -16
  364. package/dist/webhooks/events.js +10 -8
  365. package/dist/webhooks/index.d.ts +5 -7
  366. package/dist/webhooks/index.js +5 -7
  367. package/dist/{schema/sync-delta-wire.d.ts → wire/delta.d.ts} +58 -41
  368. package/dist/wire/delta.js +114 -0
  369. package/dist/wire/errorEnvelope.d.ts +35 -27
  370. package/dist/wire/errorEnvelope.js +38 -32
  371. package/dist/wire/frames.d.ts +150 -67
  372. package/dist/wire/frames.js +48 -1
  373. package/dist/wire/index.d.ts +18 -13
  374. package/dist/wire/index.js +36 -13
  375. package/dist/wire/listEnvelope.d.ts +16 -23
  376. package/dist/wire/listEnvelope.js +7 -6
  377. package/dist/wire/protocol.d.ts +38 -0
  378. package/dist/wire/protocol.js +38 -0
  379. package/dist/wire/protocolVersion.d.ts +60 -0
  380. package/dist/wire/protocolVersion.js +67 -0
  381. package/docs/api-keys.md +4 -3
  382. package/docs/coordination.md +59 -0
  383. package/docs/examples/existing-python-backend.md +3 -3
  384. package/docs/identity.md +4 -4
  385. package/docs/integration-guide.md +1 -1
  386. package/docs/react.md +1 -1
  387. package/docs/sessions.md +5 -7
  388. package/package.json +24 -21
  389. package/dist/ai-sdk/coordinated-tool.d.ts +0 -101
  390. package/dist/ai-sdk/coordination-context.d.ts +0 -52
  391. package/dist/client/index.d.ts +0 -36
  392. package/dist/client/index.js +0 -33
  393. package/dist/config/index.d.ts +0 -10
  394. package/dist/config/index.js +0 -12
  395. package/dist/core/query-utils.d.ts +0 -34
  396. package/dist/core/query-utils.js +0 -59
  397. package/dist/interfaces/headless.d.ts +0 -95
  398. package/dist/interfaces/headless.js +0 -41
  399. package/dist/query/index.d.ts +0 -6
  400. package/dist/query/index.js +0 -5
  401. package/dist/realtime/index.d.ts +0 -10
  402. package/dist/realtime/index.js +0 -9
  403. package/dist/schema/plane.d.ts +0 -23
  404. package/dist/schema/plane.js +0 -19
  405. package/dist/schema/sync-delta-row.js +0 -103
  406. package/dist/schema/sync-delta-wire.js +0 -102
  407. package/dist/server/next.d.ts +0 -51
  408. package/dist/server/next.js +0 -47
  409. package/dist/server/read-config.d.ts +0 -67
  410. package/dist/server/read-config.js +0 -8
  411. package/dist/server/storage-mode.d.ts +0 -1
  412. package/dist/server/storage-mode.js +0 -18
  413. package/dist/source/connector-protocol.d.ts +0 -159
  414. package/dist/source/connector-protocol.js +0 -161
  415. package/dist/sync/OfflineFlush.d.ts +0 -9
  416. package/dist/sync/OfflineFlush.js +0 -22
  417. package/dist/sync/OfflineTransactionStore.d.ts +0 -37
  418. package/dist/sync/OfflineTransactionStore.js +0 -263
  419. package/dist/transactions/OptimisticEchoTracker.d.ts +0 -82
  420. package/dist/transactions/OptimisticEchoTracker.js +0 -104
  421. package/dist/transactions/index.d.ts +0 -16
  422. package/dist/transactions/index.js +0 -7
  423. package/dist/transactions/mutation-error-handler.d.ts +0 -5
  424. package/dist/transactions/mutation-error-handler.js +0 -39
  425. package/dist/utils/mobx-setup.d.ts +0 -42
@@ -0,0 +1,333 @@
1
+ /**
2
+ * The shared resource types of the client: {@link ModelRead}, {@link ModelClient},
3
+ * the commit and claim shapes, the session-mint params and resource, and the
4
+ * {@link HttpClaimApi} derivation. This module holds only types and has no runtime
5
+ * imports.
6
+ */
7
+ import type { StaleNotification, ReadDependency } from '../coordination/schema.js';
8
+ import type { ModelTarget, ModelClaim } from '../coordination/schema.js';
9
+ export type { ModelTarget, ModelClaim };
10
+ import type { SchemaRecord } from '../schema/schema.js';
11
+ import type { SyncGroupInput } from '../schema/roles.js';
12
+ import type { Claim, ClaimStream, ClaimWaitOptions, Duration, HeldClaim } from '../types/streams.js';
13
+ import type { ModelUpdater, ContentionOptions } from './functionalUpdate.js';
14
+ import type { ClaimOptions, ClaimParams, ClaimReadApi, AwaitedClaimMethod, ServerReadOptions } from './createModelProxy.js';
15
+ /**
16
+ * The operations available on each model in the sync engine:
17
+ * `retrieve({ id })` — an async single-row server read
18
+ * `list({ where })` — an async collection server read
19
+ * `get(id)` / `getAll(...)` / `getCount(...)` — synchronous local-cache reads
20
+ * `create({ data })` / `update({ id, data })` / `delete({ id })` — writes
21
+ * `claim({ id })` — a durable claim handle for coordinated writes
22
+ */
23
+ export type { LocalCountOptions, LocalReadOptions, ModelListScope, ServerReadOptions, ModelRetrieveParams, ModelCreateParams, ModelUpdateParams, ModelDeleteParams, ClaimOptions, ClaimParams, ClaimLookupParams, ClaimReorderParams, Claim, ClaimHeartbeat, ClaimHeartbeatOptions, HeldClaim, ModelOperations, } from './createModelProxy.js';
24
+ export type ModelOperationAction = 'create' | 'update' | 'delete' | 'archive' | 'unarchive';
25
+ export type CommitWait = 'queued' | 'confirmed';
26
+ export interface ModelRead<T = Record<string, unknown>> {
27
+ /**
28
+ * The row, or `undefined` when no row matched the id (or it's outside the
29
+ * caller's scope). A miss is data-absence, not an error — `retrieve` never
30
+ * throws "not found", mirroring the WebSocket client's `T | undefined`.
31
+ * Branch on it: `const deal = (await ablo.deals.retrieve({ id })).data; if (!deal) …`.
32
+ */
33
+ readonly data: T | undefined;
34
+ readonly stamp: number;
35
+ readonly claims: readonly ModelClaim[];
36
+ }
37
+ export type IfClaimedPolicy = 'return' | 'fail';
38
+ export interface ClaimedOptions {
39
+ /**
40
+ * What to do when another participant has claimed the target: `return`
41
+ * includes active claim metadata in the response; `fail` throws
42
+ * `AbloClaimedError`. Waiting for a claim to clear is a claim-side concern —
43
+ * take `ablo.<model>.claim({ id })` (it queues fairly); reads never block.
44
+ */
45
+ readonly ifClaimed?: IfClaimedPolicy;
46
+ }
47
+ export type { ClaimWaitOptions } from '../types/streams.js';
48
+ export interface ModelReadOptions extends ClaimedOptions {
49
+ }
50
+ export interface ClaimCreateOptions {
51
+ readonly target: ModelTarget;
52
+ /** Human-readable phase shown to peers — `'editing'`, `'writing'`. The same
53
+ * word on every claim surface. */
54
+ readonly reason: string;
55
+ readonly ttl?: Duration;
56
+ /**
57
+ * Join the server's fair FIFO queue when the target is already claimed,
58
+ * rather than failing immediately. `create` then resolves only once the
59
+ * lease is actually ours (the server pushes `claim_acquired` if the target
60
+ * was free, or `claim_granted` when we reach the head of the line). Without
61
+ * this, a contended claim throws. Used by `ablo.<model>.claim` so writers
62
+ * serialize instead of racing.
63
+ */
64
+ readonly queue?: boolean;
65
+ /** Cap on how long to wait for a queued grant before rejecting. */
66
+ readonly waitTimeoutMs?: number;
67
+ /**
68
+ * Backpressure: reject with `AbloClaimedError('queue_too_deep')` instead of
69
+ * waiting if the queue is already `>= maxQueueDepth` when we join.
70
+ */
71
+ readonly maxQueueDepth?: number;
72
+ }
73
+ export interface CommitOperationInput {
74
+ readonly action: ModelOperationAction;
75
+ /** The model name — matches `ablo.<model>` and the schema's `model()`. */
76
+ readonly model?: string;
77
+ readonly target?: ModelTarget;
78
+ readonly id?: string | null;
79
+ readonly data?: Record<string, unknown> | null;
80
+ readonly transactionId?: string | null;
81
+ readonly readAt?: number | null;
82
+ readonly onStale?: 'reject' | 'overwrite' | 'notify' | null;
83
+ }
84
+ export interface CommitCreateOptions {
85
+ readonly claimRef?: string | {
86
+ readonly id: string;
87
+ } | null;
88
+ readonly idempotencyKey?: string | null;
89
+ readonly readAt?: number | null;
90
+ readonly onStale?: 'reject' | 'overwrite' | 'notify' | null;
91
+ /**
92
+ * A claim handle from `ablo.<model>.claim({ id })` (or the HTTP claim
93
+ * surface). Same vocabulary as the per-model writes: the handle's
94
+ * snapshot watermark becomes the batch `readAt` default and `onStale`
95
+ * defaults to `'reject'`, so a commit that follows a claim is guarded
96
+ * against concurrent edits without re-stating the watermark by hand.
97
+ * Explicit `readAt`/`onStale` on the options win.
98
+ */
99
+ readonly claim?: Claim | null;
100
+ readonly operation?: CommitOperationInput;
101
+ readonly operations?: readonly CommitOperationInput[];
102
+ readonly wait?: CommitWait;
103
+ /**
104
+ * Batch-level read dependencies — the "did anything I looked at change?" guard.
105
+ * Declare the rows (`{ model, id, readAt, fields? }`) or sync groups
106
+ * (`{ group, readAt }`, for example `deck:abc`) this batch was premised on; the
107
+ * server checks that none moved since `readAt` and fires the entry's `onStale`
108
+ * over the batch. This is distinct from the write-target `readAt`: it guards what
109
+ * you read, not what you write.
110
+ */
111
+ readonly reads?: readonly ReadDependency[] | null;
112
+ }
113
+ export interface CommitReceipt {
114
+ readonly id: string;
115
+ readonly status: CommitWait;
116
+ readonly lastSyncId?: number;
117
+ /**
118
+ * Stale-context notifications: present only when this commit guarded a write with
119
+ * `onStale: 'notify'` and the premise moved concurrently. Each carries the
120
+ * conflicting field's current value, handed back as data rather than raising an
121
+ * `AbloStaleContextError`, so the caller — an agent or a human — decides how to
122
+ * resolve it.
123
+ */
124
+ readonly notifications?: readonly StaleNotification[];
125
+ /**
126
+ * Ids of update or delete targets in this commit that matched no rows, because
127
+ * the row does not exist or is outside the caller's organization. Present and
128
+ * non-empty only when a write missed. The typed resource wrappers turn this into
129
+ * an `AbloNotFoundError`; a raw `commits.create` caller can inspect it directly.
130
+ */
131
+ readonly missingIds?: readonly string[];
132
+ }
133
+ export interface CommitResource {
134
+ create(options: CommitCreateOptions): Promise<CommitReceipt>;
135
+ }
136
+ export interface ClaimResource extends ClaimStream {
137
+ create(options: ClaimCreateOptions): Promise<Claim>;
138
+ list(target?: Partial<ModelTarget>): readonly ModelClaim[];
139
+ waitFor(target: Partial<ModelTarget>, options?: ClaimWaitOptions): Promise<void>;
140
+ }
141
+ export interface ModelMutationOptions extends ClaimedOptions {
142
+ readonly claimRef?: string | {
143
+ readonly id: string;
144
+ } | null;
145
+ readonly idempotencyKey?: string | null;
146
+ readonly readAt?: number | null;
147
+ readonly onStale?: 'reject' | 'overwrite' | 'notify' | null;
148
+ readonly wait?: CommitWait;
149
+ readonly claim?: Claim | ClaimOptions | null;
150
+ }
151
+ /**
152
+ * The stateless HTTP claim surface. Most code puts a `claim` directly on the write
153
+ * (`update({ id, data, claim })`) and lets the SDK release it; reach for this
154
+ * namespace for multi-step handles and coordination screens.
155
+ *
156
+ * It is the same surface as the reactive claim API, but because every read is a
157
+ * server round-trip, `state`, `queue`, and `reorder` are awaited here. The
158
+ * WebSocket client resolves those synchronously from its local cache, which is what
159
+ * lets it read a claim's state inside a React render; a stateless client has no
160
+ * cache to read, so the promise is unavoidable.
161
+ *
162
+ * It is derived from `ClaimReadApi` through {@link AwaitedClaimMethod} so the two
163
+ * transports cannot drift: the only difference is the promise wrapper that
164
+ * statelessness forces. `claim({ id })` is identical on both (already async);
165
+ * `state`, `queue`, `reorder`, and `release` are the awaited form.
166
+ */
167
+ export type HttpClaimApi<T = Record<string, unknown>> = ((params: ClaimParams<T>) => Promise<HeldClaim<T>>) & {
168
+ [K in keyof ClaimReadApi<T>]: AwaitedClaimMethod<ClaimReadApi<T>[K]>;
169
+ };
170
+ export interface ModelClient<T = Record<string, unknown>> {
171
+ /**
172
+ * Single-row read over HTTP. **Returns an envelope, not the bare row** — the
173
+ * row is on `.data`, alongside the `.stamp` watermark (for stale-context
174
+ * guards on the following write) and any active `.claims`. A stateless HTTP
175
+ * client can't synthesize the watermark from a local snapshot, so the
176
+ * envelope is load-bearing here (the WebSocket client's `retrieve` returns
177
+ * `T | undefined` because it reads from its local cache).
178
+ *
179
+ * ```ts
180
+ * const deal = await ablo.deals.retrieve({ id });
181
+ * deal.data?.recommendation; // ← the row is on .data
182
+ * deal.stamp; // watermark — pass to the next write's readAt
183
+ * ```
184
+ */
185
+ retrieve(params: ModelReadOptions & {
186
+ readonly id: string;
187
+ }): Promise<ModelRead<T>>;
188
+ /**
189
+ * Collection read over HTTP (server round-trip). Equality `where`, `orderBy`,
190
+ * `limit`. Present on the stateless protocol client; the store-backed
191
+ * `.model(name)` accessor omits it (use the typed `ablo.<model>.list` there).
192
+ */
193
+ list?(options?: ServerReadOptions<T>): Promise<T[]>;
194
+ /**
195
+ * Creates a row and returns the confirmed server row, including framework
196
+ * defaults such as `createdAt` and `createdBy`. Matches the stateful client's
197
+ * `create`. Passing an id that already exists is idempotent: the existing row is
198
+ * returned, not the input.
199
+ */
200
+ create(params: ModelMutationOptions & {
201
+ readonly data: Record<string, unknown>;
202
+ readonly id?: string | null;
203
+ }): Promise<T>;
204
+ update(params: ModelMutationOptions & {
205
+ readonly id: string;
206
+ readonly data: Record<string, unknown>;
207
+ }): Promise<CommitReceipt>;
208
+ /**
209
+ * Update under contention with a function of the latest state —
210
+ * `update(id, current => next)`, the `setState(prev => next)` of the data
211
+ * layer. The SDK reads the freshest row, runs your updater, writes it as a
212
+ * compare-and-swap against the row's watermark, and re-reads + re-runs on any
213
+ * concurrent write. No claim, no identity, no conflict codes surface: the
214
+ * write either lands or throws {@link AbloContentionError} once its reconcile
215
+ * budget is spent. Return `null`/`undefined` from the updater to skip the
216
+ * write (resolves to `undefined`).
217
+ */
218
+ update(id: string, updater: ModelUpdater<T>, options?: ContentionOptions): Promise<CommitReceipt | undefined>;
219
+ delete(params: ModelMutationOptions & {
220
+ readonly id: string;
221
+ }): Promise<CommitReceipt>;
222
+ /**
223
+ * Durable lease + FIFO wait-line over HTTP — coordination without a socket.
224
+ * Present on the stateless protocol client (`Ablo({ schema: null })` /
225
+ * `createAbloHttpClient`); the store-backed `.model(name)` accessor omits it
226
+ * (the typed `ablo.<model>.claim` proxy is the full reactive namespace there).
227
+ */
228
+ claim?: HttpClaimApi<T>;
229
+ }
230
+ /** A single data operation a scoped **agent** session may perform on a model. */
231
+ export type SessionOperation = 'read' | 'create' | 'update' | 'delete';
232
+ /** Parameters for minting an end-user session — full data authority within the
233
+ * organization. Mints an `ek_` token. `user.id` is your end user's id from your
234
+ * own identity provider and becomes the session's `participantId`; Ablo does not
235
+ * model your users, so it is treated as an opaque string at the trust boundary. */
236
+ export interface CreateUserSessionParams {
237
+ /** Your end user. `id` becomes the token's `participantId`. */
238
+ user: {
239
+ id: string;
240
+ };
241
+ /** Mint the session into this organization instead of the key's own — for a
242
+ * platform that serves many tenants from one backend. Requires the `sk_` key to
243
+ * carry the `ephemeral:mint-any-org` scope; omit it for the normal
244
+ * single-tenant case. */
245
+ organizationId?: string;
246
+ /** Sync groups this session may subscribe to — typed (`'default'` or
247
+ * `<namespace>:<id>`; build with `syncGroup(kind, id)` from
248
+ * `@abloatai/ablo/schema`). Omit for the server default:
249
+ * `[org:<your org>, user:<user.id>]`. */
250
+ syncGroups?: readonly SyncGroupInput[];
251
+ /** Token lifetime in seconds. Defaults to 900 (15 minutes). */
252
+ ttlSeconds?: number;
253
+ /** Opaque identity blob echoed back to the client as `ablo.user`. */
254
+ userMeta?: Record<string, unknown>;
255
+ agent?: never;
256
+ can?: never;
257
+ }
258
+ /** Mint params for a scoped **agent** session — mints a restricted `rk_` token
259
+ * gated to exactly the operations named in `can`. `can` is typed off your
260
+ * schema (no magic `'task.update'` strings): `{ Task: ['update'], Deck: ['read'] }`
261
+ * — the SDK serializes each entry to the wire allowlist (`task.update`). */
262
+ export interface CreateAgentSessionParams<S extends SchemaRecord> {
263
+ /** Your agent. `id` becomes the token's `participantId`. */
264
+ agent: {
265
+ id: string;
266
+ };
267
+ /** Per-model operation allowlist, typed against the schema's model names. */
268
+ can: Partial<Record<keyof S & string, readonly SessionOperation[]>>;
269
+ /** Sync groups this session may subscribe to — typed (`'default'` or
270
+ * `<namespace>:<id>`; build with `syncGroup(kind, id)` from
271
+ * `@abloatai/ablo/schema`). Omit for the server default: the org
272
+ * anchor (`org:<your org>`) + the agent's own anchor. */
273
+ syncGroups?: readonly SyncGroupInput[];
274
+ /** Token lifetime in seconds. Defaults to 900 (15 minutes). */
275
+ ttlSeconds?: number;
276
+ /** Opaque identity blob echoed back to the client as `ablo.agent`. */
277
+ userMeta?: Record<string, unknown>;
278
+ user?: never;
279
+ }
280
+ /** Params for {@link Ablo.sessions}.create — a discriminated union: pass
281
+ * `{ user }` for a full-authority end-user session (`ek_`) or `{ agent, can }`
282
+ * for a scoped agent session (`rk_`). */
283
+ export type CreateSessionParams<S extends SchemaRecord> = CreateUserSessionParams | CreateAgentSessionParams<S>;
284
+ /** Params for {@link Ablo.agents}.create — a flattened agent descriptor (no
285
+ * `{ agent }` discriminator: `agents.create` only ever mints an agent). Unlike
286
+ * {@link CreateSessionParams} it resolves to a connected, scoped {@link Ablo}
287
+ * client rather than a raw token. */
288
+ export interface CreateAgentClientParams<S extends SchemaRecord> {
289
+ /** The wire participant identity (`agent:<id>`) that claim exclusion and the
290
+ * FIFO queue gate on. Omit it to get a fresh random id — a distinct, independent
291
+ * participant, which is the default and what you want for concurrent agents.
292
+ * Pass a stable string only when one logical agent must re-attach to its own
293
+ * held claims across reconnects or restarts. */
294
+ id?: string;
295
+ /** A human-readable label for logs and attribution (carried in `userMeta.name`).
296
+ * It is independent of `id`: two agents that share a `name` still receive
297
+ * distinct ids and coordinate as separate participants — `name` never derives or
298
+ * collapses identity. */
299
+ name?: string;
300
+ /** Per-model operation allowlist, typed against the schema's model names. */
301
+ can: Partial<Record<keyof S & string, readonly SessionOperation[]>>;
302
+ /** Sync groups this agent may subscribe to — typed (`'default'` or
303
+ * `<namespace>:<id>`). Omit for the server default (org anchor + the
304
+ * agent's own anchor). */
305
+ syncGroups?: readonly SyncGroupInput[];
306
+ /** Token lifetime in seconds. Defaults to 900 (15 minutes); the returned client
307
+ * re-mints before expiry, so a long-running agent never handles rotation
308
+ * itself. */
309
+ ttlSeconds?: number;
310
+ /** Extra opaque identity blob echoed on the session scope. Merged with
311
+ * `name` (the `name` param wins if you also set `userMeta.name`). */
312
+ userMeta?: Record<string, unknown>;
313
+ }
314
+ /** A minted session. `token` is the secret the holder presents as its bearer. */
315
+ export interface AbloSession {
316
+ object: 'session';
317
+ /** Stable id of the minted credential (for revocation). */
318
+ id: string;
319
+ /** The short-lived session token — `ek_` for a `{ user }` session, `rk_`
320
+ * for an `{ agent }` session. Hand this to the participant's runtime. */
321
+ token: string;
322
+ /** ISO-8601 expiry. */
323
+ expiresAt: string;
324
+ organizationId: string;
325
+ scope: {
326
+ organizationId: string;
327
+ syncGroups: readonly string[];
328
+ operations: readonly string[];
329
+ participantKind: 'user' | 'agent' | 'system';
330
+ participantId: string;
331
+ };
332
+ userMeta: Record<string, unknown>;
333
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * The shared resource types of the client: {@link ModelRead}, {@link ModelClient},
3
+ * the commit and claim shapes, the session-mint params and resource, and the
4
+ * {@link HttpClaimApi} derivation. This module holds only types and has no runtime
5
+ * imports.
6
+ */
7
+ export {};
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Derives engine configuration from a schema. This module holds two pure
3
+ * functions: {@link computeFKDepthPriority} works out a safe row-insertion
4
+ * order from the schema's foreign-key relations, and
5
+ * {@link deriveConfigFromSchema} packages that ordering, together with a few
6
+ * defaults, into the {@link SyncEngineConfig} a client uses at startup. Both
7
+ * are deterministic transforms of the schema and hold no engine state.
8
+ */
9
+ import type { Schema } from '../schema/schema.js';
10
+ import type { SyncEngineConfig } from '../interfaces/index.js';
11
+ /**
12
+ * Computes a create-priority map that gives the engine a safe order for
13
+ * inserting rows, so a child row is never written before the parent its
14
+ * foreign key references.
15
+ *
16
+ * Every `belongsTo` relation is an edge from a child model to its parent. This
17
+ * function runs Tarjan's strongly-connected-components algorithm over that
18
+ * graph, which does two things at once: it groups any models that reference
19
+ * each other in a cycle into a single component, and it produces those
20
+ * components in an order where parents come before children. Each model then
21
+ * gets a numeric priority from that order, where a lower number means "insert
22
+ * earlier". Top-level models with no parent — an organization or a theme, say —
23
+ * come first, and the deepest descendants come last.
24
+ *
25
+ * Models in the same cycle share a priority, so within a cycle the order rows
26
+ * were queued in breaks the tie. To break a cycle deterministically instead,
27
+ * mark one side of it with `belongsTo(target, fk, { defer: true })`. A deferred
28
+ * edge is left out of the graph, which turns the cycle into a chain and gives
29
+ * the deferred child a strictly higher priority than its parent. Pair it with a
30
+ * Postgres `DEFERRABLE INITIALLY DEFERRED` constraint if you also want the
31
+ * database to relax its check. See {@link BelongsToOptions.defer}.
32
+ *
33
+ * The returned map is keyed by each model's wire type name
34
+ * ({@link ModelDef.typename}, falling back to the schema key), because that is
35
+ * the name the engine looks up at commit time. Keying by the schema key would
36
+ * miss that lookup, and every model would fall back to the default priority.
37
+ *
38
+ * The result does not depend on which model the walk starts from, and the
39
+ * algorithm runs in time linear in the number of models plus relations.
40
+ * Reference: Tarjan, R. (1972), "Depth-first search and linear graph
41
+ * algorithms."
42
+ */
43
+ export declare function computeFKDepthPriority(schema: Schema): ReadonlyMap<string, number>;
44
+ export declare function deriveConfigFromSchema(schema: Schema): SyncEngineConfig;
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Derives engine configuration from a schema. This module holds two pure
3
+ * functions: {@link computeFKDepthPriority} works out a safe row-insertion
4
+ * order from the schema's foreign-key relations, and
5
+ * {@link deriveConfigFromSchema} packages that ordering, together with a few
6
+ * defaults, into the {@link SyncEngineConfig} a client uses at startup. Both
7
+ * are deterministic transforms of the schema and hold no engine state.
8
+ */
9
+ import { schemaHash } from '../schema/serialize.js';
10
+ // ── Config derivation from schema ─────────────────────────────────────────
11
+ /**
12
+ * Computes a create-priority map that gives the engine a safe order for
13
+ * inserting rows, so a child row is never written before the parent its
14
+ * foreign key references.
15
+ *
16
+ * Every `belongsTo` relation is an edge from a child model to its parent. This
17
+ * function runs Tarjan's strongly-connected-components algorithm over that
18
+ * graph, which does two things at once: it groups any models that reference
19
+ * each other in a cycle into a single component, and it produces those
20
+ * components in an order where parents come before children. Each model then
21
+ * gets a numeric priority from that order, where a lower number means "insert
22
+ * earlier". Top-level models with no parent — an organization or a theme, say —
23
+ * come first, and the deepest descendants come last.
24
+ *
25
+ * Models in the same cycle share a priority, so within a cycle the order rows
26
+ * were queued in breaks the tie. To break a cycle deterministically instead,
27
+ * mark one side of it with `belongsTo(target, fk, { defer: true })`. A deferred
28
+ * edge is left out of the graph, which turns the cycle into a chain and gives
29
+ * the deferred child a strictly higher priority than its parent. Pair it with a
30
+ * Postgres `DEFERRABLE INITIALLY DEFERRED` constraint if you also want the
31
+ * database to relax its check. See {@link BelongsToOptions.defer}.
32
+ *
33
+ * The returned map is keyed by each model's wire type name
34
+ * ({@link ModelDef.typename}, falling back to the schema key), because that is
35
+ * the name the engine looks up at commit time. Keying by the schema key would
36
+ * miss that lookup, and every model would fall back to the default priority.
37
+ *
38
+ * The result does not depend on which model the walk starts from, and the
39
+ * algorithm runs in time linear in the number of models plus relations.
40
+ * Reference: Tarjan, R. (1972), "Depth-first search and linear graph
41
+ * algorithms."
42
+ */
43
+ export function computeFKDepthPriority(schema) {
44
+ // schemaKey → typename (wire name used at transaction time)
45
+ const keyToTypename = new Map();
46
+ for (const [key, def] of Object.entries(schema.models)) {
47
+ keyToTypename.set(key, def.typename ?? key);
48
+ }
49
+ // Adjacency: schemaKey → parent schema keys pulled from `belongsTo`.
50
+ // Parents not in the schema (e.g. external types) are dropped so the
51
+ // graph stays closed. Edges marked `{ defer: true }` are also
52
+ // dropped — the schema author has declared this side of a cycle to
53
+ // be the "soft" one (insert with null FK, patch later), so the
54
+ // dependency-graph walker treats it as if the edge weren't there.
55
+ // That breaks the cycle deterministically and lets the other side
56
+ // become a strict topological predecessor.
57
+ const parentsOf = new Map();
58
+ for (const [key, def] of Object.entries(schema.models)) {
59
+ const out = [];
60
+ for (const rel of Object.values(def.relations)) {
61
+ if (rel.type !== 'belongsTo')
62
+ continue;
63
+ if (!keyToTypename.has(rel.target))
64
+ continue;
65
+ if (rel.options?.defer === true)
66
+ continue;
67
+ out.push(rel.target);
68
+ }
69
+ parentsOf.set(key, out);
70
+ }
71
+ // Tarjan SCC bookkeeping
72
+ const dfsIndex = new Map();
73
+ const lowlink = new Map();
74
+ const onStack = new Set();
75
+ const stack = [];
76
+ const sccs = [];
77
+ let counter = 0;
78
+ function strongconnect(v) {
79
+ dfsIndex.set(v, counter);
80
+ lowlink.set(v, counter);
81
+ counter++;
82
+ stack.push(v);
83
+ onStack.add(v);
84
+ for (const w of parentsOf.get(v) ?? []) {
85
+ if (!dfsIndex.has(w)) {
86
+ strongconnect(w);
87
+ lowlink.set(v, Math.min(lowlink.get(v), lowlink.get(w)));
88
+ }
89
+ else if (onStack.has(w)) {
90
+ // Back-edge into the active DFS path — w is in the same SCC as v.
91
+ lowlink.set(v, Math.min(lowlink.get(v), dfsIndex.get(w)));
92
+ }
93
+ }
94
+ // v is the root of an SCC: pop everything down to v inclusive.
95
+ if (lowlink.get(v) === dfsIndex.get(v)) {
96
+ const component = [];
97
+ let w;
98
+ do {
99
+ w = stack.pop();
100
+ onStack.delete(w);
101
+ component.push(w);
102
+ } while (w !== v);
103
+ sccs.push(component);
104
+ }
105
+ }
106
+ for (const key of keyToTypename.keys()) {
107
+ if (!dfsIndex.has(key))
108
+ strongconnect(key);
109
+ }
110
+ // Tarjan emits SCCs in reverse topological order of the condensation.
111
+ // In our edge convention (child→parent), reverse-topo of the
112
+ // condensation means root-SCCs (no outgoing edges = no parents)
113
+ // first, leaf-SCCs (deepest descendants) last. We could just use
114
+ // emit-order as the priority — but that gives independent sibling
115
+ // SCCs different priorities, which is semantically wrong: siblings
116
+ // don't depend on each other and shouldn't be ordered relative to
117
+ // each other.
118
+ //
119
+ // Instead, do one more pass to compute *longest-path depth* on the
120
+ // condensation DAG: depth(SCC) = max(depth(parent SCC)) + 1, or 0
121
+ // for SCCs with no in-schema parents. SCCs at the same depth get
122
+ // the same priority — siblings stay tied, insertion order in the
123
+ // queue breaks the tie. Priority = (depth + 1) * 10.
124
+ //
125
+ // We can compute this in a single pass over the SCCs because
126
+ // Tarjan's emit-order *is* a valid topological order of the
127
+ // condensation: when we process sccs[i], every parent SCC has
128
+ // already been assigned a depth.
129
+ const nodeToSccIdx = new Map();
130
+ sccs.forEach((scc, i) => {
131
+ for (const node of scc)
132
+ nodeToSccIdx.set(node, i);
133
+ });
134
+ const sccDepth = new Map();
135
+ sccs.forEach((scc, i) => {
136
+ let maxParentDepth = -1;
137
+ for (const node of scc) {
138
+ for (const parent of parentsOf.get(node) ?? []) {
139
+ const parentSccIdx = nodeToSccIdx.get(parent);
140
+ if (parentSccIdx === undefined)
141
+ continue;
142
+ if (parentSccIdx === i)
143
+ continue; // intra-SCC edge — not a dep
144
+ const d = sccDepth.get(parentSccIdx);
145
+ if (d !== undefined && d > maxParentDepth)
146
+ maxParentDepth = d;
147
+ }
148
+ }
149
+ sccDepth.set(i, maxParentDepth + 1);
150
+ });
151
+ const out = new Map();
152
+ sccs.forEach((scc, i) => {
153
+ const priority = (sccDepth.get(i) + 1) * 10;
154
+ for (const key of scc) {
155
+ out.set(keyToTypename.get(key), priority);
156
+ }
157
+ });
158
+ return out;
159
+ }
160
+ export function deriveConfigFromSchema(schema) {
161
+ // Field-level serialization for commits happens in the transaction queue,
162
+ // which reads each model's declared fields from the model registry at commit
163
+ // time. There is no per-field metadata to configure here, so these maps stay
164
+ // empty.
165
+ return {
166
+ modelCreatePriority: computeFKDepthPriority(schema),
167
+ defaultCreatePriority: 40,
168
+ defaultNonCreatePriority: 50,
169
+ essentialFields: {},
170
+ classNameFallbackMap: {},
171
+ // Hash this schema once, so startup can detect when it has drifted from the
172
+ // schema the server currently has active. The server and the `ablo push`
173
+ // command compute this same hash.
174
+ expectedSchemaHash: schemaHash(schema),
175
+ };
176
+ }
@@ -1,25 +1,29 @@
1
1
  import type { SchemaRecord } from '../schema/schema.js';
2
- import type { AbloSession, CreateSessionParams } from './Ablo.js';
3
- /** The resolved control-plane context a mint needs. `fetch` is optional — the
4
- * auth helpers fall back to the runtime global when omitted. */
2
+ import type { AbloSession, CreateSessionParams } from './resourceTypes.js';
3
+ /**
4
+ * The resolved control-plane details a mint needs: a secret key, a base URL,
5
+ * and an optional `fetch`. When `fetch` is omitted, the auth helpers fall back
6
+ * to the runtime's global `fetch`.
7
+ */
5
8
  export interface MintSessionContext {
6
9
  readonly apiKey: string;
7
10
  readonly baseUrl: string;
8
11
  readonly fetch?: typeof fetch;
9
12
  /**
10
- * Schema-key wire typename map, supplied ONLY by the schema client
11
- * (`Ablo`). A capability is scoped by the lowercased TYPENAME the Hub
12
- * checks, but `can` is keyed by schema key — so `can: { documents: ['update'] }`
13
- * on a model whose `typename` is overridden to `Document` must mint
14
- * `document.update`, not `documents.update` (else the Hub denies it with
15
- * `capability_scope_denied`). The schemaless `ApiClient` omits this map:
16
- * there the `can` key already IS the wire token, so no translation applies.
13
+ * Maps each schema key to its wire type name. Only the schema-aware client
14
+ * supplies this. A capability is scoped by the lowercased type name the
15
+ * server checks, but `can` is keyed by schema key — so
16
+ * `can: { documents: ['update'] }` on a model whose type name is overridden
17
+ * to `Document` must mint `document.update`, not `documents.update`, or the
18
+ * server denies the write with `capability_scope_denied`. The schemaless
19
+ * client omits this map, because there the `can` key is already the wire
20
+ * token and needs no translation.
17
21
  */
18
22
  readonly modelTypenames?: Readonly<Record<string, string>>;
19
23
  }
20
24
  /**
21
- * Mint a session token from an already-resolved `sk_` credential + base URL.
22
- * Discriminates the `{ user }` / `{ agent }` union onto the server's two mint
23
- * doors and reshapes each flat response into the `AbloSession` resource.
25
+ * Mints a session token from an already-resolved secret key and base URL.
26
+ * Routes the `{ user }` or `{ agent }` request to the matching mint endpoint
27
+ * and reshapes the response into an {@link AbloSession}.
24
28
  */
25
29
  export declare function mintSession<S extends SchemaRecord>(params: CreateSessionParams<S>, ctx: MintSessionContext): Promise<AbloSession>;