stitchkit 0.93.0 → 0.94.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 (791) hide show
  1. package/CHANGELOG.md +134 -0
  2. package/README.md +5 -2
  3. package/dist/agent-runtime/children-control.d.ts +6 -0
  4. package/dist/agent-runtime/children-control.d.ts.map +1 -0
  5. package/dist/agent-runtime/children-spawn.d.ts +6 -0
  6. package/dist/agent-runtime/children-spawn.d.ts.map +1 -0
  7. package/dist/agent-runtime/children-state.d.ts +46 -0
  8. package/dist/agent-runtime/children-state.d.ts.map +1 -0
  9. package/dist/agent-runtime/children-usage.d.ts +8 -0
  10. package/dist/agent-runtime/children-usage.d.ts.map +1 -0
  11. package/dist/agent-runtime/children.d.ts +11 -14
  12. package/dist/agent-runtime/children.d.ts.map +1 -1
  13. package/dist/agent-runtime/coding-tool-contract.d.ts +2 -1
  14. package/dist/agent-runtime/coding-tool-contract.d.ts.map +1 -1
  15. package/dist/agent-runtime/deferred-tool-types.d.ts +2 -2
  16. package/dist/agent-runtime/deferred-tool-types.d.ts.map +1 -1
  17. package/dist/agent-runtime/events.d.ts +1 -1
  18. package/dist/agent-runtime/events.d.ts.map +1 -1
  19. package/dist/agent-runtime/managed-tools.d.ts +1 -1
  20. package/dist/agent-runtime/managed-tools.d.ts.map +1 -1
  21. package/dist/agent-runtime/observability.d.ts +1 -1
  22. package/dist/agent-runtime/observability.d.ts.map +1 -1
  23. package/dist/{agent-runtime-openrouter.d.ts → agent-runtime/openrouter.d.ts} +3 -3
  24. package/dist/agent-runtime/openrouter.d.ts.map +1 -0
  25. package/dist/agent-runtime/projections.d.ts +1 -1
  26. package/dist/agent-runtime/projections.d.ts.map +1 -1
  27. package/dist/agent-runtime/run-acquisition.d.ts +17 -0
  28. package/dist/agent-runtime/run-acquisition.d.ts.map +1 -0
  29. package/dist/agent-runtime/run-execution-state.d.ts +133 -0
  30. package/dist/agent-runtime/run-execution-state.d.ts.map +1 -0
  31. package/dist/agent-runtime/run-execution.d.ts +17 -33
  32. package/dist/agent-runtime/run-execution.d.ts.map +1 -1
  33. package/dist/agent-runtime/run-failure.d.ts +18 -0
  34. package/dist/agent-runtime/run-failure.d.ts.map +1 -0
  35. package/dist/agent-runtime/run-model-attempts.d.ts +6 -0
  36. package/dist/agent-runtime/run-model-attempts.d.ts.map +1 -0
  37. package/dist/agent-runtime/run-prompt-history.d.ts +58 -0
  38. package/dist/agent-runtime/run-prompt-history.d.ts.map +1 -0
  39. package/dist/agent-runtime/run-provider-ledger.d.ts +26 -0
  40. package/dist/agent-runtime/run-provider-ledger.d.ts.map +1 -0
  41. package/dist/agent-runtime/run-stream-parts.d.ts +17 -0
  42. package/dist/agent-runtime/run-stream-parts.d.ts.map +1 -0
  43. package/dist/agent-runtime/run-terminal.d.ts +11 -0
  44. package/dist/agent-runtime/run-terminal.d.ts.map +1 -0
  45. package/dist/agent-runtime/run-turn-preparation.d.ts +22 -0
  46. package/dist/agent-runtime/run-turn-preparation.d.ts.map +1 -0
  47. package/dist/agent-runtime/runtime-admission-gate.d.ts +29 -0
  48. package/dist/agent-runtime/runtime-admission-gate.d.ts.map +1 -0
  49. package/dist/agent-runtime/runtime-control.d.ts +9 -0
  50. package/dist/agent-runtime/runtime-control.d.ts.map +1 -0
  51. package/dist/agent-runtime/runtime-recovery.d.ts +10 -0
  52. package/dist/agent-runtime/runtime-recovery.d.ts.map +1 -0
  53. package/dist/agent-runtime/runtime-state.d.ts +36 -0
  54. package/dist/agent-runtime/runtime-state.d.ts.map +1 -0
  55. package/dist/agent-runtime/runtime-submit.d.ts +5 -0
  56. package/dist/agent-runtime/runtime-submit.d.ts.map +1 -0
  57. package/dist/agent-runtime/runtime.d.ts +9 -4
  58. package/dist/agent-runtime/runtime.d.ts.map +1 -1
  59. package/dist/{agent-runtime-sqlite-bun.d.ts → agent-runtime/sqlite-bun.d.ts} +5 -4
  60. package/dist/agent-runtime/sqlite-bun.d.ts.map +1 -0
  61. package/dist/agent-runtime/sqlite-events.d.ts +5 -0
  62. package/dist/agent-runtime/sqlite-events.d.ts.map +1 -0
  63. package/dist/agent-runtime/sqlite-history.d.ts +7 -0
  64. package/dist/agent-runtime/sqlite-history.d.ts.map +1 -0
  65. package/dist/agent-runtime/sqlite-ledger.d.ts +7 -0
  66. package/dist/agent-runtime/sqlite-ledger.d.ts.map +1 -0
  67. package/dist/{agent-runtime-sqlite-node.d.ts → agent-runtime/sqlite-node.d.ts} +5 -4
  68. package/dist/agent-runtime/sqlite-node.d.ts.map +1 -0
  69. package/dist/agent-runtime/sqlite-reads.d.ts +14 -0
  70. package/dist/agent-runtime/sqlite-reads.d.ts.map +1 -0
  71. package/dist/agent-runtime/sqlite-rows.d.ts +178 -0
  72. package/dist/agent-runtime/sqlite-rows.d.ts.map +1 -0
  73. package/dist/agent-runtime/sqlite-schema.d.ts +7 -0
  74. package/dist/agent-runtime/sqlite-schema.d.ts.map +1 -0
  75. package/dist/agent-runtime/sqlite-transactions.d.ts +25 -0
  76. package/dist/agent-runtime/sqlite-transactions.d.ts.map +1 -0
  77. package/dist/agent-runtime/sqlite.d.ts +10 -6
  78. package/dist/agent-runtime/sqlite.d.ts.map +1 -1
  79. package/dist/agent-runtime/store-archive.d.ts +16 -0
  80. package/dist/agent-runtime/store-archive.d.ts.map +1 -0
  81. package/dist/{testing/agent-store-conformance.d.ts → agent-runtime/store-conformance.d.ts} +2 -2
  82. package/dist/agent-runtime/store-conformance.d.ts.map +1 -0
  83. package/dist/agent-runtime/store-create.d.ts +11 -0
  84. package/dist/agent-runtime/store-create.d.ts.map +1 -0
  85. package/dist/agent-runtime/{store-driver.d.ts → store-driver-contract.d.ts} +7 -7
  86. package/dist/agent-runtime/store-driver-contract.d.ts.map +1 -0
  87. package/dist/agent-runtime/store-events.d.ts +7 -89
  88. package/dist/agent-runtime/store-events.d.ts.map +1 -1
  89. package/dist/agent-runtime/store-memory.d.ts +4 -0
  90. package/dist/agent-runtime/store-memory.d.ts.map +1 -0
  91. package/dist/agent-runtime/store-mutate.d.ts +13 -0
  92. package/dist/agent-runtime/store-mutate.d.ts.map +1 -0
  93. package/dist/agent-runtime/store-purge.d.ts +1 -1
  94. package/dist/agent-runtime/store-purge.d.ts.map +1 -1
  95. package/dist/agent-runtime/store-reads.d.ts +29 -0
  96. package/dist/agent-runtime/store-reads.d.ts.map +1 -0
  97. package/dist/agent-runtime/store-reduce-history.d.ts +10 -0
  98. package/dist/agent-runtime/store-reduce-history.d.ts.map +1 -0
  99. package/dist/agent-runtime/store-reduce-run.d.ts +14 -0
  100. package/dist/agent-runtime/store-reduce-run.d.ts.map +1 -0
  101. package/dist/agent-runtime/store-reduce-shared.d.ts +76 -0
  102. package/dist/agent-runtime/store-reduce-shared.d.ts.map +1 -0
  103. package/dist/agent-runtime/store-reduce-terminal.d.ts +6 -0
  104. package/dist/agent-runtime/store-reduce-terminal.d.ts.map +1 -0
  105. package/dist/agent-runtime/store-reducer.d.ts +24 -0
  106. package/dist/agent-runtime/store-reducer.d.ts.map +1 -0
  107. package/dist/agent-runtime/store-snapshot.d.ts +19 -0
  108. package/dist/agent-runtime/store-snapshot.d.ts.map +1 -0
  109. package/dist/agent-runtime/store.d.ts +1 -1
  110. package/dist/agent-runtime/store.d.ts.map +1 -1
  111. package/dist/application/admission.d.ts +1 -1
  112. package/dist/application/admission.d.ts.map +1 -1
  113. package/dist/application/events.d.ts +1 -1
  114. package/dist/application/events.d.ts.map +1 -1
  115. package/dist/{server → application}/file-state-store.d.ts +1 -1
  116. package/dist/application/file-state-store.d.ts.map +1 -0
  117. package/dist/application/health.d.ts +1 -1
  118. package/dist/application/health.d.ts.map +1 -1
  119. package/dist/application/kernel-admission.d.ts +8 -0
  120. package/dist/application/kernel-admission.d.ts.map +1 -0
  121. package/dist/application/kernel-contract.d.ts +142 -0
  122. package/dist/application/kernel-contract.d.ts.map +1 -0
  123. package/dist/application/kernel-resource-context.d.ts +24 -0
  124. package/dist/application/kernel-resource-context.d.ts.map +1 -0
  125. package/dist/application/kernel-restart.d.ts +5 -0
  126. package/dist/application/kernel-restart.d.ts.map +1 -0
  127. package/dist/application/kernel-rollback.d.ts +4 -0
  128. package/dist/application/kernel-rollback.d.ts.map +1 -0
  129. package/dist/application/kernel-shutdown.d.ts +6 -0
  130. package/dist/application/kernel-shutdown.d.ts.map +1 -0
  131. package/dist/application/kernel-start.d.ts +20 -0
  132. package/dist/application/kernel-start.d.ts.map +1 -0
  133. package/dist/application/kernel-state.d.ts +116 -0
  134. package/dist/application/kernel-state.d.ts.map +1 -0
  135. package/dist/application/kernel.d.ts +9 -140
  136. package/dist/application/kernel.d.ts.map +1 -1
  137. package/dist/application/latest-sink.d.ts +1 -1
  138. package/dist/application/latest-sink.d.ts.map +1 -1
  139. package/dist/application/opentelemetry.d.ts +1 -1
  140. package/dist/application/opentelemetry.d.ts.map +1 -1
  141. package/dist/application/watch-hub.d.ts +2 -2
  142. package/dist/application/watch-hub.d.ts.map +1 -1
  143. package/dist/browser/client-multipart.d.ts +1 -1
  144. package/dist/browser/client-multipart.d.ts.map +1 -1
  145. package/dist/browser/client-url.d.ts +1 -1
  146. package/dist/browser/client-url.d.ts.map +1 -1
  147. package/dist/browser/client.d.ts +1 -1
  148. package/dist/browser/client.d.ts.map +1 -1
  149. package/dist/browser/contract-stream.d.ts +1 -1
  150. package/dist/browser/contract-stream.d.ts.map +1 -1
  151. package/dist/browser/http.d.ts +1 -1
  152. package/dist/browser/http.d.ts.map +1 -1
  153. package/dist/browser/resumable.d.ts +1 -28
  154. package/dist/browser/resumable.d.ts.map +1 -1
  155. package/dist/browser/retained.d.ts.map +1 -0
  156. package/dist/browser/socket-io.d.ts +23 -1
  157. package/dist/browser/socket-io.d.ts.map +1 -1
  158. package/dist/browser/stream.d.ts +14 -2
  159. package/dist/browser/stream.d.ts.map +1 -1
  160. package/dist/contract/define.d.ts +72 -65
  161. package/dist/contract/define.d.ts.map +1 -1
  162. package/dist/{internal/errors.d.ts → contract/normalize.d.ts} +3 -39
  163. package/dist/contract/normalize.d.ts.map +1 -0
  164. package/dist/contract/tool-view.d.ts +135 -0
  165. package/dist/contract/tool-view.d.ts.map +1 -0
  166. package/dist/declaration/declaration.d.ts.map +1 -0
  167. package/dist/{agent-runtime/durability-contract.d.ts → durability/contract.d.ts} +2 -2
  168. package/dist/durability/contract.d.ts.map +1 -0
  169. package/dist/{agent-runtime/durability.d.ts → durability/engine.d.ts} +4 -4
  170. package/dist/durability/engine.d.ts.map +1 -0
  171. package/dist/durability/events.d.ts +101 -0
  172. package/dist/durability/events.d.ts.map +1 -0
  173. package/dist/{agent-runtime/durability-json.d.ts → durability/json.d.ts} +1 -1
  174. package/dist/durability/json.d.ts.map +1 -0
  175. package/dist/{agent-runtime/durability-ledger.d.ts → durability/ledger.d.ts} +2 -2
  176. package/dist/durability/ledger.d.ts.map +1 -0
  177. package/dist/{agent-runtime/durability-scheduler.d.ts → durability/scheduler.d.ts} +2 -2
  178. package/dist/durability/scheduler.d.ts.map +1 -0
  179. package/dist/entrypoints/agent-runtime/browser.d.ts +5 -0
  180. package/dist/entrypoints/agent-runtime/browser.d.ts.map +1 -0
  181. package/dist/{agent-runtime-browser.js → entrypoints/agent-runtime/browser.js} +3 -3
  182. package/dist/{agent-runtime-coding-tools.d.ts → entrypoints/agent-runtime/coding-tools.d.ts} +2 -2
  183. package/dist/entrypoints/agent-runtime/coding-tools.d.ts.map +1 -0
  184. package/dist/entrypoints/agent-runtime/coding-tools.js +22 -0
  185. package/dist/{agent-runtime-harness.d.ts → entrypoints/agent-runtime/harness.d.ts} +2 -2
  186. package/dist/entrypoints/agent-runtime/harness.d.ts.map +1 -0
  187. package/dist/{agent-runtime-harness.js → entrypoints/agent-runtime/harness.js} +24 -25
  188. package/dist/entrypoints/agent-runtime/openrouter.d.ts +2 -0
  189. package/dist/entrypoints/agent-runtime/openrouter.d.ts.map +1 -0
  190. package/dist/{agent-runtime-openrouter.js → entrypoints/agent-runtime/openrouter.js} +3 -3
  191. package/dist/{agent-runtime-sandbox.d.ts → entrypoints/agent-runtime/sandbox.d.ts} +5 -5
  192. package/dist/entrypoints/agent-runtime/sandbox.d.ts.map +1 -0
  193. package/dist/{agent-runtime-sandbox.js → entrypoints/agent-runtime/sandbox.js} +11 -12
  194. package/dist/entrypoints/agent-runtime/sqlite/bun.d.ts +2 -0
  195. package/dist/entrypoints/agent-runtime/sqlite/bun.d.ts.map +1 -0
  196. package/dist/{agent-runtime-sqlite-bun.js → entrypoints/agent-runtime/sqlite/bun.js} +8 -6
  197. package/dist/entrypoints/agent-runtime/sqlite/node.d.ts +2 -0
  198. package/dist/entrypoints/agent-runtime/sqlite/node.d.ts.map +1 -0
  199. package/dist/{agent-runtime-sqlite-node.js → entrypoints/agent-runtime/sqlite/node.js} +8 -6
  200. package/dist/entrypoints/agent-runtime/testing.d.ts +4 -0
  201. package/dist/entrypoints/agent-runtime/testing.d.ts.map +1 -0
  202. package/dist/entrypoints/agent-runtime/testing.js +1084 -0
  203. package/dist/{agent-runtime.d.ts → entrypoints/agent-runtime.d.ts} +41 -37
  204. package/dist/entrypoints/agent-runtime.d.ts.map +1 -0
  205. package/dist/{agent-runtime.js → entrypoints/agent-runtime.js} +408 -366
  206. package/dist/{application-diagnostic-journal.d.ts → entrypoints/application/diagnostic-journal.d.ts} +2 -2
  207. package/dist/entrypoints/application/diagnostic-journal.d.ts.map +1 -0
  208. package/dist/{application-diagnostic-journal.js → entrypoints/application/diagnostic-journal.js} +3 -3
  209. package/dist/{application-grammy.d.ts → entrypoints/application/grammy.d.ts} +2 -2
  210. package/dist/entrypoints/application/grammy.d.ts.map +1 -0
  211. package/dist/{application-grammy.js → entrypoints/application/grammy.js} +2 -2
  212. package/dist/{application-opentelemetry.d.ts → entrypoints/application/opentelemetry.d.ts} +2 -2
  213. package/dist/entrypoints/application/opentelemetry.d.ts.map +1 -0
  214. package/dist/{application-opentelemetry.js → entrypoints/application/opentelemetry.js} +4 -4
  215. package/dist/{application-schemas.d.ts → entrypoints/application/schemas.d.ts} +2 -2
  216. package/dist/entrypoints/application/schemas.d.ts.map +1 -0
  217. package/dist/{application-schemas.js → entrypoints/application/schemas.js} +2 -2
  218. package/dist/{application.d.ts → entrypoints/application.d.ts} +22 -21
  219. package/dist/entrypoints/application.d.ts.map +1 -0
  220. package/dist/{application.js → entrypoints/application.js} +24 -22
  221. package/dist/entrypoints/bin/upgrade-cli.d.ts.map +1 -0
  222. package/dist/{upgrade-cli.js → entrypoints/bin/upgrade-cli.js} +3 -3
  223. package/dist/{cli.d.ts → entrypoints/cli.d.ts} +15 -15
  224. package/dist/entrypoints/cli.d.ts.map +1 -0
  225. package/dist/{cli.js → entrypoints/cli.js} +30 -32
  226. package/dist/entrypoints/contract.d.ts +9 -0
  227. package/dist/entrypoints/contract.d.ts.map +1 -0
  228. package/dist/{contract/index.js → entrypoints/contract.js} +14 -6
  229. package/dist/entrypoints/declaration.d.ts +2 -0
  230. package/dist/entrypoints/declaration.d.ts.map +1 -0
  231. package/dist/{declaration.js → entrypoints/declaration.js} +1 -1
  232. package/dist/{files.d.ts → entrypoints/files.d.ts} +2 -2
  233. package/dist/entrypoints/files.d.ts.map +1 -0
  234. package/dist/{files.js → entrypoints/files.js} +3 -3
  235. package/dist/{geo.d.ts → entrypoints/geo.d.ts} +1 -1
  236. package/dist/entrypoints/geo.d.ts.map +1 -0
  237. package/dist/{geo.js → entrypoints/geo.js} +4 -4
  238. package/dist/entrypoints/google.d.ts +2 -0
  239. package/dist/entrypoints/google.d.ts.map +1 -0
  240. package/dist/{google.js → entrypoints/google.js} +1 -1
  241. package/dist/{index.d.ts → entrypoints/index.d.ts} +14 -13
  242. package/dist/entrypoints/index.d.ts.map +1 -0
  243. package/dist/{index.js → entrypoints/index.js} +99 -33
  244. package/dist/{live.d.ts → entrypoints/live.d.ts} +4 -4
  245. package/dist/entrypoints/live.d.ts.map +1 -0
  246. package/dist/{live.js → entrypoints/live.js} +6 -4
  247. package/dist/{node.d.ts → entrypoints/node.d.ts} +11 -11
  248. package/dist/entrypoints/node.d.ts.map +1 -0
  249. package/dist/{node.js → entrypoints/node.js} +20 -16
  250. package/dist/entrypoints/oauth.d.ts +2 -0
  251. package/dist/entrypoints/oauth.d.ts.map +1 -0
  252. package/dist/{oauth.js → entrypoints/oauth.js} +3 -3
  253. package/dist/{observability/index.d.ts → entrypoints/observability.d.ts} +11 -11
  254. package/dist/entrypoints/observability.d.ts.map +1 -0
  255. package/dist/{observability/index.js → entrypoints/observability.js} +9 -11
  256. package/dist/entrypoints/primitives.d.ts +3 -0
  257. package/dist/entrypoints/primitives.d.ts.map +1 -0
  258. package/dist/{primitives.js → entrypoints/primitives.js} +1 -6
  259. package/dist/{react.d.ts → entrypoints/react.d.ts} +4 -4
  260. package/dist/entrypoints/react.d.ts.map +1 -0
  261. package/dist/{react.js → entrypoints/react.js} +3 -3
  262. package/dist/{release.d.ts → entrypoints/release.d.ts} +4 -4
  263. package/dist/entrypoints/release.d.ts.map +1 -0
  264. package/dist/{release.js → entrypoints/release.js} +1 -1
  265. package/dist/{remote.d.ts → entrypoints/remote.d.ts} +1 -1
  266. package/dist/entrypoints/remote.d.ts.map +1 -0
  267. package/dist/entrypoints/remote.js +66 -0
  268. package/dist/{server/index.d.ts → entrypoints/server.d.ts} +35 -34
  269. package/dist/entrypoints/server.d.ts.map +1 -0
  270. package/dist/{server/index.js → entrypoints/server.js} +294 -244
  271. package/dist/{telegram.d.ts → entrypoints/telegram.d.ts} +2 -2
  272. package/dist/entrypoints/telegram.d.ts.map +1 -0
  273. package/dist/{telegram.js → entrypoints/telegram.js} +1 -1
  274. package/dist/entrypoints/testing.d.ts +9 -0
  275. package/dist/entrypoints/testing.d.ts.map +1 -0
  276. package/dist/{testing.js → entrypoints/testing.js} +80 -919
  277. package/dist/{tools/connections/index.d.ts → entrypoints/tools/connections.d.ts} +6 -7
  278. package/dist/entrypoints/tools/connections.d.ts.map +1 -0
  279. package/dist/{tools/connections/index.js → entrypoints/tools/connections.js} +7 -4
  280. package/dist/{tools-contract.d.ts → entrypoints/tools/contract.d.ts} +5 -5
  281. package/dist/entrypoints/tools/contract.d.ts.map +1 -0
  282. package/dist/{tools-contract.js → entrypoints/tools/contract.js} +4 -4
  283. package/dist/{tool-invoker.d.ts → entrypoints/tools/invoker.d.ts} +2 -2
  284. package/dist/entrypoints/tools/invoker.d.ts.map +1 -0
  285. package/dist/entrypoints/tools/invoker.js +20 -0
  286. package/dist/entrypoints/tools.d.ts +51 -0
  287. package/dist/entrypoints/tools.d.ts.map +1 -0
  288. package/dist/{tools.js → entrypoints/tools.js} +1787 -1751
  289. package/dist/{tracking-server.d.ts → entrypoints/tracking/server.d.ts} +8 -8
  290. package/dist/entrypoints/tracking/server.d.ts.map +1 -0
  291. package/dist/{tracking.d.ts → entrypoints/tracking.d.ts} +15 -15
  292. package/dist/entrypoints/tracking.d.ts.map +1 -0
  293. package/dist/{tracking.js → entrypoints/tracking.js} +5 -8
  294. package/dist/google/google.d.ts.map +1 -0
  295. package/dist/{index-a916km3r.js → index-0b1ess5e.js} +6 -13
  296. package/dist/{index-zwkgfq1s.js → index-1nd48tm9.js} +113 -118
  297. package/dist/{index-7zbps32p.js → index-1zbbzgfh.js} +2 -2
  298. package/dist/{index-mzvgxp0n.js → index-2cr1cqhn.js} +16 -4
  299. package/dist/{index-f9mb610r.js → index-35mh5bhj.js} +2 -2
  300. package/dist/index-48ffdxgk.js +6 -0
  301. package/dist/index-58k4fp34.js +1023 -0
  302. package/dist/{index-p13mwz16.js → index-83bdg97s.js} +1 -1
  303. package/dist/index-97ac4gph.js +3618 -0
  304. package/dist/{index-kw9t5ayn.js → index-cq4qfycf.js} +5 -5
  305. package/dist/{index-7gnkny4z.js → index-d9pk3td4.js} +1 -1
  306. package/dist/{index-e42wzzz5.js → index-dcpdvjsc.js} +7 -7
  307. package/dist/{index-h9etkkyk.js → index-dydjcp8z.js} +102 -25
  308. package/dist/{index-sr93cwf9.js → index-e2z3ahw9.js} +2 -2
  309. package/dist/{index-yewwh1w4.js → index-e87kakm4.js} +96 -11
  310. package/dist/{index-cby4ar3v.js → index-eqqvgdb3.js} +1 -1
  311. package/dist/index-fdp6hdxn.js +942 -0
  312. package/dist/{index-0a349c33.js → index-gyr48nzg.js} +125 -198
  313. package/dist/{index-wnfk50r0.js → index-h6eeys1v.js} +1 -1
  314. package/dist/{index-77fekveh.js → index-hffjpmq9.js} +1 -15
  315. package/dist/{index-yn8remb1.js → index-j05z5gn4.js} +50 -14
  316. package/dist/index-k5hsfc3j.js +31 -0
  317. package/dist/{index-fq77yfzc.js → index-kj2wbeta.js} +1 -1
  318. package/dist/index-kvj7f4hq.js +39 -0
  319. package/dist/{index-4fpa9dy2.js → index-m9zn6cpq.js} +2 -2
  320. package/dist/{index-2na0qrfn.js → index-mdzh02yc.js} +7 -7
  321. package/dist/{index-ywd0y6m1.js → index-mkm15s49.js} +1 -1
  322. package/dist/index-mp5sn43f.js +1084 -0
  323. package/dist/{index-3bmnp41g.js → index-n6hxg8as.js} +507 -419
  324. package/dist/index-ngfhvfpd.js +30 -0
  325. package/dist/{index-e0znv5gn.js → index-p5r7qpdd.js} +2 -93
  326. package/dist/{index-n0f51dfn.js → index-p81267c2.js} +608 -549
  327. package/dist/{index-wc4x00bn.js → index-qwhynv6x.js} +1 -1
  328. package/dist/index-r7nmqpsg.js +154 -0
  329. package/dist/{index-bx75zwt7.js → index-rewkc2hj.js} +5 -4
  330. package/dist/{index-9f8ztey6.js → index-sees8yf8.js} +2 -2
  331. package/dist/{index-vjpvjqpn.js → index-v38qyerb.js} +16 -2
  332. package/dist/{index-2c2bjw3s.js → index-vcvkq30w.js} +3 -3
  333. package/dist/index-wqgjfstn.js +18 -0
  334. package/dist/{index-f477k430.js → index-x4799c19.js} +1 -1
  335. package/dist/{index-cxqhvq21.js → index-xnj9bgxe.js} +142 -129
  336. package/dist/index-xsqjkha9.js +281 -0
  337. package/dist/{index-6kyksz9y.js → index-yw4fzmdz.js} +1 -1
  338. package/dist/{index-3xwxfj4z.js → index-zeemqhqx.js} +1 -1
  339. package/dist/{index-tmwcrptx.js → index-zfrhfn82.js} +1 -1
  340. package/dist/index-znfs20ss.js +98 -0
  341. package/dist/internal/backoff.d.ts +29 -0
  342. package/dist/internal/backoff.d.ts.map +1 -0
  343. package/dist/internal/canonical-json.d.ts +21 -11
  344. package/dist/internal/canonical-json.d.ts.map +1 -1
  345. package/dist/internal/channel.d.ts.map +1 -0
  346. package/dist/internal/logger.d.ts.map +1 -0
  347. package/dist/internal/request.d.ts.map +1 -0
  348. package/dist/internal/stable-digest.d.ts +0 -43
  349. package/dist/internal/stable-digest.d.ts.map +1 -1
  350. package/dist/internal/typed.d.ts +0 -8
  351. package/dist/internal/typed.d.ts.map +1 -1
  352. package/dist/internal/zod-issues.d.ts +38 -0
  353. package/dist/internal/zod-issues.d.ts.map +1 -0
  354. package/dist/{tools/json-schema-dialect.d.ts → json-schema/dialect.d.ts} +1 -1
  355. package/dist/json-schema/dialect.d.ts.map +1 -0
  356. package/dist/json-schema/json-schema.d.ts.map +1 -0
  357. package/dist/live/watch-delta.d.ts.map +1 -1
  358. package/dist/{oauth.d.ts → oauth/authorization-code.d.ts} +1 -1
  359. package/dist/oauth/authorization-code.d.ts.map +1 -0
  360. package/dist/observability/audit.d.ts +2 -2
  361. package/dist/observability/audit.d.ts.map +1 -1
  362. package/dist/observability/bounded-logger.d.ts +1 -1
  363. package/dist/observability/bounded-logger.d.ts.map +1 -1
  364. package/dist/{internal/observability-sink.d.ts → observability/bounded-sink.d.ts} +2 -2
  365. package/dist/observability/bounded-sink.d.ts.map +1 -0
  366. package/dist/observability/context.d.ts +1 -1
  367. package/dist/observability/context.d.ts.map +1 -1
  368. package/dist/observability/event.d.ts +1 -1
  369. package/dist/observability/event.d.ts.map +1 -1
  370. package/dist/observability/work.d.ts +1 -1
  371. package/dist/observability/work.d.ts.map +1 -1
  372. package/dist/primitives/audit.d.ts +1 -1
  373. package/dist/primitives/audit.d.ts.map +1 -1
  374. package/dist/primitives/export-operation.d.ts +4 -2
  375. package/dist/primitives/export-operation.d.ts.map +1 -1
  376. package/dist/realtime/socket.d.ts +1 -1
  377. package/dist/realtime/socket.d.ts.map +1 -1
  378. package/dist/server/context-contribution.d.ts +1 -1
  379. package/dist/server/context-contribution.d.ts.map +1 -1
  380. package/dist/server/context.d.ts +2 -2
  381. package/dist/server/context.d.ts.map +1 -1
  382. package/dist/server/contract-method.d.ts +15 -0
  383. package/dist/server/contract-method.d.ts.map +1 -0
  384. package/dist/server/contract-stream.d.ts +1 -1
  385. package/dist/server/contract-stream.d.ts.map +1 -1
  386. package/dist/server/create.d.ts +8 -0
  387. package/dist/server/create.d.ts.map +1 -1
  388. package/dist/server/endpoint-dispatch.d.ts +10 -0
  389. package/dist/server/endpoint-dispatch.d.ts.map +1 -0
  390. package/dist/server/endpoint-response.d.ts +18 -0
  391. package/dist/server/endpoint-response.d.ts.map +1 -0
  392. package/dist/server/error-dispatch.d.ts +17 -1
  393. package/dist/server/error-dispatch.d.ts.map +1 -1
  394. package/dist/server/error-hook.d.ts +2 -2
  395. package/dist/server/error-hook.d.ts.map +1 -1
  396. package/dist/server/handler-state.d.ts +44 -0
  397. package/dist/server/handler-state.d.ts.map +1 -0
  398. package/dist/server/implement.d.ts +1 -1
  399. package/dist/server/implement.d.ts.map +1 -1
  400. package/dist/server/middleware/auth.d.ts +1 -1
  401. package/dist/server/middleware/auth.d.ts.map +1 -1
  402. package/dist/server/middleware/cors.d.ts +17 -0
  403. package/dist/server/middleware/cors.d.ts.map +1 -1
  404. package/dist/server/middleware/trust-fence.d.ts +1 -1
  405. package/dist/server/middleware/trust-fence.d.ts.map +1 -1
  406. package/dist/server/multipart.d.ts +1 -1
  407. package/dist/server/multipart.d.ts.map +1 -1
  408. package/dist/{tools/oauth-metadata.d.ts → server/oauth/metadata.d.ts} +2 -2
  409. package/dist/server/oauth/metadata.d.ts.map +1 -0
  410. package/dist/{tools/oauth-provider.d.ts → server/oauth/provider.d.ts} +2 -2
  411. package/dist/server/oauth/provider.d.ts.map +1 -0
  412. package/dist/server/realtime.d.ts +1 -1
  413. package/dist/server/realtime.d.ts.map +1 -1
  414. package/dist/server/request-completion.d.ts +16 -0
  415. package/dist/server/request-completion.d.ts.map +1 -0
  416. package/dist/server/response-metadata.d.ts +1 -1
  417. package/dist/server/response-metadata.d.ts.map +1 -1
  418. package/dist/server/route-table.d.ts +9 -0
  419. package/dist/server/route-table.d.ts.map +1 -0
  420. package/dist/server/stream.d.ts +0 -13
  421. package/dist/server/stream.d.ts.map +1 -1
  422. package/dist/server/types.d.ts +7 -4
  423. package/dist/server/types.d.ts.map +1 -1
  424. package/dist/testing/handler-clients.d.ts +31 -0
  425. package/dist/testing/handler-clients.d.ts.map +1 -0
  426. package/dist/testing/managed-resource-conformance-scenarios.d.ts.map +1 -1
  427. package/dist/testing/surface-conformance.d.ts +2 -1
  428. package/dist/testing/surface-conformance.d.ts.map +1 -1
  429. package/dist/testing/surface-manifest.d.ts +30 -4
  430. package/dist/testing/surface-manifest.d.ts.map +1 -1
  431. package/dist/tools/{cli-args.d.ts → cli/args.d.ts} +1 -1
  432. package/dist/tools/cli/args.d.ts.map +1 -0
  433. package/dist/tools/{cli-checkpoint.d.ts → cli/checkpoint.d.ts} +1 -1
  434. package/dist/tools/cli/checkpoint.d.ts.map +1 -0
  435. package/dist/tools/{cli-command.d.ts → cli/command.d.ts} +4 -4
  436. package/dist/tools/cli/command.d.ts.map +1 -0
  437. package/dist/tools/{cli.d.ts → cli/config.d.ts} +5 -9
  438. package/dist/tools/cli/config.d.ts.map +1 -0
  439. package/dist/tools/cli/create-cli.d.ts +36 -0
  440. package/dist/tools/cli/create-cli.d.ts.map +1 -0
  441. package/dist/tools/cli/download.d.ts +8 -0
  442. package/dist/tools/cli/download.d.ts.map +1 -0
  443. package/dist/tools/{cli-format.d.ts → cli/format.d.ts} +2 -2
  444. package/dist/tools/cli/format.d.ts.map +1 -0
  445. package/dist/tools/cli/help.d.ts +24 -0
  446. package/dist/tools/cli/help.d.ts.map +1 -0
  447. package/dist/tools/{cli-installer.d.ts → cli/installer.d.ts} +2 -2
  448. package/dist/tools/cli/installer.d.ts.map +1 -0
  449. package/dist/tools/{cli-invoke.d.ts → cli/invoke.d.ts} +8 -8
  450. package/dist/tools/cli/invoke.d.ts.map +1 -0
  451. package/dist/tools/cli/io.d.ts +10 -0
  452. package/dist/tools/cli/io.d.ts.map +1 -0
  453. package/dist/tools/cli/managed-surface.d.ts +30 -0
  454. package/dist/tools/cli/managed-surface.d.ts.map +1 -0
  455. package/dist/tools/{cli-manifest.d.ts → cli/manifest.d.ts} +1 -1
  456. package/dist/tools/cli/manifest.d.ts.map +1 -0
  457. package/dist/tools/{cli-policy.d.ts → cli/policy.d.ts} +2 -2
  458. package/dist/tools/cli/policy.d.ts.map +1 -0
  459. package/dist/tools/cli/prepare.d.ts +14 -0
  460. package/dist/tools/cli/prepare.d.ts.map +1 -0
  461. package/dist/tools/{cli-profile.d.ts → cli/profile.d.ts} +2 -2
  462. package/dist/tools/cli/profile.d.ts.map +1 -0
  463. package/dist/tools/cli/run-managed.d.ts +5 -0
  464. package/dist/tools/cli/run-managed.d.ts.map +1 -0
  465. package/dist/tools/cli/run-native.d.ts +9 -0
  466. package/dist/tools/cli/run-native.d.ts.map +1 -0
  467. package/dist/tools/cli/session.d.ts +40 -0
  468. package/dist/tools/cli/session.d.ts.map +1 -0
  469. package/dist/tools/{cli-signature.d.ts → cli/signature.d.ts} +2 -2
  470. package/dist/tools/cli/signature.d.ts.map +1 -0
  471. package/dist/tools/{cli-stream.d.ts → cli/stream.d.ts} +4 -4
  472. package/dist/tools/cli/stream.d.ts.map +1 -0
  473. package/dist/tools/{cli-update.d.ts → cli/update.d.ts} +3 -3
  474. package/dist/tools/cli/update.d.ts.map +1 -0
  475. package/dist/tools/{cli-view.d.ts → cli/view.d.ts} +2 -2
  476. package/dist/tools/cli/view.d.ts.map +1 -0
  477. package/dist/tools/{cli-wait.d.ts → cli/wait.d.ts} +2 -2
  478. package/dist/tools/cli/wait.d.ts.map +1 -0
  479. package/dist/tools/connections/runtime.d.ts +1 -1
  480. package/dist/tools/connections/runtime.d.ts.map +1 -1
  481. package/dist/tools/connections/types.d.ts +3 -3
  482. package/dist/tools/connections/types.d.ts.map +1 -1
  483. package/dist/tools/durability-context.d.ts +1 -1
  484. package/dist/tools/durability-context.d.ts.map +1 -1
  485. package/dist/tools/execute.d.ts +30 -3
  486. package/dist/tools/execute.d.ts.map +1 -1
  487. package/dist/tools/internal/surface-projector.d.ts +8 -6
  488. package/dist/tools/internal/surface-projector.d.ts.map +1 -1
  489. package/dist/tools/internal/tool-view.d.ts +41 -0
  490. package/dist/tools/internal/tool-view.d.ts.map +1 -0
  491. package/dist/tools/invoker.d.ts +11 -3
  492. package/dist/tools/invoker.d.ts.map +1 -1
  493. package/dist/tools/list-names.d.ts +3 -3
  494. package/dist/tools/list-names.d.ts.map +1 -1
  495. package/dist/tools/manifest.d.ts +2 -2
  496. package/dist/tools/manifest.d.ts.map +1 -1
  497. package/dist/tools/{mcp-app.d.ts → mcp/app.d.ts} +1 -1
  498. package/dist/tools/mcp/app.d.ts.map +1 -0
  499. package/dist/tools/{mcp-catalog.d.ts → mcp/catalog.d.ts} +2 -2
  500. package/dist/tools/mcp/catalog.d.ts.map +1 -0
  501. package/dist/tools/{mcp-handler.d.ts → mcp/handler.d.ts} +5 -5
  502. package/dist/tools/mcp/handler.d.ts.map +1 -0
  503. package/dist/tools/{mcp.d.ts → mcp/mount.d.ts} +9 -9
  504. package/dist/tools/mcp/mount.d.ts.map +1 -0
  505. package/dist/tools/{mcp-prepare.d.ts → mcp/prepare.d.ts} +9 -9
  506. package/dist/tools/mcp/prepare.d.ts.map +1 -0
  507. package/dist/tools/{mcp-progress.d.ts → mcp/progress.d.ts} +2 -2
  508. package/dist/tools/mcp/progress.d.ts.map +1 -0
  509. package/dist/tools/mcp/register.d.ts +35 -0
  510. package/dist/tools/mcp/register.d.ts.map +1 -0
  511. package/dist/tools/{mcp-round-policy.d.ts → mcp/round-policy.d.ts} +2 -2
  512. package/dist/tools/mcp/round-policy.d.ts.map +1 -0
  513. package/dist/tools/{mcp-round.d.ts → mcp/round.d.ts} +4 -4
  514. package/dist/tools/mcp/round.d.ts.map +1 -0
  515. package/dist/tools/mcp/runtime-tools.d.ts +24 -0
  516. package/dist/tools/mcp/runtime-tools.d.ts.map +1 -0
  517. package/dist/tools/{mcp-stdio-signals.d.ts → mcp/stdio-signals.d.ts} +3 -3
  518. package/dist/tools/mcp/stdio-signals.d.ts.map +1 -0
  519. package/dist/tools/{mcp-stdio.d.ts → mcp/stdio.d.ts} +4 -4
  520. package/dist/tools/mcp/stdio.d.ts.map +1 -0
  521. package/dist/tools/{mcp-trace.d.ts → mcp/trace.d.ts} +1 -1
  522. package/dist/tools/mcp/trace.d.ts.map +1 -0
  523. package/dist/tools/mount.d.ts +12 -7
  524. package/dist/tools/mount.d.ts.map +1 -1
  525. package/dist/tools/native-definition.d.ts +3 -3
  526. package/dist/tools/native-definition.d.ts.map +1 -1
  527. package/dist/tools/operations/async-operation-binding-types.d.ts +127 -0
  528. package/dist/tools/operations/async-operation-binding-types.d.ts.map +1 -0
  529. package/dist/tools/operations/async-operation-binding.d.ts +28 -0
  530. package/dist/tools/operations/async-operation-binding.d.ts.map +1 -0
  531. package/dist/tools/operations/async-operation-canonical-types.d.ts +110 -0
  532. package/dist/tools/operations/async-operation-canonical-types.d.ts.map +1 -0
  533. package/dist/tools/operations/async-operation-canonical.d.ts +7 -0
  534. package/dist/tools/operations/async-operation-canonical.d.ts.map +1 -0
  535. package/dist/tools/operations/async-operation-contract.d.ts.map +1 -0
  536. package/dist/tools/operations/async-operation-id.d.ts +23 -0
  537. package/dist/tools/operations/async-operation-id.d.ts.map +1 -0
  538. package/dist/tools/operations/async-operation-runtime-tools.d.ts +40 -0
  539. package/dist/tools/operations/async-operation-runtime-tools.d.ts.map +1 -0
  540. package/dist/tools/operations/async-operation-runtime-types.d.ts +68 -0
  541. package/dist/tools/operations/async-operation-runtime-types.d.ts.map +1 -0
  542. package/dist/tools/operations/async-operation-runtime.d.ts +5 -0
  543. package/dist/tools/operations/async-operation-runtime.d.ts.map +1 -0
  544. package/dist/tools/{define-wait-tool.d.ts → operations/define-wait-tool.d.ts} +2 -2
  545. package/dist/tools/operations/define-wait-tool.d.ts.map +1 -0
  546. package/dist/tools/operations/mount-wait.d.ts.map +1 -0
  547. package/dist/tools/operations/wait-core.d.ts.map +1 -0
  548. package/dist/tools/remote.d.ts +1 -1
  549. package/dist/tools/remote.d.ts.map +1 -1
  550. package/dist/tools/runtime-tool.d.ts +11 -4
  551. package/dist/tools/runtime-tool.d.ts.map +1 -1
  552. package/dist/tools/schema/coerce.d.ts.map +1 -0
  553. package/dist/tools/schema/flatten-join.d.ts.map +1 -0
  554. package/dist/tools/schema/flatten.d.ts.map +1 -0
  555. package/dist/tools/schema/portable-formats.d.ts.map +1 -0
  556. package/dist/tools/{presentation.d.ts → schema/presentation.d.ts} +2 -0
  557. package/dist/tools/schema/presentation.d.ts.map +1 -0
  558. package/dist/tools/schema/schema.d.ts.map +1 -0
  559. package/dist/tools/schema/untyped-properties.d.ts.map +1 -0
  560. package/dist/tools/surface.d.ts +2 -3
  561. package/dist/tools/surface.d.ts.map +1 -1
  562. package/dist/tools/toolkit.d.ts +4 -4
  563. package/dist/tools/toolkit.d.ts.map +1 -1
  564. package/dist/tools/{define-download-tool.d.ts → transfer/define-download-tool.d.ts} +4 -4
  565. package/dist/tools/transfer/define-download-tool.d.ts.map +1 -0
  566. package/dist/tools/{define-upload-tool.d.ts → transfer/define-upload-tool.d.ts} +3 -3
  567. package/dist/tools/transfer/define-upload-tool.d.ts.map +1 -0
  568. package/dist/tools/{define-view-file-tool.d.ts → transfer/define-view-file-tool.d.ts} +2 -2
  569. package/dist/tools/transfer/define-view-file-tool.d.ts.map +1 -0
  570. package/dist/tools/{download-core.d.ts → transfer/download-core.d.ts} +2 -2
  571. package/dist/tools/transfer/download-core.d.ts.map +1 -0
  572. package/dist/tools/{managed-file-error.d.ts → transfer/managed-file-error.d.ts} +1 -1
  573. package/dist/tools/transfer/managed-file-error.d.ts.map +1 -0
  574. package/dist/tools/{mount-download.d.ts → transfer/mount-download.d.ts} +1 -1
  575. package/dist/tools/transfer/mount-download.d.ts.map +1 -0
  576. package/dist/tools/{mount-upload.d.ts → transfer/mount-upload.d.ts} +1 -1
  577. package/dist/tools/transfer/mount-upload.d.ts.map +1 -0
  578. package/dist/tools/transfer/native-result.d.ts.map +1 -0
  579. package/dist/tools/{upload-core.d.ts → transfer/upload-core.d.ts} +1 -1
  580. package/dist/tools/transfer/upload-core.d.ts.map +1 -0
  581. package/dist/tools/transfer/view-file-contract.d.ts.map +1 -0
  582. package/dist/tools/{view-file.d.ts → transfer/view-file.d.ts} +1 -1
  583. package/dist/tools/transfer/view-file.d.ts.map +1 -0
  584. package/dist/tools/transports.d.ts +1 -1
  585. package/dist/tools/transports.d.ts.map +1 -1
  586. package/dist/tracking/contract.d.ts +1 -1
  587. package/dist/tracking/contract.d.ts.map +1 -1
  588. package/llms/agent-runtime-browser.txt +33 -0
  589. package/llms/agent-runtime-coding-tools.txt +58 -0
  590. package/llms/agent-runtime-harness.txt +45 -0
  591. package/llms/agent-runtime-openrouter.txt +22 -0
  592. package/llms/agent-runtime-sandbox.txt +159 -0
  593. package/llms/agent-runtime-sqlite-bun.txt +29 -0
  594. package/llms/agent-runtime-sqlite-node.txt +26 -0
  595. package/llms/agent-runtime-testing.txt +30 -0
  596. package/llms/agent-runtime.2.txt +550 -0
  597. package/llms/agent-runtime.3.txt +311 -0
  598. package/llms/agent-runtime.txt +893 -0
  599. package/llms/application-diagnostic-journal.txt +30 -0
  600. package/llms/application-grammy.txt +27 -0
  601. package/llms/application-opentelemetry.txt +27 -0
  602. package/llms/application-schemas.txt +42 -0
  603. package/llms/application.2.txt +223 -0
  604. package/llms/application.txt +1144 -0
  605. package/llms/cli.txt +977 -0
  606. package/llms/contract.txt +606 -0
  607. package/llms/declaration.txt +286 -0
  608. package/llms/files.txt +30 -0
  609. package/llms/geo.txt +114 -0
  610. package/llms/google.txt +27 -0
  611. package/llms/live.txt +471 -0
  612. package/llms/node.txt +43 -0
  613. package/llms/oauth.txt +136 -0
  614. package/llms/observability.txt +893 -0
  615. package/llms/primitives.txt +158 -0
  616. package/llms/react.txt +184 -0
  617. package/llms/release.txt +176 -0
  618. package/llms/remote.txt +25 -0
  619. package/llms/server.2.txt +361 -0
  620. package/llms/server.3.txt +1031 -0
  621. package/llms/server.4.txt +905 -0
  622. package/llms/server.5.txt +250 -0
  623. package/llms/server.txt +996 -0
  624. package/llms/stitchkit.2.txt +836 -0
  625. package/llms/stitchkit.3.txt +147 -0
  626. package/llms/stitchkit.txt +260 -0
  627. package/llms/telegram.txt +30 -0
  628. package/llms/testing.txt +676 -0
  629. package/llms/tools-connections.txt +45 -0
  630. package/llms/tools-contract.txt +9 -0
  631. package/llms/tools-invoker.txt +9 -0
  632. package/llms/tools.2.txt +838 -0
  633. package/llms/tools.txt +1004 -0
  634. package/llms/tracking-server.txt +32 -0
  635. package/llms/tracking.txt +263 -0
  636. package/llms/upgrading-0.37.0-0.50.0.txt +947 -0
  637. package/llms/upgrading-0.53.0-0.67.0.txt +1174 -0
  638. package/llms/upgrading-0.68.0-0.94.0.txt +1159 -0
  639. package/llms/upgrading.txt +215 -0
  640. package/llms-full.txt +214 -75
  641. package/llms.txt +54 -5
  642. package/package.json +84 -83
  643. package/dist/agent-runtime/durability-contract.d.ts.map +0 -1
  644. package/dist/agent-runtime/durability-json.d.ts.map +0 -1
  645. package/dist/agent-runtime/durability-ledger.d.ts.map +0 -1
  646. package/dist/agent-runtime/durability-scheduler.d.ts.map +0 -1
  647. package/dist/agent-runtime/durability.d.ts.map +0 -1
  648. package/dist/agent-runtime/store-driver.d.ts.map +0 -1
  649. package/dist/agent-runtime-browser.d.ts +0 -5
  650. package/dist/agent-runtime-browser.d.ts.map +0 -1
  651. package/dist/agent-runtime-coding-tools.d.ts.map +0 -1
  652. package/dist/agent-runtime-coding-tools.js +0 -23
  653. package/dist/agent-runtime-harness.d.ts.map +0 -1
  654. package/dist/agent-runtime-openrouter.d.ts.map +0 -1
  655. package/dist/agent-runtime-sandbox.d.ts.map +0 -1
  656. package/dist/agent-runtime-sqlite-bun.d.ts.map +0 -1
  657. package/dist/agent-runtime-sqlite-node.d.ts.map +0 -1
  658. package/dist/agent-runtime-testing.d.ts +0 -3
  659. package/dist/agent-runtime-testing.d.ts.map +0 -1
  660. package/dist/agent-runtime-testing.js +0 -156
  661. package/dist/agent-runtime.d.ts.map +0 -1
  662. package/dist/application/channel.d.ts.map +0 -1
  663. package/dist/application-diagnostic-journal.d.ts.map +0 -1
  664. package/dist/application-grammy.d.ts.map +0 -1
  665. package/dist/application-opentelemetry.d.ts.map +0 -1
  666. package/dist/application-schemas.d.ts.map +0 -1
  667. package/dist/application.d.ts.map +0 -1
  668. package/dist/cli.d.ts.map +0 -1
  669. package/dist/contract/index.d.ts +0 -8
  670. package/dist/contract/index.d.ts.map +0 -1
  671. package/dist/declaration.d.ts.map +0 -1
  672. package/dist/files.d.ts.map +0 -1
  673. package/dist/geo.d.ts.map +0 -1
  674. package/dist/google.d.ts.map +0 -1
  675. package/dist/index-0j3vcp5m.js +0 -28
  676. package/dist/index-a11g2kry.js +0 -866
  677. package/dist/index-cnyk6te3.js +0 -77
  678. package/dist/index-fadnxwna.js +0 -1046
  679. package/dist/index-hrbajay7.js +0 -1196
  680. package/dist/index-s8cnx02s.js +0 -90
  681. package/dist/index-v5573g1k.js +0 -142
  682. package/dist/index-vk3kq9sb.js +0 -3344
  683. package/dist/index.d.ts.map +0 -1
  684. package/dist/internal/errors.d.ts.map +0 -1
  685. package/dist/internal/observability-sink.d.ts.map +0 -1
  686. package/dist/live.d.ts.map +0 -1
  687. package/dist/logger.d.ts.map +0 -1
  688. package/dist/node.d.ts.map +0 -1
  689. package/dist/oauth.d.ts.map +0 -1
  690. package/dist/observability/index.d.ts.map +0 -1
  691. package/dist/primitives.d.ts +0 -3
  692. package/dist/primitives.d.ts.map +0 -1
  693. package/dist/react.d.ts.map +0 -1
  694. package/dist/release.d.ts.map +0 -1
  695. package/dist/remote.d.ts.map +0 -1
  696. package/dist/remote.js +0 -88
  697. package/dist/retained.d.ts.map +0 -1
  698. package/dist/server/file-state-store.d.ts.map +0 -1
  699. package/dist/server/index.d.ts.map +0 -1
  700. package/dist/server/request.d.ts.map +0 -1
  701. package/dist/telegram.d.ts.map +0 -1
  702. package/dist/testing/agent-store-conformance.d.ts.map +0 -1
  703. package/dist/testing.d.ts +0 -39
  704. package/dist/testing.d.ts.map +0 -1
  705. package/dist/tool-invoker.d.ts.map +0 -1
  706. package/dist/tool-invoker.js +0 -21
  707. package/dist/tools/async-operation-contract.d.ts.map +0 -1
  708. package/dist/tools/async-operation.d.ts +0 -332
  709. package/dist/tools/async-operation.d.ts.map +0 -1
  710. package/dist/tools/cli-args.d.ts.map +0 -1
  711. package/dist/tools/cli-checkpoint.d.ts.map +0 -1
  712. package/dist/tools/cli-command.d.ts.map +0 -1
  713. package/dist/tools/cli-format.d.ts.map +0 -1
  714. package/dist/tools/cli-installer.d.ts.map +0 -1
  715. package/dist/tools/cli-invoke.d.ts.map +0 -1
  716. package/dist/tools/cli-manifest.d.ts.map +0 -1
  717. package/dist/tools/cli-policy.d.ts.map +0 -1
  718. package/dist/tools/cli-profile.d.ts.map +0 -1
  719. package/dist/tools/cli-signature.d.ts.map +0 -1
  720. package/dist/tools/cli-stream.d.ts.map +0 -1
  721. package/dist/tools/cli-update.d.ts.map +0 -1
  722. package/dist/tools/cli-view.d.ts.map +0 -1
  723. package/dist/tools/cli-wait.d.ts.map +0 -1
  724. package/dist/tools/cli.d.ts.map +0 -1
  725. package/dist/tools/coerce.d.ts.map +0 -1
  726. package/dist/tools/connections/index.d.ts.map +0 -1
  727. package/dist/tools/define-download-tool.d.ts.map +0 -1
  728. package/dist/tools/define-upload-tool.d.ts.map +0 -1
  729. package/dist/tools/define-view-file-tool.d.ts.map +0 -1
  730. package/dist/tools/define-wait-tool.d.ts.map +0 -1
  731. package/dist/tools/download-core.d.ts.map +0 -1
  732. package/dist/tools/flatten-join.d.ts.map +0 -1
  733. package/dist/tools/flatten.d.ts.map +0 -1
  734. package/dist/tools/json-schema-dialect.d.ts.map +0 -1
  735. package/dist/tools/json-schema.d.ts.map +0 -1
  736. package/dist/tools/managed-file-error.d.ts.map +0 -1
  737. package/dist/tools/mcp-app.d.ts.map +0 -1
  738. package/dist/tools/mcp-catalog.d.ts.map +0 -1
  739. package/dist/tools/mcp-handler.d.ts.map +0 -1
  740. package/dist/tools/mcp-prepare.d.ts.map +0 -1
  741. package/dist/tools/mcp-progress.d.ts.map +0 -1
  742. package/dist/tools/mcp-round-policy.d.ts.map +0 -1
  743. package/dist/tools/mcp-round.d.ts.map +0 -1
  744. package/dist/tools/mcp-stdio-signals.d.ts.map +0 -1
  745. package/dist/tools/mcp-stdio.d.ts.map +0 -1
  746. package/dist/tools/mcp-trace.d.ts.map +0 -1
  747. package/dist/tools/mcp.d.ts.map +0 -1
  748. package/dist/tools/mount-download.d.ts.map +0 -1
  749. package/dist/tools/mount-upload.d.ts.map +0 -1
  750. package/dist/tools/mount-wait.d.ts.map +0 -1
  751. package/dist/tools/native-mcp.d.ts +0 -20
  752. package/dist/tools/native-mcp.d.ts.map +0 -1
  753. package/dist/tools/native-result.d.ts.map +0 -1
  754. package/dist/tools/oauth-metadata.d.ts.map +0 -1
  755. package/dist/tools/oauth-provider.d.ts.map +0 -1
  756. package/dist/tools/portable-formats.d.ts.map +0 -1
  757. package/dist/tools/presentation.d.ts.map +0 -1
  758. package/dist/tools/schema.d.ts.map +0 -1
  759. package/dist/tools/untyped-properties.d.ts.map +0 -1
  760. package/dist/tools/upload-core.d.ts.map +0 -1
  761. package/dist/tools/view-file-contract.d.ts.map +0 -1
  762. package/dist/tools/view-file.d.ts.map +0 -1
  763. package/dist/tools/wait-core.d.ts.map +0 -1
  764. package/dist/tools-contract.d.ts.map +0 -1
  765. package/dist/tools.d.ts +0 -50
  766. package/dist/tools.d.ts.map +0 -1
  767. package/dist/tracking-server.d.ts.map +0 -1
  768. package/dist/tracking.d.ts.map +0 -1
  769. package/dist/upgrade-cli.d.ts.map +0 -1
  770. package/dist/{retained.d.ts → browser/retained.d.ts} +0 -0
  771. package/dist/{declaration.d.ts → declaration/declaration.d.ts} +0 -0
  772. package/dist/{upgrade-cli.d.ts → entrypoints/bin/upgrade-cli.d.ts} +0 -0
  773. package/dist/{tracking-server.js → entrypoints/tracking/server.js} +0 -0
  774. package/dist/{google.d.ts → google/google.d.ts} +0 -0
  775. package/dist/{index-pq95qkbf.js → index-5jm36zv1.js} +0 -0
  776. package/dist/{index-actkayzn.js → index-70yj2ebz.js} +3 -3
  777. /package/dist/{application → internal}/channel.d.ts +0 -0
  778. /package/dist/{logger.d.ts → internal/logger.d.ts} +0 -0
  779. /package/dist/{server → internal}/request.d.ts +0 -0
  780. /package/dist/{tools → json-schema}/json-schema.d.ts +0 -0
  781. /package/dist/tools/{async-operation-contract.d.ts → operations/async-operation-contract.d.ts} +0 -0
  782. /package/dist/tools/{mount-wait.d.ts → operations/mount-wait.d.ts} +0 -0
  783. /package/dist/tools/{wait-core.d.ts → operations/wait-core.d.ts} +0 -0
  784. /package/dist/tools/{coerce.d.ts → schema/coerce.d.ts} +0 -0
  785. /package/dist/tools/{flatten-join.d.ts → schema/flatten-join.d.ts} +0 -0
  786. /package/dist/tools/{flatten.d.ts → schema/flatten.d.ts} +0 -0
  787. /package/dist/tools/{portable-formats.d.ts → schema/portable-formats.d.ts} +0 -0
  788. /package/dist/tools/{schema.d.ts → schema/schema.d.ts} +0 -0
  789. /package/dist/tools/{untyped-properties.d.ts → schema/untyped-properties.d.ts} +0 -0
  790. /package/dist/tools/{native-result.d.ts → transfer/native-result.d.ts} +0 -0
  791. /package/dist/tools/{view-file-contract.d.ts → transfer/view-file-contract.d.ts} +0 -0
