@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
@@ -1,26 +1,32 @@
1
1
  /**
2
- * Data Source adapter conformance suite the shared "is this adapter correct?"
3
- * test set, in the Auth.js `@auth/adapter-test` mould. Every ORM adapter
4
- * (Prisma/Drizzle/Kysely) and any hand-written handler runs THIS to prove,
5
- * before production, the guarantees the adapter interface promises. A new adapter is "done"
6
- * when it passes not when it compiles.
2
+ * The conformance suite for data-source adapters: a shared set of tests that checks
3
+ * whether an adapter is correct. Every adapter in this package (Prisma, Drizzle,
4
+ * Kysely) and any adapter you write yourself runs this suite to confirm it upholds
5
+ * the guarantees {@link DataSourceAdapter} promises. An adapter is complete when it
6
+ * passes, not merely when it compiles.
7
7
  *
8
- * Runner-agnostic: checks are plain async functions that throw (node:assert) on
9
- * failure. `runDataSourceTests` registers them with whatever `it`/`test` you
10
- * pass, so it works under vitest, jest, or node:test:
8
+ * The suite is runner-agnostic: each check is a plain async function that throws,
9
+ * via `node:assert`, on failure. {@link runDataSourceTests} registers the checks
10
+ * with whichever `it` or `test` function you pass, so it runs under vitest, jest,
11
+ * or `node:test`:
11
12
  *
12
13
  * import { it } from 'vitest';
13
14
  * runDataSourceTests(memoryDataSource, it);
14
15
  *
15
- * Scope: this covers the ADAPTER contract (commit idempotency, read-after-write,
16
- * the transactional outbox + cursor). Signature/scope rejection is a HANDLER
17
- * concern (the adapter never sees a signature) and is tested separately.
16
+ * The checks cover the adapter contract: commit idempotency, read-after-write, and
17
+ * the transactional outbox with its cursor. They do not cover request-signature or
18
+ * scope rejection, which the HTTP handler enforces before the adapter is ever
19
+ * called and which is tested separately.
18
20
  */
19
21
  import assert from 'node:assert/strict';
20
22
  const change = (clientTxId, ops) => ({
21
23
  clientTxId,
22
24
  operations: ops,
23
25
  });
26
+ /**
27
+ * Builds the list of conformance checks for an adapter. Call this to run the checks
28
+ * yourself, or use {@link runDataSourceTests} to register them with a test runner.
29
+ */
24
30
  export function dataSourceConformanceChecks(make) {
25
31
  return [
26
32
  {
@@ -29,8 +35,10 @@ export function dataSourceConformanceChecks(make) {
29
35
  const adapter = await make();
30
36
  const result = await adapter.commit(change('tx_create', [{ type: 'CREATE', model: 'task', id: 't1', input: { title: 'A' } }]));
31
37
  assert.equal(result.rows.length, 1, 'one row returned');
32
- assert.equal(result.rows[0].id, 't1');
33
- assert.equal(result.rows[0].title, 'A');
38
+ const created = result.rows[0];
39
+ assert.ok(created, 'one row returned');
40
+ assert.equal(created.id, 't1');
41
+ assert.equal(created.title, 'A');
34
42
  },
35
43
  },
36
44
  {
@@ -40,7 +48,7 @@ export function dataSourceConformanceChecks(make) {
40
48
  await adapter.commit(change('tx1', [{ type: 'CREATE', model: 'task', id: 't1', input: { title: 'A' } }]));
41
49
  const found = await adapter.read({ kind: 'load', model: 'task', id: 't1' });
42
50
  assert.equal(found.length, 1);
43
- assert.equal(found[0].title, 'A');
51
+ assert.equal(found[0]?.title, 'A');
44
52
  const missing = await adapter.read({ kind: 'load', model: 'task', id: 'nope' });
45
53
  assert.equal(missing.length, 0, 'unknown id reads empty');
46
54
  },
@@ -54,7 +62,7 @@ export function dataSourceConformanceChecks(make) {
54
62
  { type: 'CREATE', model: 'task', id: 't2', input: { title: 'B' } },
55
63
  ]));
56
64
  const rows = await adapter.read({ kind: 'list', model: 'task' });
57
- const ids = rows.map((r) => r.id).sort();
65
+ const ids = rows.map((r) => (r).id).sort();
58
66
  assert.deepEqual(ids, ['t1', 't2']);
59
67
  },
60
68
  },
@@ -83,9 +91,9 @@ export function dataSourceConformanceChecks(make) {
83
91
  assert.ok(page.events.length >= 1, 'at least one event');
84
92
  const evt = page.events.find((e) => e.entityId === 't1');
85
93
  assert.ok(evt, 'event for the committed row');
86
- assert.equal(evt?.model, 'task');
87
- assert.equal(evt?.type, 'CREATE');
88
- assert.equal(evt?.clientTxId, 'tx_evt');
94
+ assert.equal(evt.model, 'task');
95
+ assert.equal(evt.type, 'CREATE');
96
+ assert.equal(evt.clientTxId, 'tx_evt');
89
97
  },
90
98
  },
91
99
  {
@@ -115,7 +123,7 @@ export function dataSourceConformanceChecks(make) {
115
123
  await adapter.commit(change('tx_c1', [{ type: 'CREATE', model: 'task', id: 't1', input: { title: 'A' } }]));
116
124
  await adapter.commit(change('tx_u1', [{ type: 'UPDATE', model: 'task', id: 't1', input: { title: 'B' } }]));
117
125
  const found = await adapter.read({ kind: 'load', model: 'task', id: 't1' });
118
- assert.equal(found[0].title, 'B', 'update applied');
126
+ assert.equal(found[0]?.title, 'B', 'update applied');
119
127
  },
120
128
  },
121
129
  ];
@@ -1,15 +1,13 @@
1
1
  /**
2
- * Customer-side Data Source reverse-channel connector.
2
+ * Opens the connector's side of the Data Source reverse channel. You run this
3
+ * process next to your database; it dials an outbound WebSocket to Ablo and serves
4
+ * the load, list, and commit requests over that socket, so a handler with no
5
+ * public URL never needs to receive inbound webhooks. It is the counterpart to
6
+ * `createPushQueue`, which gives the outbound events feed the same treatment, and
7
+ * it speaks the frames defined in `connectorProtocol.ts`.
3
8
  *
4
- * The dial-out half of the reverse channel (see `connector-protocol.ts`). The
5
- * customer runs this next to their database; it opens an OUTBOUND WebSocket to
6
- * Ablo Cloud and serves the `commit`/`load`/`list` leg over that socket instead
7
- * of receiving inbound webhooks. This is the symmetric primitive to
8
- * `createPushQueue` (which already gives the `events` leg an outbound transport)
9
- * and mirrors the Stripe CLI's `stripe listen`.
10
- *
11
- * The connector does NOT reimplement any handler logic. It wraps the SAME
12
- * `(request: Request) => Promise<Response>` the customer's deployed route uses:
9
+ * The connector reimplements none of the handler logic. It wraps the same
10
+ * `(request: Request) => Promise<Response>` your deployed route already uses:
13
11
  *
14
12
  * import { dataSource, createSourceConnector } from '@abloatai/ablo';
15
13
  * import { sourceOptions } from './ablo.source'; // shared with route.ts
@@ -20,23 +18,24 @@
20
18
  * });
21
19
  * await connector.run(controller.signal);
22
20
  *
23
- * Each drained `request` frame is replayed into a synthesized `Request` carrying
24
- * the original Standard Webhooks signature headers, so the handler verifies it
25
- * through the unchanged `verifyAbloSourceRequest` identical to the webhook
26
- * path. The transport changes; the trust model does not.
21
+ * Each incoming `request` frame is replayed into a `Request` that carries the
22
+ * original signature headers, so the handler verifies it through the same
23
+ * `verifyAbloSourceRequest` it uses on the webhook path. The transport changes;
24
+ * the trust model does not.
27
25
  */
28
26
  /**
29
- * Reconnect backoff, in ms, indexed by consecutive failed connect attempts.
30
- * Unlike the (multi-day) Standard Webhooks delivery schedule, a long-lived
31
- * control socket should re-establish quickly and cap at a steady interval, so
32
- * this is a short capped curve. The last entry repeats for further attempts. A
33
- * clean `ready` resets the counter to 0.
27
+ * The reconnect backoff, in milliseconds, indexed by the number of consecutive
28
+ * failed connect attempts. A long-lived control socket should recover quickly and
29
+ * then settle at a steady interval, so this is a short curve that caps rather than
30
+ * growing without bound. The final entry repeats for any further attempts, and a
31
+ * connection that reaches `ready` resets the count to zero.
34
32
  */