@@ -0,0 +1,1031 @@
1
+ # stitchkit/server — stitchkit docs slice, part 3 of 5
2
+
3
+ > Generated from the `docs/` tree by `bun run gen:llms`. The index of all slices is
4
+ > `llms.txt` in this package.
5
+ > Continues in `llms/server.4.txt`.
6
+
7
+ Parts of this slice:
8
+ - `llms/server.txt`: Guide: HTTP server (docs/guide/server.md)
9
+ - `llms/server.2.txt`: Guide: HTTP server (docs/guide/server.md)
10
+ - `llms/server.3.txt`: Guide: Realtime (docs/guide/realtime.md)
11
+ - `llms/server.4.txt`: Guide: Auth & errors (docs/guide/auth-and-errors.md) · Guide: Multi-tenant (docs/guide/multi-tenant.md)
12
+ - `llms/server.5.txt`: API reference: `stitchkit/server` (docs/api/reference.md)
13
+
14
+ Also read:
15
+ - see `llms/testing.txt` for the Testing & deployment guide
16
+
17
+ ==============================================================================
18
+ # Guide: Realtime (docs/guide/realtime.md)
19
+ ==============================================================================
20
+
21
+ # Realtime
22
+
23
+ stitchkit's realtime layer is [Socket.IO](https://socket.io) — `polling`
24
+ fallback, heartbeats, acks, a mature client. stitchkit does not ship its own
25
+ WebSocket engine; it ships thin, typed wrappers over Socket.IO and a bridge that
26
+ syncs socket events into the TanStack Query cache. See
27
+ [ADR 0008](../decisions/0008-thin-wrappers.md).
28
+ The separate contract shape and rejection ownership are recorded in
29
+ [ADR 0069](../decisions/0069-realtime-contracts-validate-without-owning-delivery.md).
30
+
31
+ ## Zod-first event contract
32
+
33
+ Declare wire events once in the shared module. Each `args` schema is a tuple, so
34
+ Socket.IO's no-payload and variadic forms stay intact; `ack` describes the value
35
+ returned through an acknowledgement callback.
36
+
37
+ ```ts
38
+ // shared/contracts.ts
39
+ import { defineRealtimeContract } from 'stitchkit'
40
+ import { z } from 'zod'
41
+
42
+ export const realtimeContract = defineRealtimeContract({
43
+ serverToClient: {
44
+ 'note:created': { args: z.tuple([NoteSchema]) },
45
+ 'note:deleted': { args: z.tuple([z.string()]) },
46
+ },
47
+ clientToServer: {
48
+ 'room:join': {
49
+ args: z.tuple([z.string()]),
50
+ ack: z.object({ joined: z.boolean() }),
51
+ },
52
+ ready: { args: z.tuple([]) },
53
+ },
54
+ })
55
+ ```
56
+
57
+ The contract derives every event handler type and validates both directions at
58
+ runtime. A malformed inbound tuple never reaches the application handler;
59
+ invalid outbound data throws before Socket.IO publishes it. Rejections call the
60
+ optional `onRejected` hook with event, direction, phase and the Zod error.
61
+
62
+ ### Protocol generations
63
+
64
+ For a distributed producer/consumer pair, put a literal generation first in the
65
+ first payload object. Zod validates object fields in declaration order, so an
66
+ incompatible peer is identified before the rest of its payload is interpreted:
67
+
68
+ ```ts
69
+ const ReplicationMessage = z.object({
70
+ v: z.literal(2),
71
+ item: ReplicatedItem,
72
+ })
73
+
74
+ const realtimeContract = defineRealtimeContract({
75
+ serverToClient: {
76
+ replicated: { args: z.tuple([ReplicationMessage]) },
77
+ },
78
+ clientToServer: {},
79
+ })
80
+ ```
81
+
82
+ A frame that fails this check is **refused, and the sender is told so** — when
83
+ the event has an acknowledgement. `request()` rejects with
84
+ `RealtimeRequestRejectedError`, immediately, carrying the peer's own issues:
85
+
86
+ ```ts
87
+ import { RealtimeRequestRejectedError } from 'stitchkit'
88
+
89
+ try {
90
+ await socket.request('replicate', message, { timeoutMs: 5_000 })
91
+ } catch (error) {
92
+ if (error instanceof RealtimeRequestRejectedError) {
93
+ // reason: 'invalid-arguments'; issues: [{ path: '0.v', code: 'invalid_value', … }]
94
+ if (error.issues?.some((issue) => issue.path === '0.v')) schedulePeerUpgrade()
95
+ else reportMalformedRealtimePayload(error)
96
+ }
97
+ }
98
+ ```
99
+
100
+ `path` is `'0.v'` and not `'v'` because event arguments are a tuple: index `0`
101
+ is the first payload. The issues are already flattened by Stitchkit's own
102
+ normaliser, so telling "wrong generation" from "malformed payload" is one
103
+ comparison rather than an inspection of a `ZodError`'s internals.
104
+
105
+ The receiving side still reports it locally through `onRejected` — a refusal is
106
+ now visible on **both** ends rather than only where it happened.
107
+
108
+ **Two limits, both real.** A **fire-and-forget** event has no acknowledgement
109
+ channel, so its refusal stays local: the sender learns nothing, and no
110
+ convention in the payload can change that. And an event the receiver's contract
111
+ does not contain has no listener at all, so there is nothing on that side to
112
+ answer with — adding an event is not a change a generation field can announce.
113
+
114
+ ### Where protocol identity belongs
115
+
116
+ For a distributed pair whose planes are mostly fire-and-forget, compare
117
+ identity **at the handshake** instead, where a mismatch is refused before the
118
+ first frame is interpreted and both ends see it at once. The typed handshake is
119
+ already the place:
120
+
121
+ ```ts
122
+ const handshake = {
123
+ schema: z.object({ token: z.string(), protocol: z.string() }),
124
+ verify: (auth) => {
125
+ if (auth.protocol !== PROTOCOL_IDENTITY) return null // refused, with a reason
126
+ return { subject: verifyToken(auth.token) }
127
+ },
128
+ }
129
+ ```
130
+
131
+ The client sends it as `auth`, and a rejection reaches `onConnectError` with
132
+ `terminal: true` — distinguishable in a log from a bad token, so a half-rolled
133
+ deployment reads as a half-rolled deployment and not as an access problem.
134
+
135
+ What that identity *is* remains the application's decision — a build version, a
136
+ contract hash, a protocol generation. Stitchkit does not compare it for you
137
+ (→ ADR 0002); it gives the place where the comparison happens before any frame
138
+ is interpreted, and it makes the per-frame alternative honest by letting its
139
+ refusals be seen.
140
+
141
+ ## Server — `createSocketIOServer`
142
+
143
+ ```ts
144
+ import {
145
+ bindRealtimeServer,
146
+ createServer,
147
+ createSocketIOServer,
148
+ } from 'stitchkit/server'
149
+ import { realtimeContract } from '@app/shared'
150
+
151
+ const socket = await createSocketIOServer({
152
+ cors: { origin: 'https://app.example.com' },
153
+ })
154
+
155
+ const realtime = bindRealtimeServer(realtimeContract, socket, {
156
+ onRejected: (event) => audit.realtimeRejected(event),
157
+ })
158
+
159
+ realtime.onConnection(({ raw, events, to }) => {
160
+ events.on('room:join', (room, acknowledge) => {
161
+ raw.join(room) // authorization and room membership remain application policy
162
+ acknowledge({ joined: true })
163
+ to(room).emit('note:created', note)
164
+ })
165
+ })
166
+ ```
167
+
168
+ Pass the full handle to `createServer`; it mounts and owns the transport once:
169
+
170
+ ```ts
171
+ createServer({
172
+ services,
173
+ socket,
174
+ })
175
+
176
+ // elsewhere — validated broadcast:
177
+ realtime.emit('note:created', note)
178
+ ```
179
+
180
+ `socket.io` and, on Bun, `@socket.io/bun-engine` are optional peers, resolved
181
+ lazily so a project that never opens a socket does not have to install them. If
182
+ you ship **one self-contained file** to a machine with no `node_modules`, tell
183
+ the framework how to load them so your bundler can put them inside — see
184
+ [shipping one self-contained artifact](./testing-and-deployment.md#shipping-one-self-contained-artifact).
185
+
186
+ The canonical room-broadcast example below is executed by the test suite. Its
187
+ body is kept byte-identical to `packages/core/examples/realtime/realtime-room.ts`.
188
+
189
+ ```ts canonical-realtime-room
190
+ export function publishExampleNote(realtime: ExampleRealtimePublisher): void {
191
+ const note = { id: 'note-1', text: 'Ready' };
192
+ realtime.to('general').emit('note:created', note);
193
+ }
194
+ ```
195
+
196
+ | Handle field | Purpose |
197
+ |--------------|---------|
198
+ | `io` | raw Socket.IO server for middleware, handshake auth and transport ownership |
199
+ | `websocket` | Bun handlers used directly only in explicit raw-lane composition |
200
+ | `route` | `/socket.io/*socketPath`, mounted automatically by `createServer({ socket })` |
201
+ | `close()` | idempotent standalone close for CLI/tools with no HTTP server |
202
+ | `beginShutdown()` / `connections()` | lifecycle surface consumed by the managed server |
203
+
204
+ `SocketIOServerConfig` also takes `path`, `transports`, `pingTimeout`,
205
+ `pingInterval`, a runtime-neutral `allowRequest(Request)` handshake policy and
206
+ the typed **`handshake`** identity gate (schema + verify →
207
+ [typed `socket.data`](#handshake-auth--cookie-or-token)). `allowRequest` is the
208
+ transport gate (composed with managed-shutdown admission on both Bun and Node);
209
+ `handshake` is the identity gate that runs after it.
210
+ `transports` is an admission allowlist: `['websocket']` refuses polling,
211
+ `['polling']` refuses WebSocket handshakes/upgrades, and both explicitly enabled
212
+ transports remain usable. Defaults are both transports on Bun and WebSocket-only
213
+ on Node. Bun enforces this before consumer authorization through the engine's
214
+ request-policy extension (including existing sessions); Node uses native Engine.IO
215
+ enforcement. Bun's native upgrade hints do not override the allowlist. CORS
216
+ preflight is not transport admission and keeps its ordinary behavior.
217
+ For anything else socket.io's `ServerOptions` exposes, use the
218
+ typed **`serverOptions`** passthrough — most often `maxHttpBufferSize` to lift the
219
+ 1 MB default for large emits:
220
+
221
+ ```ts
222
+ await createSocketIOServer({
223
+ cors: { origin: 'https://app.example.com' },
224
+ serverOptions: { maxHttpBufferSize: 5 * 1024 * 1024 }, // 5 MB
225
+ })
226
+ ```
227
+
228
+ `cors` is **optional**. Omit it when the browser reaches this server on its
229
+ own origin — Socket.IO then emits no CORS headers, which is same-origin only.
230
+ Supply it only for a genuinely cross-origin browser: naming a foreign origin is
231
+ naming where the code will run, and a repository that does not have to know
232
+ should not say.
233
+
234
+ The wrapper-owned fields (`cors` / `path` / `transports` / `ping*` /
235
+ `allowRequest`) take
236
+ precedence over the same keys in `serverOptions`. On Bun the engine-level options
237
+ (`maxHttpBufferSize`, the ping heartbeat, `upgradeTimeout`) are forwarded to
238
+ `@socket.io/bun-engine` too — so a configured `maxHttpBufferSize` actually applies
239
+ instead of silently truncating at 1 MB.
240
+
241
+ ## Client — `createRealtimeClient`
242
+
243
+ ```ts
244
+ import { createRealtimeClient } from 'stitchkit'
245
+ import { realtimeContract } from '@app/shared'
246
+
247
+ const socket = createRealtimeClient(realtimeContract, {
248
+ url: 'https://api.example.com',
249
+ retain: ['note:created'],
250
+ onRejected: (event) => reportClientError(event),
251
+ onRequestPhase: (event) => metrics.realtimeRequestPhase(event),
252
+ })
253
+
254
+ socket.connect()
255
+ socket.on('note:created', (note) => { /* typed note */ })
256
+ socket.emit('room:join', 'general', ({ joined }) => { /* typed + validated */ })
257
+ ```
258
+
259
+ When an application already owns the low-level Stitchkit transport, bind the
260
+ contract without opening a second connection:
261
+
262
+ ```ts
263
+ import { bindRealtimeClient, createSocketIOClient } from 'stitchkit'
264
+
265
+ const transport = createSocketIOClient({ url: 'https://api.example.com' })
266
+ const events = bindRealtimeClient(realtimeContract, transport, { onRejected })
267
+
268
+ transport.connect() // lifecycle stays with the transport owner
269
+ events.on('note:created', handleNote)
270
+ await events.request('room:join', 'general', { timeoutMs: 5_000 })
271
+ ```
272
+
273
+ The bound handle intentionally has no `connect()` or `disconnect()`. Its
274
+ `on`/`emit`/`request`, rejection and timeout semantics are exactly the path used
275
+ by `createRealtimeClient`; only transport construction/lifecycle differs.
276
+
277
+ ## Snapshot + event state synchronization
278
+
279
+ `createLiveStateController` is the optional browser-safe state machine between a
280
+ validated transport binding and any renderer. It solves one problem: install a
281
+ snapshot and every event after that snapshot's consistency point without a race.
282
+ It does not create a socket, choose a cursor, retry a transport, store history or
283
+ invent ordering for the application.
284
+
285
+ ```ts
286
+ import {
287
+ createLiveStateController,
288
+ type LiveStateEventDecision,
289
+ type LiveStateSource,
290
+ } from 'stitchkit'
291
+
292
+ type View = { revision: number; rows: readonly Row[] }
293
+ type Change = { revision: number; row: Row }
294
+
295
+ const applyChange = (state: View, event: Change): LiveStateEventDecision<View> => {
296
+ if (event.revision <= state.revision) return { outcome: 'duplicate' }
297
+ if (event.revision !== state.revision + 1) return { outcome: 'gap' }
298
+ return {
299
+ outcome: 'applied',
300
+ state: { revision: event.revision, rows: [...state.rows, event.row] },
301
+ }
302
+ }
303
+
304
+ const live = createLiveStateController({
305
+ source,
306
+ applyEvent: applyChange,
307
+ maxBufferedEvents: 128,
308
+ maxBufferedBytes: 256 * 1024,
309
+ sizeOfEvent: encodedChangeBytes,
310
+ })
311
+
312
+ const unsubscribe = live.subscribe(render)
313
+ await live.start()
314
+ // On a gap/overflow or source loss, choose when the UI should resync.
315
+ const status = live.getSnapshot()
316
+ if (status.phase === 'resync-required' || status.phase === 'unavailable') {
317
+ await live.resync()
318
+ }
319
+
320
+ unsubscribe()
321
+ await live.close()
322
+ ```
323
+
324
+ The source boundary is the important part:
325
+
326
+ ```ts
327
+ interface LiveStateSource<State, Event> {
328
+ open(input: {
329
+ signal: AbortSignal
330
+ onEvent(event: Event): void
331
+ onUnavailable(): void
332
+ }): Promise<{ snapshot: State; close(): void | Promise<void> }>
333
+ }
334
+ ```
335
+
336
+ `onEvent` is available before `open()` begins asynchronous work. By the time
337
+ `open()` resolves, the source guarantees that every event after the returned
338
+ snapshot's consistency point has already been or will be passed to that callback.
339
+ The controller buffers early events within both explicit limits, installs the
340
+ snapshot, drains in order, then becomes `live`. A late result from an earlier
341
+ `resync()` generation is fenced. Non-cooperative caller-owned cleanup is asked to
342
+ stop but cannot hold controller settlement.
343
+
344
+ `subscribe()` listeners are synchronous external-store notifications: read the
345
+ published snapshot and schedule rendering elsewhere. A listener that returns a
346
+ Promise is removed after its first call, preventing unresolved UI work from
347
+ accumulating per event. Source `close()` must be idempotent because an abort-aware
348
+ binding may have started cleanup before the controller calls it.
349
+
350
+ At most two physical source `open()` / `close()` operations in total may remain
351
+ unsettled. If a caller-owned source ignores cancellation beyond that operation
352
+ bound, `resync()` returns
353
+ `unavailable/controller-capacity` without opening another generation. When a slot
354
+ settles, the controller publishes `resync-required/controller-capacity`; the host
355
+ may retry explicitly. This bounds controller-retained work without inventing a
356
+ transport retry loop.
357
+
358
+ ### Socket.IO binding
359
+
360
+ Use an acknowledged operation whose server handler establishes the subscription
361
+ before it captures/returns the snapshot. For example, the server can join the
362
+ socket to the resource room, capture revision `N`, then acknowledge that snapshot;
363
+ ordered Socket.IO frames after that point reach the already-installed handler:
364
+
365
+ ```ts
366
+ const source: LiveStateSource<View, Change> = {
367
+ async open({ signal, onEvent, onUnavailable }) {
368
+ const offEvent = socket.on('view:changed', onEvent)
369
+ const offConnection = socket.onConnectionChange((connected) => {
370
+ if (!connected) onUnavailable()
371
+ })
372
+ let closed = false
373
+ const close = () => {
374
+ if (closed) return
375
+ closed = true
376
+ offEvent()
377
+ offConnection()
378
+ }
379
+ signal.addEventListener('abort', close, { once: true })
380
+
381
+ try {
382
+ const snapshot = await socket.request('view:open', { timeoutMs: 5_000 })
383
+ return { snapshot, close }
384
+ } catch (error) {
385
+ close()
386
+ throw error
387
+ }
388
+ },
389
+ }
390
+ ```
391
+
392
+ Socket.IO still owns physical reconnect. A reconnected transport only means the
393
+ connection is open; call `resync()` when application state needs a fresh
394
+ generation. If the application has replay, its source may resume from its opaque
395
+ cursor and return an accepted consistency point. If history expired or a cursor is
396
+ incompatible, the source must acquire a fresh authoritative snapshot or reject the
397
+ open; the controller does not classify or compare opaque cursors itself.
398
+
399
+ ### One-way HTTP stream binding
400
+
401
+ NDJSON/SSE can use the same receiver semantics when **one response generation**
402
+ starts with a schema-validated snapshot frame and every later frame is a validated
403
+ event. Attach `parseNDJSON` or the typed contract-stream reader, parse the first
404
+ frame before resolving `open()`, and pump remaining frames into `onEvent`. Abort
405
+ that response in `close()`.
406
+
407
+ A separate `GET /snapshot` followed by `GET /events` is not this boundary: a
408
+ change can land between the two requests and disappear unless the application
409
+ supplies a watermark/replay protocol. The controller intentionally cannot make
410
+ that uncoordinated recipe safe.
411
+
412
+ ### Rendering, cache and process lifecycle
413
+
414
+ For replaceable progress, let the reducer replace the absolute view at each
415
+ accepted revision. For ordered records, append only the exact next revision and
416
+ return `gap` otherwise. Both use the same controller; their ordering policy stays
417
+ in their reducers. `getSnapshot()` + `subscribe()` works headlessly and with
418
+ `useSyncExternalStore`. A React Query application can update its existing query
419
+ cache from a subscriber after `phase === 'live'`; no second hook or store adapter
420
+ is required. Cache `markFresh` windows suppress local echoes, while revision/cursor
421
+ classification detects duplicates—those are different policies.
422
+
423
+ A server process that owns such a receiver can place `start()` and `close()` in
424
+ an existing `defineManagedResource` and include it in `createApplication`.
425
+ Readiness follows a successful `live` snapshot; shutdown calls `close()`. Stitchkit
426
+ does not add another supervisor, reconnect loop or durable event database.
427
+
428
+ When migrating a hand-written receiver, remove only the superseded attach/snapshot
429
+ race loop, retry timer and listener bookkeeping. Keep the application's schemas,
430
+ authorization, reducer, cursor/replay policy and durable storage. Development
431
+ proxying and Vite HMR remain frontend tooling; they are described in
432
+ [frontend integrations](./frontend-integrations.md) and never travel through live
433
+ application event envelopes.
434
+
435
+ The Agent harness control server follows the same ordering: it installs the
436
+ conversation attachment before awaiting the authoritative snapshot and rolls the
437
+ attachment back if that read fails. A host adapter installs its delivery callback,
438
+ issues `attach`, and supplies the returned snapshot through its live-state source;
439
+ the existing Agent cursor and view reducers still own runtime epochs, durable
440
+ versions and transcript projection.
441
+
442
+ ### Request-response over realtime
443
+
444
+ For an event with an `ack` schema, `request()` is the Promise form of the same
445
+ native Socket.IO acknowledgement. Arguments and the resolved value are inferred
446
+ from the contract and validated on both sides:
447
+
448
+ ```ts
449
+ const result = await socket.request(
450
+ 'room:join',
451
+ 'general',
452
+ {
453
+ timeoutMs: 5_000,
454
+ onPhase: (phase) => roomJoinMetrics.record(phase),
455
+ },
456
+ )
457
+ // result: { joined: boolean }
458
+ ```
459
+
460
+ An event without `ack` cannot be passed to `request()` by type. A disconnected
461
+ client rejects immediately with `RealtimeRequestDisconnectedError`; an in-flight
462
+ disconnect uses the same error; an elapsed native acknowledgement timeout uses
463
+ `RealtimeRequestTimeoutError`. These are distinct stable classes and codes, so
464
+ never parse Socket.IO error text. An invalid acknowledgement still fires the
465
+ existing `onRejected` hook with phase `acknowledgement`, then rejects with
466
+ `RealtimeRequestInvalidAcknowledgementError`.
467
+
468
+ `timeoutMs` must be finite and greater than zero. Use acknowledgements only for
469
+ bounded request-response work. A job that runs for minutes, progress streaming,
470
+ or resumable delivery should use separate correlated events or the async
471
+ operation protocol; keeping one acknowledgement open is not a durable RPC/job
472
+ transport.
473
+
474
+ ### Acknowledged-request phases
475
+
476
+ `createRealtimeClient` can expose the local boundary that a single Promise
477
+ normally hides:
478
+
479
+ ```ts
480
+ const socket = createRealtimeClient(realtimeContract, {
481
+ url,
482
+ onRequestPhase: ({ requestId, event, phase, elapsedMs }) => {
483
+ requestPhaseHistogram.record(elapsedMs, { requestId, event, phase })
484
+ },
485
+ })
486
+ ```
487
+
488
+ The hook is opt-in and each record has exactly four metadata fields: an opaque,
489
+ Kit-owned `requestId`, the contract event name, monotonic `elapsedMs`, and one
490
+ closed phase:
491
+
492
+ | Phase | Exact local boundary |
493
+ |-------|----------------------|
494
+ | `engine-handoff` | Engine.IO created the outbound message packet and accepted it into its write path |
495
+ | `engine-ack-received` | Engine.IO decoded the inbound acknowledgement message, before Socket.IO invokes the acknowledgement callback |
496
+ | `settled` | the acknowledgement callback ran and Stitchkit finished acknowledgement validation |
497
+ | `timeout` | the existing native acknowledgement timeout won |
498
+ | `disconnected` | the request began disconnected or an in-flight disconnect won |
499
+
500
+ Observation also works on non-localhost HTTP origins: identity generation uses
501
+ browser-compatible `crypto.getRandomValues`, not secure-context-only
502
+ `crypto.randomUUID`. A `requestId` is opaque local diagnostic identity, not a
503
+ promised UUID format, authentication token or transmitted field. Bun and Node
504
+ use the same mechanism; enabling observation adds no HTTPS requirement.
505
+
506
+ When a caller needs to join those phases to its own invocation, put `onPhase`
507
+ on that request's options and keep the caller identity in the hook's closure:
508
+
509
+ ```ts
510
+ await socket.request('room:join', 'general', {
511
+ timeoutMs: 5_000,
512
+ onPhase: (phase) => recordPhase({ operationId, phase }),
513
+ })
514
+ ```
515
+
516
+ The client-wide hook receives every observed request; a request hook receives
517
+ only its invocation. If the same function is supplied in both places it runs
518
+ once per phase. The closure is local: Stitchkit does not retain `operationId`,
519
+ add it to the event or transmit it to the peer. A request hook works without a
520
+ client-wide hook, and the no-hook path installs no phase listeners.
521
+
522
+ Engine handoff is not proof of a physical network write. Engine acknowledgement
523
+ receipt is not a remote clock, end-to-end RTT or proof that application
524
+ validation has run. The useful interval is local and monotonic:
525
+ `engine-ack-received → settled` isolates callback scheduling plus validation
526
+ from transport waiting.
527
+
528
+ Records never contain request arguments, acknowledgement values, raw packets,
529
+ credentials, URLs or query data. Concurrent requests are correlated internally
530
+ with Socket.IO acknowledgement ids, but those ids are never exposed. A timeout
531
+ or disconnect is terminal, a late packet cannot reopen the identity, and sync
532
+ or async observer failures are ignored so telemetry cannot change request
533
+ correctness. With no hook, no request identity, Engine.IO listener or correlation
534
+ map entry is created. The low-level `createSocketIOClient` implements the same
535
+ request option, so a non-owning `bindRealtimeClient` over that transport keeps
536
+ request-scoped observation without opening a second connection.
537
+
538
+ ## Low-level transport
539
+
540
+ `createSocketIOClient` remains the low-level Socket.IO transport wrapper for
541
+ schema-agnostic infrastructure. Application wire events should use
542
+ `createRealtimeClient`; it adds the shared contract without replacing Socket.IO.
543
+ Use `bindRealtimeClient` when that low-level transport already exists.
544
+
545
+ ### Durable subscriptions
546
+
547
+ `socket.on(...)` returns an unsubscribe and is **durable** — the handler is
548
+ re-attached to every socket the client builds, so it survives a reconnect. You
549
+ subscribe once; reconnection is the wrapper's problem, not yours.
550
+
551
+ `SocketIOClientConfig` takes `url`, `path`, `withCredentials` (cookies on the
552
+ handshake — default `true`), `auth`, `query`, `extraHeaders`, `transports`,
553
+ `reconnectionAttempts`, `reconnectionDelay`, `retain` (below), `onConnectError`
554
+ (handshake/connection failures — see the auth section) and `onDroppedEmit`
555
+ (observability for emits dropped while disconnected — see below).
556
+
557
+ ### Honest emit — what happens while disconnected
558
+
559
+ `emit` has exactly three outcomes, in order:
560
+
561
+ 1. **A local contract violation throws** (validated `RealtimeClient` only) —
562
+ validation runs before the connection guard, even while disconnected.
563
+ 2. **Disconnected → the emit is dropped**: `emit` returns `false` and the
564
+ `onDroppedEmit` hook fires with the event name and wire arguments. This
565
+ includes the short window right after `connect()` while the socket.io peer
566
+ is still loading.
567
+ 3. **Otherwise `emit` returns `true`** — handed to the transport, which is
568
+ *not* a delivery guarantee.
569
+
570
+ The default is deliberately a drop, not a buffer: after a reconnect, durable
571
+ subscriptions and [sticky events](#sticky-events) replay current state
572
+ deterministically, instead of the server receiving an unordered backlog of
573
+ stale emits. What changed is that the drop is now observable — assert it
574
+ per-call (`if (!client.emit(...)) …`) or centrally:
575
+
576
+ ```ts
577
+ const client = createSocketIOClient({
578
+ url,
579
+ onDroppedEmit: ({ event }) => metrics.count('realtime.dropped_emit', { event }),
580
+ })
581
+ ```
582
+
583
+ Server-side emits (`realtime.emit`, `to(room).emit`, `connection.events.emit`)
584
+ always return `true` — a broadcast into an empty room is not a drop, and the
585
+ server has no disconnected state of this kind. For state that must survive
586
+ gaps, see [durability](#durability--idempotent--replay).
587
+
588
+ ### Sticky events
589
+
590
+ A handler that subscribes **after** an event was emitted misses it — the UI stays
591
+ on stale state until the next emission. List those events in **`retain`** and the
592
+ client keeps each one's last payload and replays it to a handler the moment it
593
+ subscribes (and on the next subscribe after a re-render). It is the pub/sub
594
+ analogue of an MQTT *retained* message or an RxJS `BehaviorSubject`.
595
+
596
+ ```ts
597
+ const client = createRealtimeClient(realtimeContract, {
598
+ url,
599
+ retain: ['presence:changed', 'job:state'], // events to keep the last value of
600
+ })
601
+ client.connect()
602
+
603
+ // Later — even after the event already fired — this handler fires at once with
604
+ // the last value, then on every future change:
605
+ client.on('job:state', (s) => render(s))
606
+ ```
607
+
608
+ The retained value survives a `disconnect()` / `connect()` cycle (the store lives
609
+ outside the socket). Only an event's **first** argument is retained.
610
+
611
+ For a pub/sub channel that is **not** Socket.IO (your own transport — see
612
+ [below](#bring-your-own-transport)), use the same memory directly:
613
+
614
+ ```ts
615
+ import { createRetainedTopics } from 'stitchkit'
616
+
617
+ const topics = createRetainedTopics<{ 'job:state': JobState }>()
618
+ topics.record('job:state', state) // on every publish
619
+ topics.replay('job:state', (s) => render(s)) // for a late subscriber
620
+ ```
621
+
622
+ ### Handshake auth — cookie or token
623
+
624
+ By default the handshake carries cookies (`withCredentials: true`) — the right
625
+ fit for a browser app with a session cookie. A client that holds a token
626
+ explicitly (desktop, mobile, CLI, server-to-server) authenticates the
627
+ handshake with **`auth`** instead — the token reaches the server as
628
+ `socket.handshake.auth`:
629
+
630
+ ```ts
631
+ // client — a function is re-read on every (re)connect, so a rotated token is
632
+ // picked up automatically; no need to recreate the client (or lose durable
633
+ // subscriptions). It may be async.
634
+ const socket = createRealtimeClient(realtimeContract, {
635
+ url: 'https://api.example.com',
636
+ auth: () => ({ token: getAccessToken() }),
637
+ })
638
+ ```
639
+
640
+ ```ts
641
+ // server — the typed identity gate: Zod-validate handshake.auth, verify,
642
+ // and the result lands in socket.data — typed all the way to onConnection.
643
+ import { verifyJwt } from 'stitchkit/server'
644
+
645
+ const socket = await createSocketIOServer({
646
+ cors: { origin: 'https://app.example.com' },
647
+ handshake: {
648
+ schema: z.object({ token: z.string() }),
649
+ verify: async ({ token }) => ({ user: await verifyJwt(token, secret) }),
650
+ },
651
+ })
652
+
653
+ const realtime = bindRealtimeServer(realtimeContract, socket)
654
+ realtime.onConnection(({ raw }) => {
655
+ raw.data.user // typed — no String(...) coercions, no casts
656
+ })
657
+ ```
658
+
659
+ `verify` may be async (the wrapper runs it inside a settled promise chain —
660
+ raw async `io.use` middleware would leak an unhandled rejection); throwing or
661
+ returning `null` rejects the handshake **before** the connection handler and
662
+ before any event validation. A thrown error's raw message is logged
663
+ server-side and never reaches the unauthenticated peer — the wire always
664
+ carries the generic `handshake rejected` (the same never-leak policy as the
665
+ HTTP error normalizer). The schema itself must be synchronous (no async
666
+ refine/transform). Omit `verify` and the schema output itself is the
667
+ identity. The gate registers as the **first** middleware, so `socket.io.use(…)`
668
+ middlewares you add afterwards see the typed `socket.data` already in place.
669
+ Raw `io.use` remains available for anything beyond identity.
670
+
671
+ Type inference works on calls without explicit event generics (the
672
+ `bindRealtimeServer` lane above). With explicit generics TypeScript cannot
673
+ partially infer — pass the identity types too:
674
+ `createSocketIOServer<S, C, z.infer<typeof schema>, Identity>`.
675
+
676
+ A static object (`auth: { token }`) works too, but only the function form
677
+ re-reads on reconnect — prefer it for rotating tokens. `query` adds handshake
678
+ URL params (`socket.handshake.query`) — note its values are **strings** on the
679
+ wire, which is why the schema gate reads `auth`; `extraHeaders` adds handshake
680
+ headers, but in a browser those apply to the **polling** transport only (a
681
+ WebSocket upgrade cannot set request headers) — for browser WebSocket auth use
682
+ `auth`.
683
+
684
+ **A gate rejection is terminal for the client.** Unlike a transport-level
685
+ failure (which socket.io retries indefinitely), a middleware/handshake-gate
686
+ rejection stops the client: socket.io destroys its retry path and will not
687
+ reconnect on its own. The stitchkit client surfaces this through
688
+ **`onConnectError`** with `terminal: true` (and `data.code ===
689
+ 'handshake_rejected'` for the built-in gate) and resets its connection intent —
690
+ so recovery is explicit: rotate the credential, call `connect()`, and the
691
+ function-form `auth` is re-read:
692
+
693
+ ```ts
694
+ const client = createRealtimeClient(realtimeContract, {
695
+ url: 'https://api.example.com',
696
+ auth: () => ({ token: getAccessToken() }),
697
+ onConnectError: ({ terminal }) => {
698
+ if (terminal) refreshTokenThen(() => client.connect())
699
+ },
700
+ })
701
+ ```
702
+
703
+ If an auth producer throws or rejects, the wrapper sends an empty auth object —
704
+ the server gate then rejects it visibly (via `onConnectError`) instead of
705
+ leaving the handshake waiting forever.
706
+
707
+ ## Cache bridge
708
+
709
+ **Using a validated realtime contract? Use `createRealtimeCacheBridge`.** A
710
+ realtime registry maps an event name to its *definition* (`{ args, ack }`),
711
+ while the plain bridge's event map expects the *handler function* at that
712
+ position. A validated socket satisfies the looser type structurally, so passing
713
+ one to `createCacheBridge` compiled and inferred every payload as `never` —
714
+ the error then landed on your own property access rather than on the seam.
715
+ `createRealtimeCacheBridge` performs the mapping; nothing runs differently.
716
+
717
+ ```ts
718
+ import { createRealtimeCacheBridge } from 'stitchkit/react'
719
+
720
+ const bridge = createRealtimeCacheBridge<typeof contract.serverToClient>({
721
+ socket: realtimeClient,
722
+ queryClient,
723
+ handlers: {
724
+ noteUpdated: (note, { queryClient: qc }) => qc.setQueryData(noteKey(note.id), note),
725
+ },
726
+ })
727
+ ```
728
+
729
+ `createCacheBridge` syncs socket events into the TanStack Query cache — a server
730
+ push updates the UI with no refetch. It is transport-agnostic: it takes any
731
+ emitter with `on(event, handler) => unsubscribe`, which the
732
+ `createSocketIOClient` result satisfies.
733
+
734
+ ```ts
735
+ import { createCacheBridge } from 'stitchkit/react'
736
+
737
+ const bridge = createCacheBridge({
738
+ socket,
739
+ queryClient,
740
+ handlers: {
741
+ 'note:created': (note, ctx) => {
742
+ if (ctx.isFresh(['notes'])) return // skip the echo of our own mutation
743
+ ctx.queryClient.invalidateQueries({ queryKey: ['notes'] })
744
+ },
745
+ },
746
+ })
747
+ bridge.connect()
748
+ ```
749
+
750
+ ### The echo problem
751
+
752
+ When the client makes a mutation, it updates the cache itself — and the server
753
+ also broadcasts the change back over the socket. Without care the UI updates
754
+ twice. `markFresh` plus a short freshness window solves it: mark a key fresh
755
+ right after a local mutation, and the bridge handler skips the echo.
756
+
757
+ ```ts
758
+ // in the mutation:
759
+ onSuccess: () => bridge.markFresh(['notes'])
760
+ // in the handler: if (ctx.isFresh(['notes'])) return
761
+ ```
762
+
763
+ `createCacheBridge` is a convenience, not a requirement — any code can subscribe
764
+ to the socket and call `queryClient` directly. The bridge just centralises the
765
+ event-to-cache mapping and the echo guard.
766
+
767
+ ### Entity cache handlers
768
+
769
+ The created / updated / deleted events of one entity almost always patch the
770
+ cache the same way: prepend to the list, replace by id, remove by id — plus the
771
+ detail query. `createEntityCacheHandlers` builds those three handlers from a
772
+ small config, so you wire them onto the bridge instead of hand-rolling the
773
+ updater per entity:
774
+
775
+ ```ts
776
+ import { createEntityCacheHandlers } from 'stitchkit/react'
777
+
778
+ const widgetCache = createEntityCacheHandlers<Widget>({
779
+ getId: (widget) => widget.id,
780
+ getListItemId: (widget) => widget.id,
781
+ toListItem: (widget) => widget,
782
+ list: {
783
+ key: ['widgets'],
784
+ shape: 'paginated',
785
+ createAt: 'start',
786
+ updateMissing: 'skip',
787
+ },
788
+ detailKey: (event) => ['widgets', event.id],
789
+ })
790
+
791
+ createCacheBridge({ socket, queryClient, handlers: {
792
+ widgetCreated: widgetCache.created,
793
+ widgetUpdated: widgetCache.updated,
794
+ widgetDeleted: widgetCache.deleted,
795
+ }})
796
+ ```
797
+
798
+ The `list.shape` discriminant supports `array`, `paginated`, `infinite-array`
799
+ and `infinite-paginated`. Every mutation preserves the surrounding envelope,
800
+ page metadata and `pageParams`; an infinite create changes only the selected
801
+ edge page (`createAt: 'start' | 'end'`). Creates are deduplicated across every
802
+ cached page. `updateMissing` makes an absent update explicitly skip or insert.
803
+
804
+ Filtered query families can additionally declare membership per exact key and
805
+ evidence-aware total reconciliation:
806
+
807
+ ```ts
808
+ list: {
809
+ key: ['tickets'],
810
+ shape: 'infinite-paginated',
811
+ createAt: 'start',
812
+ updateMissing: 'skip',
813
+ membership: {
814
+ evaluate: (event, queryKey) => membershipFor(event, queryKey),
815
+ unknown: 'invalidate',
816
+ },
817
+ total: {
818
+ mode: 'reconcile',
819
+ unknown: 'invalidate',
820
+ delta: ({ event, present, membership }) => provenDelta(event, present, membership),
821
+ },
822
+ }
823
+ ```
824
+
825
+ Membership is `include | exclude | unknown`. An excluded update removes an
826
+ existing row; an included one follows `updateMissing`. Unknown evidence never
827
+ guesses and either preserves or invalidates the exact query. The conservative
828
+ total policy increments only a non-duplicate create and decrements only a
829
+ delete/update whose membership is observed; unseen IDs are `unknown`. Supply
830
+ `delta` only when the event itself proves a stronger transition. Every page's
831
+ numeric `total` changes together while cursor metadata and `pageParams` remain
832
+ unchanged.
833
+
834
+ The event entity may be richer than a list row. Keep the full value in detail
835
+ cache, project it for lists, and provide the same comparator the backend uses:
836
+
837
+ ```ts
838
+ const memberCache = createEntityCacheHandlers<Member, MemberListItem>({
839
+ getId: (member) => member.id,
840
+ getListItemId: (item) => item.id,
841
+ toListItem: (member) => ({
842
+ id: member.id,
843
+ name: member.name,
844
+ joinedAt: member.joinedAt,
845
+ }),
846
+ list: {
847
+ key: (event) => {
848
+ if (event.type !== 'deleted') {
849
+ return ['workspaces', event.entity.workspaceId, 'members']
850
+ }
851
+ if ('workspaceId' in event.payload) {
852
+ return ['workspaces', event.payload.workspaceId, 'members']
853
+ }
854
+ throw new Error('A scoped delete must carry its entity')
855
+ },
856
+ shape: 'array',
857
+ createAt: 'start',
858
+ updateMissing: 'skip',
859
+ compare: (left, right) => left.joinedAt.localeCompare(right.joinedAt),
860
+ },
861
+ detailKey: (event) => ['members', event.id],
862
+ })
863
+ ```
864
+
865
+ Static `QueryKey` values remain the short path. A key factory receives a typed
866
+ `created | updated | deleted` event, so scoped keys can use the full entity or
867
+ deleted payload without guessing. The same resolved detail key drives the
868
+ `isFresh` echo guard. Shape checks also leave neighbouring detail caches alone
869
+ when a list key is intentionally used as a partial query-key prefix.
870
+
871
+ The helper deliberately does **not** flatten pages, infer filter semantics,
872
+ derive a sort order or replace arbitrary `setQueryData` logic. Those remain
873
+ declared application policies; Stitchkit applies their generic cache mechanics.
874
+
875
+ ## Raw binary lane (Bun)
876
+
877
+ For a high-throughput raw binary channel beside Socket.IO, use the orthogonal
878
+ composition boundary from
879
+ [ADR 0020](../decisions/0020-raw-websocket-lane.md).
880
+
881
+ `composeWebSocketHandlers` composes that one handler from several lanes. A raw
882
+ lane stamps its own marker onto `ws.data` at upgrade and is matched positively;
883
+ Socket.IO is the catch-all (`socketIoLane`, placed last) — so the engine's
884
+ opaque `ws.data` is never inspected, and the whole thing stays cast-free.
885
+
886
+ ```ts
887
+ import {
888
+ composeWebSocketHandlers,
889
+ createServer,
890
+ createSocketIOServer,
891
+ socketIoLane,
892
+ webSocketLane,
893
+ } from 'stitchkit/server'
894
+ import type { RawRoute } from 'stitchkit/server'
895
+ import type { ServerWebSocket, WebSocketHandler } from 'bun'
896
+
897
+ const socket = await createSocketIOServer<ServerToClientEvents, ClientToServerEvents>({
898
+ cors: { origin: 'https://app.example.com' },
899
+ })
900
+
901
+ // 1. Discriminate the raw lane by a marker on ws.data (a type guard, cast-free
902
+ // — the `in` operator narrows, no `as`).
903
+ interface PcmData { lane: 'pcm'; roomId: string }
904
+ function isPcm(ws: ServerWebSocket<unknown>): ws is ServerWebSocket<PcmData> {
905
+ const data = ws.data
906
+ return typeof data === 'object' && data !== null && 'lane' in data && data.lane === 'pcm'
907
+ }
908
+
909
+ // 2. Raw handlers — ws.data is typed PcmData, no casts.
910
+ const pcmHandlers: WebSocketHandler<PcmData> = {
911
+ message(ws, frame) { ws.publish(ws.data.roomId, frame) },
912
+ }
913
+
914
+ // 3. An upgrade route stamps the marker (your auth + data live here).
915
+ const pcmRoute: RawRoute = {
916
+ method: 'GET',
917
+ path: '/ws/pcm',
918
+ handler: (req, ctx) => {
919
+ if (!ctx.server) throw new Error('needs a running Bun server')
920
+ const ok = ctx.server.upgrade(req, { data: { lane: 'pcm', roomId: '…' } })
921
+ return ok ? new Response(null) : new Response(null, { status: 400 })
922
+ },
923
+ }
924
+
925
+ // 4. Compose — raw lane first, Socket.IO last. The tuning is server-wide, so
926
+ // set maxPayloadLength to the most permissive lane (Socket.IO's default is
927
+ // 1 MB, its maxHttpBufferSize).
928
+ const websocket = composeWebSocketHandlers(
929
+ [webSocketLane({ match: isPcm, handlers: pcmHandlers }), socketIoLane(socket.websocket)],
930
+ { maxPayloadLength: 16 * 1024 * 1024 },
931
+ )
932
+
933
+ createServer({
934
+ services,
935
+ socket,
936
+ websocket,
937
+ rawRoutes: [pcmRoute],
938
+ })
939
+ ```
940
+
941
+ Notes:
942
+
943
+ - **Bun-only.** On Node, Socket.IO attaches to the `node:http.Server` `upgrade`
944
+ event (`serveNode({ socket })`); a raw lane there is a separate upgrade
945
+ handler, not this composition. See [ADR 0020](../decisions/0020-raw-websocket-lane.md).
946
+ - The upgrade path must not collide with `/socket.io/*socketPath`.
947
+ - The tuning (`maxPayloadLength`, `idleTimeout`, `backpressureLimit`, …) is
948
+ global — keep `idleTimeout` ≥ Socket.IO needs (> 2 × `pingInterval`).
949
+ - For high throughput, handle backpressure in the raw lane: `ws.send()` returns
950
+ `-1` under pressure; resume on the `drain` callback.
951
+
952
+ ## Bring-your-own transport
953
+
954
+ Sometimes the transport is neither HTTP nor Socket.IO — a desktop app whose UI
955
+ webview talks to its own local Bun sidecar over a raw WebSocket, an IPC channel,
956
+ a queue worker. You can still drive it from one `defineContract`: share the
957
+ contract's Zod schemas to validate each inbound frame, run your handlers, and
958
+ reuse the contract metadata below. You own **both** the wire (framing,
959
+ handshake, reconnect) *and* the per-call validate-run loop — stitchkit ships the
960
+ contract and its metadata, not a transport engine. A reliable-RPC-over-raw-
961
+ WebSocket engine would be a competing WebSocket transport
962
+ ([ADR 0008](../decisions/0008-thin-wrappers.md)); the wire stays yours.
963
+
964
+ Two pieces of the contract carry straight over to a bring-your-own lane:
965
+
966
+ - **`source` is an open tag.** `TransportSource` is `'http' | 'mcp' | 'agent' |
967
+ 'cli' | (string & {})`, so a handler or hook can tell your transport's calls
968
+ apart — tag them `source: 'local-ws'` and read `ctx.source`.
969
+ - **`idempotent` drives replay-on-reconnect** — see below.
970
+
971
+ ### Durability — `idempotent` + replay
972
+
973
+ If the sidecar can restart mid-call, the client decides what to do with an
974
+ in-flight request on reconnect from the operation's **idempotency**, declared on
975
+ the contract:
976
+
977
+ ```ts
978
+ export const runtimeContract = defineContract({ prefix: 'runtime' }, {
979
+ 'tasks.setDone': { method: 'POST', path: '/done', desc: '…',
980
+ idempotent: true, input: taskDone, output: ok }, // re-send after reconnect — same result
981
+ 'capture.start': { method: 'POST', path: '/start', desc: '…',
982
+ output: snapshot }, // unset → one-shot, do not re-send
983
+ })
984
+ ```
985
+
986
+ `idempotent` rides through to `MethodDef.idempotent`; the core attaches no
987
+ behaviour. Your reconnect logic reads it: replay an idempotent call (the
988
+ durability guarantee — the user's action is not lost), reject a non-idempotent
989
+ one rather than fire a second side effect. Pair it with
990
+ [sticky events](#sticky-events) (`createRetainedTopics`) so a reconnected client
991
+ also catches up on the latest pushed state.
992
+
993
+ This is deliberately *not* a reliable-RPC engine — that would be a competing
994
+ WebSocket transport ([ADR 0008](../decisions/0008-thin-wrappers.md)). stitchkit
995
+ gives you the contract and the metadata (`idempotent`, the open `source` tag,
996
+ `createRetainedTopics`); the wire and the per-call execution stay yours. See
997
+ [ADR 0028](../decisions/0028-revert-contract-dispatcher.md).
998
+
999
+ ## Authenticated room registry and replay
1000
+
1001
+ `bindSocketRegistry` composes over `bindRealtimeServer`; it never authenticates
1002
+ a socket a second time and never creates another outbound validator. The
1003
+ identity in `connection.raw.data` has already passed the Socket.IO handshake.
1004
+
1005
+ `rooms(identity)` names the rooms a connecting identity may be in; the registry
1006
+ joins them and refuses a later `join` to any other. The disconnect listener is
1007
+ attached before that lookup is awaited, so a socket that drops while its
1008
+ permissions are still being resolved never becomes a member. `registry.room(name)` mints
1009
+ the opaque `AuthorizedSocketRoom` for a name — the token proves the name came
1010
+ through this registry, not that anyone is in the room, so a room with no open
1011
+ tab is an ordinary `emitTo` target that reports zero recipients. The registry
1012
+ owns join/leave, multiple sockets per identity, immutable snapshots and
1013
+ listener cleanup.
1014
+
1015
+ Replay is revisioned: while a socket's snapshot is open, frames sent through
1016
+ `emitTo` to its rooms are held back and delivered after the snapshot, so the
1017
+ socket never sees a delta for state its snapshot already contains, nor a
1018
+ snapshot that predates a delta it already received. A snapshot taken across a
1019
+ `revision` change is retried up to `replayAttempts` (default 3). The hold-back buffer is
1020
+ bounded by `maxBufferedFrames` (default 1000): past it the attempt is abandoned
1021
+ and retried, and when the attempts are spent `onResyncRequired(socketId,
1022
+ identity)` fires with nothing half-delivered — the application decides what a
1023
+ resync means for that socket. A retry relies on the fresh snapshot carrying
1024
+ what the abandoned frames carried, which holds when every emitted change also
1025
+ moves `revision`; without a `revision` the registry has no way to tell, so
1026
+ declare one wherever replay matters. Room tokens are recognised, not
1027
+ remembered: a token the application keeps stays valid for the life of the
1028
+ registry, and a name seen once does not live on in a map. This ordering exists only for frames that go
1029
+ through `emitTo`; a broadcast through `realtime.to(room).emit` reaches the
1030
+ socket immediately, replay or not, so keep room traffic whose order matters
1031
+ relative to the snapshot on the registry.