35
33
  export declare const DEFAULT_RECONNECT_SCHEDULE: readonly number[];
36
34
  /**
37
- * Minimal structural WebSocket surface the browser/`globalThis.WebSocket` API,
38
- * which Node 24+ implements natively. The `ws` package's default export also
39
- * satisfies this (it exposes `addEventListener`). Injectable for tests.
35
+ * The minimal WebSocket surface the connector needs, matching the standard
36
+ * `globalThis.WebSocket` API that browsers and current Node versions provide. The
37
+ * `ws` package's default export also satisfies it. Supply your own implementation
38
+ * to substitute a fake in tests.
40
39
  */
41
40
  export interface ConnectorWebSocket {
42
41
  send(data: string): void;
@@ -57,18 +56,18 @@ export type ConnectorWebSocketFactory = (url: string, protocols: readonly string
57
56
  export type ConnectorStatus = 'connecting' | 'ready' | 'disconnected';
58
57
  export interface SourceConnectorOptions {
59
58
  /**
60
- * Ablo project API key. Defaults gate to `sk_test_*` (local-dev / sandbox);
61
- * an `sk_live_*` key is only accepted when the source has opted into
62
- * reverse-channel for production server-side.
59
+ * Your Ablo project API key. A test key (`sk_test_*`) works by default for local
60
+ * development and sandboxes; a live key (`sk_live_*`) is accepted only once the
61
+ * source has opted the reverse channel in for production use.
63
62
  */
64
63
  readonly apiKey: string;
65
64
  /**
66
- * The unchanged Data Source handler `dataSource(options)` /
67
- * `abloSource(options)`. The connector feeds it synthesized `Request`s and
68
- * relays the `Response`s back; it never inspects or alters them.
65
+ * The Data Source handler to serve, as returned by `dataSource(options)` or
66
+ * `abloSource(options)`. The connector feeds it each request and relays the
67
+ * response back untouched; it never inspects or alters either one.
69
68
  */
70
69
  readonly handler: (request: Request) => Promise<Response>;
71
- /** Ablo Cloud base URL. Default `https://api.abloatai.com`. */
70
+ /** The Ablo base URL to dial. Defaults to `https://api.abloatai.com`. */
72
71
  readonly baseURL?: string;
73
72
  /** Inject a WebSocket implementation. Default `globalThis.WebSocket`. */
74
73
  readonly webSocket?: ConnectorWebSocketFactory;
@@ -87,9 +86,9 @@ export interface SourceConnectorOptions {
87
86
  }
88
87
  export interface SourceConnector {
89
88
  /**
90
- * Run the connect serve reconnect loop until `signal` aborts. Resolves
91
- * when aborted. Rejects only on a fatal, non-retryable condition (e.g. no
92
- * WebSocket implementation available).
89
+ * Runs the connect, serve, and reconnect loop until `signal` aborts, then
90
+ * resolves. It rejects only on a fatal condition that cannot be retried, such as
91
+ * no WebSocket implementation being available.
93
92
  */
94
93
  run(signal: AbortSignal): Promise<void>;
95
94
  }
@@ -1,15 +1,13 @@
1
1
  /**
2
- * Customer-side Data Source reverse-channel connector.
2
+ * Opens the connector's side of the Data Source reverse channel. You run this
3
+ * process next to your database; it dials an outbound WebSocket to Ablo and serves
4
+ * the load, list, and commit requests over that socket, so a handler with no
5
+ * public URL never needs to receive inbound webhooks. It is the counterpart to
6
+ * `createPushQueue`, which gives the outbound events feed the same treatment, and
7
+ * it speaks the frames defined in `connectorProtocol.ts`.
3
8
  *
4
- * The dial-out half of the reverse channel (see `connector-protocol.ts`). The
5
- * customer runs this next to their database; it opens an OUTBOUND WebSocket to
6
- * Ablo Cloud and serves the `commit`/`load`/`list` leg over that socket instead
7
- * of receiving inbound webhooks. This is the symmetric primitive to
8
- * `createPushQueue` (which already gives the `events` leg an outbound transport)
9
- * and mirrors the Stripe CLI's `stripe listen`.
10
- *
11
- * The connector does NOT reimplement any handler logic. It wraps the SAME
12
- * `(request: Request) => Promise<Response>` the customer's deployed route uses:
9
+ * The connector reimplements none of the handler logic. It wraps the same
10
+ * `(request: Request) => Promise<Response>` your deployed route already uses:
13
11
  *
14
12
  * import { dataSource, createSourceConnector } from '@abloatai/ablo';
15
13
  * import { sourceOptions } from './ablo.source'; // shared with route.ts
@@ -20,20 +18,24 @@
20
18
  * });
21
19
  * await connector.run(controller.signal);
22
20
  *
23
- * Each drained `request` frame is replayed into a synthesized `Request` carrying
24
- * the original Standard Webhooks signature headers, so the handler verifies it
25
- * through the unchanged `verifyAbloSourceRequest` identical to the webhook
26
- * path. The transport changes; the trust model does not.
21
+ * Each incoming `request` frame is replayed into a `Request` that carries the
22
+ * original signature headers, so the handler verifies it through the same
23
+ * `verifyAbloSourceRequest` it uses on the webhook path. The transport changes;
24
+ * the trust model does not.
25
+ */
26
+ import { SOURCE_CONNECTOR_PROTOCOL_VERSION, SOURCE_CONNECTOR_WS_PATH, sourceConnectorSubprotocols, encodeFrame, decodeFrame, ConnectorProtocolError, } from './connectorProtocol.js';
27
+ import { ABLO_HOSTED_HTTP_BASE_URL } from '../client/hostedEndpoints.js';
28
+ /**
29
+ * The default Ablo base URL the connector dials, to which it appends
30
+ * `SOURCE_CONNECTOR_WS_PATH`.
27
31
  */
28
- import { SOURCE_CONNECTOR_PROTOCOL_VERSION, SOURCE_CONNECTOR_WS_PATH, sourceConnectorSubprotocols, encodeFrame, decodeFrame, ConnectorProtocolError, } from './connector-protocol.js';
29
- /** Default Ablo Cloud base. The connector appends `SOURCE_CONNECTOR_WS_PATH`. */
30
- const DEFAULT_BASE_URL = 'https://api.abloatai.com';
32
+ const DEFAULT_BASE_URL = ABLO_HOSTED_HTTP_BASE_URL;
31
33
  /**
32
- * Reconnect backoff, in ms, indexed by consecutive failed connect attempts.
33
- * Unlike the (multi-day) Standard Webhooks delivery schedule, a long-lived
34
- * control socket should re-establish quickly and cap at a steady interval, so
35
- * this is a short capped curve. The last entry repeats for further attempts. A
36
- * clean `ready` resets the counter to 0.
34
+ * The reconnect backoff, in milliseconds, indexed by the number of consecutive
35
+ * failed connect attempts. A long-lived control socket should recover quickly and
36
+ * then settle at a steady interval, so this is a short curve that caps rather than
37
+ * growing without bound. The final entry repeats for any further attempts, and a
38
+ * connection that reaches `ready` resets the count to zero.
37
39
  */
38
40
  export const DEFAULT_RECONNECT_SCHEDULE = [
39
41
  0, // immediate first reconnect
@@ -77,10 +79,10 @@ export function createSourceConnector(options) {
77
79
  };
78
80
  }
79
81
  /**
80
- * One connection lifecycle: open register serve drained requests until the
81
- * socket closes or `signal` aborts. Resolves to whether the connection reached
82
- * the `ready` state (used to reset reconnect backoff). Never rejects — transport
83
- * failures are normal and drive a reconnect.
82
+ * Runs one connection: open the socket, register, then serve requests until the
83
+ * socket closes or `signal` aborts. Resolves to whether the connection reached the
84
+ * `ready` state, which the caller uses to reset the reconnect backoff. It never
85
+ * rejects, because a dropped transport is expected and simply drives a reconnect.
84
86
  */
85
87
  function connectOnce(params) {
86
88
  return new Promise((resolve) => {
@@ -197,8 +199,8 @@ function connectOnce(params) {
197
199
  }
198
200
  catch (err) {
199
201
  params.onError?.(err);
200
- // Surface as a 500 so the server-side SourceClient treats it as a
201
- // retryable failure, exactly like a webhook endpoint throwing.
202
+ // Surface this as a 500 so Ablo treats it as a retryable failure, exactly
203
+ // as it would a webhook endpoint that threw.
202
204
  return {
203
205
  type: 'response',
204
206
  id: frame.id,
@@ -0,0 +1,160 @@
1
+ /**
2
+ * The wire protocol for the Data Source reverse channel — the frames that travel
3
+ * over the WebSocket a connector opens to Ablo.
4
+ *
5
+ * The load, list, and commit leg of a Data Source normally arrives as an inbound
6
+ * webhook that Ablo posts to your HTTPS endpoint. That needs a public URL, so it
7
+ * cannot reach a handler running on localhost or inside a private network with no
8
+ * inbound path. The reverse channel flips the direction: the connector dials out
9
+ * to Ablo over a WebSocket and serves those same requests back over the open
10
+ * socket. This module defines the frames exchanged on that socket.
11
+ *
12
+ * The trust model does not change. A `request` frame carries the same signature
13
+ * headers (`webhook-id`, `webhook-timestamp`, `webhook-signature`) and the same
14
+ * raw body Ablo would have posted, so the connector verifies it through
15
+ * `verifyAbloSourceRequest` exactly as it would a webhook. Only the transport
16
+ * differs.
17
+ *
18
+ * Frames are validated with Zod as they arrive, the same discipline `contract.ts`
19
+ * applies to change sets: a malformed frame is rejected at the boundary, and both
20
+ * sides infer every wire type from one schema so they cannot silently drift.
21
+ */
22
+ import { z } from 'zod';
23
+ /**
24
+ * The wire-protocol version. It increases on any breaking change to a frame's
25
+ * shape, so a connector and server on mismatched versions fail fast during
26
+ * `register` rather than misparsing a frame later in the stream.
27
+ */
28
+ export declare const SOURCE_CONNECTOR_PROTOCOL_VERSION = 1;
29
+ /** The WebSocket path the connector dials, appended to its configured base URL. */
30
+ export declare const SOURCE_CONNECTOR_WS_PATH = "/v1/source/listen";
31
+ /**
32
+ * The WebSocket subprotocol that identifies a reverse-channel source connector,
33
+ * as opposed to the SDK's sync client, which uses `ablo.sync.v1`. During the
34
+ * handshake the server echoes back only this value and never the subprotocol that
35
+ * carries the credential, keeping the API key out of proxy and load-balancer logs.
36
+ */
37
+ export declare const WS_SOURCE_SUBPROTOCOL = "ablo.source.v1";
38
+ /**
39
+ * Builds the `Sec-WebSocket-Protocol` list a connector offers during the
40
+ * handshake: the source subprotocol followed by the bearer credential, encoded as
41
+ * `ablo.bearer.<apiKey>`. A WebSocket handshake cannot carry an `Authorization`
42
+ * header, so the API key rides as a subprotocol instead — the same mechanism the
43
+ * SDK's sync client uses, which the server reads back with `extractBearer`.
44
+ */
45
+ export declare function sourceConnectorSubprotocols(apiKey: string): string[];
46
+ /**
47
+ * The first frame the connector sends, right after the socket opens. The server
48
+ * has already authenticated the connection and resolved which source it serves
49
+ * from the API key in the handshake, so this frame only negotiates the protocol
50
+ * version and carries advisory metadata.
51
+ */
52
+ export declare const registerFrameSchema: z.ZodObject<{
53
+ type: z.ZodLiteral<"register">;
54
+ protocolVersion: z.ZodNumber;
55
+ client: z.ZodOptional<z.ZodString>;
56
+ }, z.core.$strip>;
57
+ export type RegisterFrame = z.infer<typeof registerFrameSchema>;
58
+ /**
59
+ * The server's acknowledgement of a successful `register`. It echoes the resolved
60
+ * source identity so the connector can confirm and log which source it is serving.
61
+ */
62
+ export declare const readyFrameSchema: z.ZodObject<{
63
+ type: z.ZodLiteral<"ready">;
64
+ protocolVersion: z.ZodNumber;
65
+ sourceId: z.ZodOptional<z.ZodString>;
66
+ organizationId: z.ZodOptional<z.ZodString>;
67
+ environment: z.ZodOptional<z.ZodEnum<{
68
+ production: "production";
69
+ sandbox: "sandbox";
70
+ }>>;
71
+ }, z.core.$strip>;
72
+ export type ReadyFrame = z.infer<typeof readyFrameSchema>;
73
+ /**
74
+ * A single load, list, or commit request the server forwards to the connector.
75
+ * Its `headers` and `body` are byte-for-byte what the inbound webhook path would
76
+ * have sent, so the connector can replay them into a `Request` and let the same
77
+ * handler verify the signature exactly as it would for a webhook.
78
+ */
79
+ export declare const requestFrameSchema: z.ZodObject<{
80
+ type: z.ZodLiteral<"request">;
81
+ id: z.ZodString;
82
+ method: z.ZodLiteral<"POST">;
83
+ url: z.ZodString;
84
+ headers: z.ZodRecord<z.ZodString, z.ZodString>;
85
+ body: z.ZodString;
86
+ }, z.core.$strip>;
87
+ export type RequestFrame = z.infer<typeof requestFrameSchema>;
88
+ /**
89
+ * The handler's response to one `request` frame, sent back by the connector. The
90
+ * server matches it to the pending request by `id` and treats its `status` and
91
+ * `body` as though an HTTP response had returned.
92
+ */
93
+ export declare const responseFrameSchema: z.ZodObject<{
94
+ type: z.ZodLiteral<"response">;
95
+ id: z.ZodString;
96
+ status: z.ZodNumber;
97
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
98
+ body: z.ZodString;
99
+ }, z.core.$strip>;
100
+ export type ResponseFrame = z.infer<typeof responseFrameSchema>;
101
+ /**
102
+ * An error either side can send for a failure that is not a normal request
103
+ * result, such as a rejected credential, an unsupported protocol version, or a
104
+ * malformed frame. When `id` is set the error belongs to that pending request and
105
+ * fails it; without an `id` it is a connection-level error.
106
+ */
107
+ export declare const errorFrameSchema: z.ZodObject<{
108
+ type: z.ZodLiteral<"error">;
109
+ id: z.ZodOptional<z.ZodString>;
110
+ code: z.ZodString;
111
+ message: z.ZodString;
112
+ }, z.core.$strip>;
113
+ export type ErrorFrame = z.infer<typeof errorFrameSchema>;
114
+ export declare const connectorFrameSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
115
+ type: z.ZodLiteral<"register">;
116
+ protocolVersion: z.ZodNumber;
117
+ client: z.ZodOptional<z.ZodString>;
118
+ }, z.core.$strip>, z.ZodObject<{
119
+ type: z.ZodLiteral<"ready">;
120
+ protocolVersion: z.ZodNumber;
121
+ sourceId: z.ZodOptional<z.ZodString>;
122
+ organizationId: z.ZodOptional<z.ZodString>;
123
+ environment: z.ZodOptional<z.ZodEnum<{
124
+ production: "production";
125
+ sandbox: "sandbox";
126
+ }>>;
127
+ }, z.core.$strip>, z.ZodObject<{
128
+ type: z.ZodLiteral<"request">;
129
+ id: z.ZodString;
130
+ method: z.ZodLiteral<"POST">;
131
+ url: z.ZodString;
132
+ headers: z.ZodRecord<z.ZodString, z.ZodString>;
133
+ body: z.ZodString;
134
+ }, z.core.$strip>, z.ZodObject<{
135
+ type: z.ZodLiteral<"response">;
136
+ id: z.ZodString;
137
+ status: z.ZodNumber;
138
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
139
+ body: z.ZodString;
140
+ }, z.core.$strip>, z.ZodObject<{
141
+ type: z.ZodLiteral<"error">;
142
+ id: z.ZodOptional<z.ZodString>;
143
+ code: z.ZodString;
144
+ message: z.ZodString;
145
+ }, z.core.$strip>], "type">;
146
+ export type ConnectorFrame = z.infer<typeof connectorFrameSchema>;
147
+ /** Thrown when an incoming frame fails to parse or validate. */
148
+ export declare class ConnectorProtocolError extends Error {
149
+ readonly code = "source_connector_protocol_error";
150
+ constructor(message: string);
151
+ }
152
+ /** Serialize a frame for transmission. */
153
+ export declare function encodeFrame(frame: ConnectorFrame): string;
154
+ /**
155
+ * Parses and validates one incoming frame. It accepts either the string or the
156
+ * binary payloads a WebSocket `message` event can deliver, and throws
157
+ * {@link ConnectorProtocolError} on any malformed or unrecognized frame so the
158
+ * caller can reject the connection instead of acting on bad data.
159
+ */
160
+ export declare function decodeFrame(raw: string | ArrayBuffer | Uint8Array): ConnectorFrame;
@@ -0,0 +1,162 @@
1
+ /**
2
+ * The wire protocol for the Data Source reverse channel — the frames that travel
3
+ * over the WebSocket a connector opens to Ablo.
4
+ *
5
+ * The load, list, and commit leg of a Data Source normally arrives as an inbound
6
+ * webhook that Ablo posts to your HTTPS endpoint. That needs a public URL, so it
7
+ * cannot reach a handler running on localhost or inside a private network with no
8
+ * inbound path. The reverse channel flips the direction: the connector dials out
9
+ * to Ablo over a WebSocket and serves those same requests back over the open
10
+ * socket. This module defines the frames exchanged on that socket.
11
+ *
12
+ * The trust model does not change. A `request` frame carries the same signature
13
+ * headers (`webhook-id`, `webhook-timestamp`, `webhook-signature`) and the same
14
+ * raw body Ablo would have posted, so the connector verifies it through
15
+ * `verifyAbloSourceRequest` exactly as it would a webhook. Only the transport
16
+ * differs.
17
+ *
18
+ * Frames are validated with Zod as they arrive, the same discipline `contract.ts`
19
+ * applies to change sets: a malformed frame is rejected at the boundary, and both
20
+ * sides infer every wire type from one schema so they cannot silently drift.
21
+ */
22
+ import { z } from 'zod';
23
+ import { WS_BEARER_SUBPROTOCOL_PREFIX } from '../auth/credentialSource.js';
24
+ /**
25
+ * The wire-protocol version. It increases on any breaking change to a frame's
26
+ * shape, so a connector and server on mismatched versions fail fast during
27
+ * `register` rather than misparsing a frame later in the stream.
28
+ */
29
+ export const SOURCE_CONNECTOR_PROTOCOL_VERSION = 1;
30
+ /** The WebSocket path the connector dials, appended to its configured base URL. */
31
+ export const SOURCE_CONNECTOR_WS_PATH = '/v1/source/listen';
32
+ /**
33
+ * The WebSocket subprotocol that identifies a reverse-channel source connector,
34
+ * as opposed to the SDK's sync client, which uses `ablo.sync.v1`. During the
35
+ * handshake the server echoes back only this value and never the subprotocol that
36
+ * carries the credential, keeping the API key out of proxy and load-balancer logs.
37
+ */
38
+ export const WS_SOURCE_SUBPROTOCOL = 'ablo.source.v1';
39
+ /**
40
+ * Builds the `Sec-WebSocket-Protocol` list a connector offers during the
41
+ * handshake: the source subprotocol followed by the bearer credential, encoded as
42
+ * `ablo.bearer.<apiKey>`. A WebSocket handshake cannot carry an `Authorization`
43
+ * header, so the API key rides as a subprotocol instead — the same mechanism the
44
+ * SDK's sync client uses, which the server reads back with `extractBearer`.
45
+ */
46
+ export function sourceConnectorSubprotocols(apiKey) {
47
+ return [WS_SOURCE_SUBPROTOCOL, `${WS_BEARER_SUBPROTOCOL_PREFIX}${apiKey}`];
48
+ }
49
+ const headerRecord = z.record(z.string(), z.string());
50
+ /**
51
+ * The first frame the connector sends, right after the socket opens. The server
52
+ * has already authenticated the connection and resolved which source it serves
53
+ * from the API key in the handshake, so this frame only negotiates the protocol
54
+ * version and carries advisory metadata.
55
+ */
56
+ export const registerFrameSchema = z.object({
57
+ type: z.literal('register'),
58
+ protocolVersion: z.number().int(),
59
+ /**
60
+ * An optional client identifier, such as `@abloatai/ablo@0.12.0`, recorded in
61
+ * the server's logs. It is advisory only and never affects a decision.
62
+ */
63
+ client: z.string().optional(),
64
+ });
65
+ /**
66
+ * The server's acknowledgement of a successful `register`. It echoes the resolved
67
+ * source identity so the connector can confirm and log which source it is serving.
68
+ */
69
+ export const readyFrameSchema = z.object({
70
+ type: z.literal('ready'),
71
+ protocolVersion: z.number().int(),
72
+ sourceId: z.string().optional(),
73
+ organizationId: z.string().optional(),
74
+ environment: z.enum(['production', 'sandbox']).optional(),
75
+ });
76
+ /**
77
+ * A single load, list, or commit request the server forwards to the connector.
78
+ * Its `headers` and `body` are byte-for-byte what the inbound webhook path would
79
+ * have sent, so the connector can replay them into a `Request` and let the same
80
+ * handler verify the signature exactly as it would for a webhook.
81
+ */
82
+ export const requestFrameSchema = z.object({
83
+ type: z.literal('request'),
84
+ /** Correlation id; the matching `response` frame carries the same value. */
85
+ id: z.string().min(1),
86
+ method: z.literal('POST'),
87
+ /** Synthetic absolute URL used only to construct the `Request` object. */
88
+ url: z.string().min(1),
89
+ /** The signed webhook signature headers, plus `Content-Type`. */
90
+ headers: headerRecord,
91
+ /** Raw JSON request body — exactly the bytes that were signed. */
92
+ body: z.string(),
93
+ });
94
+ /**
95
+ * The handler's response to one `request` frame, sent back by the connector. The
96
+ * server matches it to the pending request by `id` and treats its `status` and
97
+ * `body` as though an HTTP response had returned.
98
+ */
99
+ export const responseFrameSchema = z.object({
100
+ type: z.literal('response'),
101
+ id: z.string().min(1),
102
+ status: z.number().int(),
103
+ headers: headerRecord.optional(),
104
+ /** Raw JSON response body. */
105
+ body: z.string(),
106
+ });
107
+ /**
108
+ * An error either side can send for a failure that is not a normal request
109
+ * result, such as a rejected credential, an unsupported protocol version, or a
110
+ * malformed frame. When `id` is set the error belongs to that pending request and
111
+ * fails it; without an `id` it is a connection-level error.
112
+ */
113
+ export const errorFrameSchema = z.object({
114
+ type: z.literal('error'),
115
+ id: z.string().min(1).optional(),
116
+ code: z.string().min(1),
117
+ message: z.string(),
118
+ });
119
+ export const connectorFrameSchema = z.discriminatedUnion('type', [
120
+ registerFrameSchema,
121
+ readyFrameSchema,
122
+ requestFrameSchema,
123
+ responseFrameSchema,
124
+ errorFrameSchema,
125
+ ]);
126
+ /** Thrown when an incoming frame fails to parse or validate. */
127
+ export class ConnectorProtocolError extends Error {
128
+ code = 'source_connector_protocol_error';
129
+ constructor(message) {
130
+ super(message);
131
+ this.name = 'ConnectorProtocolError';
132
+ }
133
+ }
134
+ /** Serialize a frame for transmission. */
135
+ export function encodeFrame(frame) {
136
+ return JSON.stringify(frame);
137
+ }
138
+ /**
139
+ * Parses and validates one incoming frame. It accepts either the string or the
140
+ * binary payloads a WebSocket `message` event can deliver, and throws
141
+ * {@link ConnectorProtocolError} on any malformed or unrecognized frame so the
142
+ * caller can reject the connection instead of acting on bad data.
143
+ */
144
+ export function decodeFrame(raw) {
145
+ const text = typeof raw === 'string' ? raw : decodeBinary(raw);
146
+ let parsed;
147
+ try {
148
+ parsed = JSON.parse(text);
149
+ }
150
+ catch {
151
+ throw new ConnectorProtocolError('Frame is not valid JSON');
152
+ }
153
+ const result = connectorFrameSchema.safeParse(parsed);
154
+ if (!result.success) {
155
+ throw new ConnectorProtocolError(`Invalid connector frame: ${result.error.message}`);
156
+ }
157
+ return result.data;
158
+ }
159
+ function decodeBinary(raw) {
160
+ const bytes = raw instanceof Uint8Array ? raw : new Uint8Array(raw);
161
+ return new TextDecoder().decode(bytes);
162
+ }